基礎語法
一、前言
1.1 概述
1.1.1 學嵌入式用C語言的理由
| 優勢 | 一句話解釋 |
|---|---|
| 直接控制 | 用指針和位操作直接命令硬件,像操作開關一樣精準。 |
| 高效精簡 | 代碼小,速度快,資源佔用極低,最適合資源有限的單片機。 |
| 通用標準 | 行業“普通話”,所有芯片和官方庫都支持,代碼可跨平台複用。 |
| 生態成熟 | 遇到任何問題,都有海量的現成代碼、項目和教程可用。 |
1.1.2 C語言的標準
| 標準版本 | 發佈年份 | 發佈組織 | 主要特點與新增功能 |
|---|---|---|---|
| C89 / C90 | 1989 / 1990 | ANSI / ISO | • 奠定基礎:確立了第一個官方 C 語言標準,成為通用基石。 |
| C99 | 1999 | ISO/IEC | • 功能擴展:
- inline 內聯函數 - 變量聲明位置更靈活 - 變長數組 (VLA) |
| C11 | 2011 | ISO/IEC | • 現代化:
- 增強與 C++ 的兼容性 - 官方多線程支持 (<threads.h>) - 泛型表達式 (_Generic) |
1.2 編程環境搭建
- 編譯器:gcc
-
集成開發環境:
(1)Trae
- 國內首個 AI 原生 IDE,內置豆包 1.5 Pro 和 DeepSeek R1/V3 雙模型
(2)Visual Studio
下載:前往 Visual Studio 官網(https://visualstudio.microsoft.com/)下載安裝程序。在下載時,可根據需求選擇不同版本,如社區版(免費用於個人、開源及小型團隊開發)。
安裝:運行安裝程序,在安裝選項中,務必勾選 “C++ 桌面開發” 工作負載,因為它包含了 C 語言的編譯器等開發工具。安裝過程可能需要一些時間,安裝完成後啓動 Visual Studio。
(3)Visual Studio Code
安裝:從 Visual Studio Code 官網(https://code.visualstudio.com/)下載並安裝。
配置 C/C++ 插件:打開 VS Code,點擊左側的擴展圖標,搜索 “C/C++” 插件,選擇由 Microsoft 官方發佈的進行安裝。安裝完成後,VS Code 會自動檢測已安裝的 GCC 編譯器(前提是環境變量配置正確),即可用於 C 語言開發。它具有智能代碼補全、語法高亮、代碼導航、調試支持等強大功能。
1.3 語言分類介紹
- 編譯型語言:C、C++
- 解釋型語言:Python、JS
1.4 C語言編譯器介紹
| 版本 | 核心本質 | 目標與特點 | 產物依賴 | 來源 |
|---|---|---|---|---|
| GCC | 跨平台編譯器 | 跨平台的標準編譯器 | 標準庫 | GNU 項目 |
| MinGW | 原生Windows移植版 | 輕量級,編譯原生 Windows 程序 | Windows API (msvcrt.dll) | MinGW 項目 |
| Cygwin | POSIX 模擬環境 | 在 Windows 上模擬 POSIX (類 Linux) 環境 | 需依賴 cygwin1.dll | Cygwin 項目 |
| MSVC | Windows 官方編譯器 | 微軟官方,與 Visual Studio 深度集成 | MSVC 運行時庫 (VCRUNTIME) | 微軟 |
二、基礎語法
2.1 第一個C語言程序
(註釋掉後,註釋部分程序就不會運行)
-
行註釋 //
- 快鍵鍵 ctrl+/
-
塊註釋 /**/
- 快捷鍵 shift+alt+a
#include <stdio.h>//頭文件
int main() //主函數
{
printf("hello world\n");//打印輸出
return 0;
}
這是一個最基本的c語言程序,可以先看着自己多打幾遍,然後確保不看能完整寫出來。
2.2 數據類型
在 C 語言中,數據類型是程序設計的基礎,它定義了變量或表達式可以存儲的數據種類、範圍的範圍以及可進行的操作。數據類型的核心作用和意義主要體現在以下幾個方面:
(1)內存管理
不同數據類型佔用的內存空間不同(如char佔 1 字節,int通常佔 4 字節)。編譯器根據數據類型分配相應大小的內存,避免內存浪費或不足。例如:
char c; // 分配1字節內存
int i; // 分配4字節內存
(2)限定數據範圍與精度
數據類型決定了變量能表示的數值範圍或數據形式:
整數類型(short、int、long)有不同的取值範圍
浮點類型(float、double)區分精度(float約 6-7 位有效數字,double約 15-17 位)
字符類型(char)專門用於存儲 ASCII 字符
2.2.1 變量的語法
- 變量在使用前必須先定義,定義變量前必須有相應的數據類型;
- 在程序運行過程中,其值可以改變;
#include <stdio.h>
int main()
{
//const修飾常變量
const int a = 10;//const修飾a後,a變為常變量,不可再賦值改變,但本質仍然是變量
//int arr[a] = { 0 };//數組內需要使用常量
//#define 定義的標識符常量
#define max 100 //#define 定義的標識符常量,定義max等價於值100
#define abd "hmj" //#define 定義的標識符常量,定義abc等價於字符串hmj
int b = max;//給b賦值100
printf("%d\n",b );//會輸出100
printf("%s\n",abd);//會輸出hmj
//枚舉常量
enum color
{
ren,blue,green
};
enum corol c = ren;
enum corol d = green;;
printf("%d\n",c);//枚舉常量數值默認是從0開始
printf("%d\n",d);
return 0;
}
2.2.2 命名規則和規範
標識符是用户編程時使用的名字, 用於給變量、 函數、 結構體等命名
-
命名規則
-
規則:規則是一定要遵循,不遵循就報錯
- 由數字, 字母, 下劃線_組成
- 不能使用數字開頭
- 不能使用關鍵字
- 嚴格區分大小寫
- 關鍵字(這個不用記):已經佔用的名字,用户起名不能和關鍵字重名
-
-
命名規範:可以不遵循,只是一個建議,建議英文的見名知意
- 大駝峯:每個單詞首字母大寫, 例如: MyFirstName
- 小駝峯:第二個單詞開始首字母大寫, 例如: myFirstName
- 下劃線命名:每個單詞之間使用下劃線連接, 例如: my_first_name
2.2.3 char類型
- char的本質就是一個1字節大小的整型,一個字符對應一個ASCII 編碼數字
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main()
{
char hmj = 'a';//字符類型char,定義hmj為字符’a‘
char arr1[] = "humengjie";//在字符串humengjie後面有個\0結束標誌,長度為10
char arr2[] = { 'h','u','m','e','n','g','j','i','e' };//長度為9,但是由於沒有\0結束標誌,輸出時,會有亂碼
char arr3[] = { 'h','u','m','e','n','g','j','i','e','\0'}; //長度為10
printf("%s\n", arr1);//輸出humengjie
printf("%s\n", arr2);//輸出humengjie燙燙燙亂碼
printf("%s\n", arr3); //有結束標誌'/0',輸出humengjie
printf("%d\n", sizeof(arr1));//arr1長度為10
printf("%d\n", sizeof(arr2));//arr2長度為9
printf("%d\n", sizeof(arr3));//arr3長度為10
printf("%d\n", strlen(arr1));//sizeof:關注內存佔用,包含終止符,編譯時確定。
//strlen:關注字符串內容,不含終止符,運行時遍歷。
printf("%d\n", strlen(arr2));
return 0;
}
2.2.4 bool類型
- 早期C語言沒有布爾類型數據,以0代表邏輯假,非0代表邏輯真
- C99標準定義了新的關鍵字_Bool,提供了布爾類型,或者也可以使用
#include <stdio.h>
#include <stdbool.h>
int main() {
bool flag=true;//bool類型只有0和1
printf("%d\n",flag);
flag=false;
printf("%d\n",flag);
printf("%d\n",(bool)-100);// ‘(bool)轉換類容’,,非0為true,0為false
return 0;
}
`
2.2.5 數據類型長度(大小)
- 數據類型的作用:編譯器預算數據分配的內存空間大小。
- 通俗理解為:數據類型是用來規範內存的開銷,約定數據在內存中的格式,便於存儲。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
//sizeof(數據類型)可以用於獲得類型長度
printf("%d\n", sizeof(int)); //4
printf("%d\n", sizeof(char)); //1
printf("%d\n", sizeof(long)); //4
printf("%d\n", sizeof(long long));//8
printf("%d\n", sizeof(float)); //4
printf("%d\n", sizeof(double)); //8
return 0;
}
-
bit(比特)
- 一個二進制代表一位,一個位只能表示0或1兩種狀態。
-
Byte(字節)
- 一個字節為8個二進制,稱為8位,計算機中存儲的最小單位是字節。
-
使用sizeof查看數據長度
○ 長度在不同平台是不一樣。 - 數據溢出
#include <stdio.h>
int main() {
char temp1;//有符號取值範圍為-128-127
unsigned char temp2;//無符號取值範圍為0-255
temp1=128;//超出範圍後會從頭計算,數據溢出
temp2=256;
//%d默認四字節打印
printf("%d\n",(char)temp1);
//%u無字符打印輸出
printf("%u\n",(unsigned char)temp2);
return 0;
}
2.2.6 可移植的類型
- 為了更好的兼容不同平台,在使用數據類型時會採用可移植的類型,這些類型可以確保在不同的平台下穩定的運行。
- C語言在可移植類型 stdint.h 和 inttype.h 中規定了精確寬度整數類型,以確保C語言的類型在各系統內功能相同。
2.2.7 常量
-
與變量不同,常量的值在程序運行時不會改變
分類 舉例 整型常量 100,200,-100,0 實型常量 3.14 , 0.125,-3.123 字符型常量 'a', 'b', '1' 字符串常量 "a", "ab","12356"
- 自定義常量
#include <stdio.h>
#include <stdint.h>
#define max 200 // 宏定義,將max定義為100,後面出現的max都將替換為100
int main()
{
uint8_t a; // 8位 等價於 unsigned char
int8_t; // 等價於 char
uint32_t a; // 32位 等價於 unsigned int
int32_t; // 等價於 int
int temp = max;
printf("temp=%d\n", temp);
const int h = 100;
// a=200;//const修飾後為只讀,不能改變
return 0;
}
- 宏替換
#include <stdio.h>
#define temp a
#define abc int
int main() {
int a=10;
temp=123;//相當於a=123
printf("%d\n",a);
abc b=20;//相當於int b=20
printf("%d",b);
return 0;
}
2.3 數值表示
2.3.1 C語言表示進制數
| 進制 | 描述 |
|---|---|
| 十進制 | 以正常數字1-9開頭,如15 |
| 八進制 | 以數字0開頭,如017 |
| 十六進制 | 以0x或0X開頭,如0xf |
| 二進制 | 以0b或0B開頭,如0b1111 |
#include <stdio.h>
#include <stdint.h>
int main()
{
uint8_t a, b, c, d;
a = 15; //十進制表示15
b = 017; //八進制表示15
c = 0xf; //十六進制表示15
d = 0b1111;//二進制表示15
printf("10進制數表示:%d,%d,%d,%d\n", a, b, c, d);
printf("8進制數表示:%o,%o,%o,%o\n", a, b, c, d);
printf("16進制數表示:%x,%x,%x,%x\n", a, b, c, d);
printf("16進制數表示:%X,%X,%X,%X\n", a, b, c, d);
printf("16進制數表示:%#x,%#x,%#x,%#x\n", a, b, c, d);
return 0;
}
2.3.2 數值存儲方式(瞭解)
計算機底層都是存儲數據都是採用二進制,但二進制也有幾種,比如:原碼、反碼、補碼。
2.3.2.1 原碼
一個數的原碼(原始的二進制碼)有如下特點:
- 最高位做為符號位,0表示正,為1表示負
- 其它數值部分就是數值本身絕對值的二進制數
- 負數的原碼是在其絕對值的基礎上,最高位變為1
下面數值以1字節的大小描述:
| 十進制數 | 原碼 |
|---|---|
| +15 | 0000 1111 |
| -15 | 1000 1111 |
| +0 | 0000 0000 |
| -0 | 1000 0000 |
2.3.2.2 反碼
- 對於正數,反碼與原碼相同
- 對於負數,符號位不變,其它部分取反(1變0,0變1)
| 十進制數 | 反碼 |
|---|---|
| +15 | 0000 1111 |
| -15 | 1111 0000 |
| +0 | 0000 0000 |
| -0 | 1111 1111 |
2.3.2.3 補碼
在計算機系統中,數值一律用補碼來存儲。
補碼特點:
- 對於正數,原碼、反碼、補碼相同
-
對於負數,其補碼為它的反碼加1
- 補碼符號位不動,其他位求反,最後整個數加1,得到原碼
| 十進制數 | 補碼 |
|---|---|
| +15 | 0000 1111 |
| -15 | 1111 0001 |
| +0 | 0000 0000 |
| -0 | 0000 0000 |
#include <stdio.h>
int main()
{
// int大小為4字節,32位
int a = -15;
printf("%x\n", a);
//結果為 fffffff1 補碼
//fffffff1對應的二進制:1111 1111 1111 1111 1111 1111 1111 0001 補碼
//符號位不變,其它取反:1000 0000 0000 0000 0000 0000 0000 1110 反碼
//上面加1:1000 0000 0000 0000 0000 0000 0000 1111 最高位1代表負數,就是-15 原碼
return 0;
}
2.3.2.4 補碼的意義
在計算機系統中,數值一律用補碼來存儲,主要原因是:
- 統一零的編碼
- 將減法運算轉變為加法運算
示例1:用8位二進制數分別表示+0和-0
| 十進制數 | 原碼 |
|---|---|
| +0 | 0000 0000 |
| -0 | 1000 0000 |
| 十進制數 | 反碼 |
|---|---|
| +0 | 0000 0000 |
| -0 | 1111 1111 |
不管以原碼方式存儲,還是以反碼方式存儲,0也有兩種表示形式。為什麼同樣一個0有兩種不同的表示方法呢?
但是如果以補碼方式存儲,補碼統一了零的編碼:
| 十進制數 | 補碼 |
|---|---|
| +0 | 0000 0000 |
| -0 | 10000 0000 由於只用8位描述,最高位1丟棄,變為0000 0000 |
示例2:1個字節大小計算9 - 6的結果
以原碼方式相加:
| 十進制數 | 原碼 |
|---|---|
| 9 | 0000 1001 |
| -6 | 1000 0110 |
| 15 | 1000 0011 |
結果為-15,不正確。
以補碼方式相加:
| 十進制數 | 補碼 |
|---|---|
| 9 | 0000 1001 |
| -6 | 1111 1010 |
| 3 | 10000 0011 |
最高位的1溢出,剩餘8位二進制表示的是3,正確。
三、輸出和輸入
3.1 輸出
格式化佔位符
| 打印格式 | 對應數據類型 | 含義 |
|---|---|---|
| %c | char | 字符型,輸入的數字按照ASCII碼相應轉換為對應的字符 |
| %d | int | 接受整數值並將它表示為有符號的十進制整數 |
| %u | unsigned int | 無符號10進制整數 |
| %ld | long | 接受長整數值並將它表示為有符號的十進制整數 |
| %f | float | 單精度浮點數 |
| %lf | double | 雙精度浮點數 |
| %s | char * | 字符串。輸出字符串中的字符直至字符串中的空字符(字符串以'\0‘結尾,這個'\0'即空字符) |
| %x,%X | unsigned int | 無符號16進制整數,x對應的是abcdef,X對應的是ABCDEF |
#include <stdio.h>
int main()
{
char ch = 'a';//1字節
printf("%c\n", ch);
short a = 12;//2字節
printf("%hd\n", a);
int b = 123;//4字節
printf("%d\n", b);
unsigned int c = 155;
printf("%u\n", c);
long d = 1345;
printf("%ld\n", d);
float pi1 = 3.14;
double pi2 = 3.14159;
printf("%f\n", pi1);//默認輸出小數點後6位
printf("%lf\n", pi2);
printf("%.2f\n", pi1);//%.2表示在小數點後面保留兩位數字
printf("%.5lf\n", pi2);//%.5表示在小數點後面保留五位數字
return 0;
}
3.2 輸入
#include <stdio.h>
int main() {
int a,b,c;
printf("請輸入:");
//scanf主要作用是從標準輸入設備(通常是鍵盤)讀取數據,並按照指定的格式將數據存儲到變量中
scanf("%d,%d",&a,&b);
//第一個是格式控制字符串,指定了輸入數據的類型和格式(如 %d 表示整數,%f 表示浮點數)。
//後續參數是要存儲輸入數據的變量地址(需使用 & 取地址符,指針變量除外)。
printf("c的值為%d\n",a+b);
return 0;
}
注意:在終端輸入數據時需要和(scanf("%d,%d",&a,&b);)中%d,%d格式一樣,比如:
| 函數 | 終端 |
|---|---|
| %d,%d | 1,1 |
| %d %d | 1 1 |
3.3 案例
- 從鍵盤輸入一個圓形的半徑,輸出圓的周長和麪積
- 思路步驟
1.定義常量pi
2.定義半徑變量r
3.輸入半徑
4.求周長和麪積, * 為乘以運算符
5.輸出周長和麪積
#include <stdio.h>
#define pi 3.14
int main() {
float r;
printf("請輸入半徑:");
scanf("%f",&r);
//周長
double len=r*pi*2;
//面積
double area=r*r*pi;
printf("周長為:%.2lf,面積為:%.2lf",len,area);
return 0;
}
四、運算符
-
運算符就是在各種運算中起到特定作用的符號
- 一般情況下, 用哪個運算符, 現查現用即可
4.1 算術運算符
| 運算符 | 術語 | 示例 | 結果 |
|---|---|---|---|
| + | 加 | 10 + 5 | 15 |
| - | 減 | 10 - 5 | 5 |
| * | 乘 | 10 * 5 | 50 |
| / | 除 | 10 / 5 | 2 |
| % | 取模(取餘) | 10 % 3 | 1 |
| ++ | 前自增 | a=2; b=++a; | a=3; b=3; |
| ++ | 後自增 | a=2; b=a++; | a=3; b=2; |
| -- | 前自減 | a=2; b=--a; | a=1; b=1; |
| -- | 後自減 | a=2; b=a--; | a=1; b=2; |
#include <stdio.h>
int main() {
printf("5+2=%d\n",5+2);
printf("5-2=%d\n",5-2);
printf("5*2=%d\n",5*2);
printf("5/2=%d\n",5/2);//兩個整數相除,只會輸出整數部分
printf("5.0/2=%.2f\n",5.0/2);//要想輸出小數部分,兩個數至少要有一個小數
printf("5%%2=%d\n",5%2);
printf("==============================\n");
int a,b;
int num1,num2;
a=b=0;
num1=a++;//先賦值,a再加1
num2=++b;
printf("++前置: num2=%d,b=%d\n",num2,b);
printf("++後置: num1=%d,a=%d\n",num1,a);
return 0;
}
4.2 賦值運算符
| 運算符 | 術語 | 示例 | 結果 |
|---|---|---|---|
| = | 賦值 | a=2; b=3; | a=2; b=3; |
| += | 加等於 | a=0; a+=2;等同於 a = a + 2; | a=2; |
| -= | 減等於 | a=5; a-=3;等同於 a = a - 3; | a=2; |
| *= | 乘等於 | a=2; a=2;等同於 a = a 2; | a=4; |
| /= | 除等於 | a=4; a/=2;等同於 a = a / 2; | a=2; |
| %= | 模等於 | a=3; a%=2;等同於 a = a % 2; | a=1; |
4.3 比較運算符
C 語言的比較運算中, “真”用數字“1”來表示, “假”用數字“0”來表示
| 運算符 | 術語 | 示例 | 結果 |
|---|---|---|---|
| == | 相等於 | 4 == 3 | 0 |
| != | 不等於 | 4 != 3 | 1 |
| < | 小於 | 4 < 3 | 0 |
| > | 大於 | 4 > 3 | 1 |
| <= | 小於等於 | 4 <= 3 | 0 |
| >= | 大於等於 | 4 >= 1 | 1 |
#include <stdio.h>
int main() {
printf("1==1:%d\n",1==1);
printf("1!=1:%d\n",1!=1);
printf("1>0:%d\n",1>0);
printf("1<0:%d\n",1<0);
return 0;
}
4.4 邏輯運算符
| 運算符 | 術語 | 示例 | 結果 | ||||
|---|---|---|---|---|---|---|---|
| ! | 非 | !a | 如果a為假,則!a為真;如果a為真,則!a為假。 | ||||
| && | 與 | a && b | 如果a和b都為真,則結果為真,否則為假。 | ||||
| \ | \ | 或 | a \ | \ | b | 如果a和b有一個為真,則結果為真,二者都為假時,結果為假。 |
#include <stdio.h>
int main()
{
printf("%d\n", 2 > 1 && 3 > 2);//輸出1 &&為與門,兩個為真才為真
printf("%d\n", 2 > 1 && 3 < 2);//輸出0
printf("%d\n", 2 > 1 || 3 > 2);//輸出1 ||為或門,一個為真就為真
printf("%d\n", 2 < 1 || 3 >2);//輸出1
printf("%d\n", !(2 > 1 && 3 > 2));//輸出0 本來為1,!取反後為0
return 0;
}