註釋 編譯器會用空格代替代碼中原來的註釋,並先於預處理指令執行/*…*/ 這種形式的註釋不能嵌套只要斜杠(/)和星號(*)之間沒有空格,都會被當作註釋的開始。例如這樣:y = x/*p; \ 是一個接續符,表示斷行。編譯器會將反斜杠剔除掉,跟在反斜杠後面的字元自動接續到前一行。但是註意:反斜杠之後不 ...
註釋
編譯器會用空格代替代碼中原來的註釋,並先於預處理指令執行
/*…*/ 這種形式的註釋不能嵌套
只要斜杠(/)和星號(*)之間沒有空格,都會被當作註釋的開始。例如這樣:
y = x/*p;
\ 是一個接續符,表示斷行。編譯器會將反斜杠剔除掉,跟在反斜杠後面的字元自動接續到前一行。但是註意:反斜杠之後不能有空格,反斜杠的下一行之前也不能有空格。(有的編譯器有空格可以通過)。\ 還能被用作轉義字元的開始標識。
位運算符
交換兩個變數的值:a ^= b; b ^= a; a ^= b;
0x01<<2+3; // ==32 // "+"號的優先順序比移位運算符的優先順序高
在 32 位系統下:
0x01<<2+30; 0x01<<2-3;
左移和右移的位數不能大於數據的長度,不能小於0。(有的編譯器還是可以通過的)
對於有符號數,在>>右移時,符號位將隨同移動。當為正數時,最高位補0;
而為負數時,符號位為 1,最高位是補 0 或是補 1 取決於編譯系統的規定。Turbo C 和很多系統規定為補 1。
常用的位操作巨集:
#define SETBIT(x, y) ((x) |= (y)) #define CLRBIT(x, y) ((x) &= ~(y)) #define TOGLBIT(x, y) ((x) ^= (y)) #define TESTBIT(x, y) ((x) & (y))
#define SETBIT(x, y) ((x) |= 1<<(y)) #define CLRBIT(x, y) ((x) &= ~(1<<(y)))
花括弧
char a[10]{ = “abcde”};
花括弧的作用就是打包。
自加減++、--
i=3; (++i)+(++i)+(++i); //未定義行為,取決於編譯器 // TCC:15, VC6:16, GCC:18
i=3;
(i++)+(i++)+(i++);
自加或自減運算是在本計算單位計算結束( 遇到 , 或 ; )之後再自加或自減。
int i,j; i=0; j=(i++,i++,i++); //j=2,i=3 i=0; j=(++i,++i,++i); //j=3
/ 和 %
有2組計算
3/2; (-3)/2; 3/(-2); (-3)/(-2); 3%2; (-3)%2; 3%(-2); (-3)%(-2);
優先順序
. []和() 的優先順序比 * 高
== 和 != 優先順序高於位操作
== 和 != 優先順序高於賦值符
算術運算符高於位移運算符
預處理
預處理指令是編譯器的功能,不是C語言的一部分。
巨集定義
ANSI 標準 C 還定義瞭如下幾個巨集:
_LINE_ 表示正在編譯的文件的行號
_FILE_ 表示正在編譯的文件的名字
_DATE_ 表示編譯時刻的日期字元串,例如: "25 Dec 2007"
_TIME_ 表示編譯時刻的時間字元串,例如: "12:30:55"
_STDC_ 判斷該文件是不是定義成標準 C 程式
下麵的寫法都是對的:
#define EMPTY # define EMPTY
在使用巨集函數的時候,巨集名和參數之間的空格會被編譯器忽略掉。定義巨集的時候空格是有效的。
#error 預處理指令的作用是,編譯程式時,只要遇到 #error 就會生成一個編譯錯誤提示消息,並停止編譯。其語法格式為:
#error error-message
#line 的作用是改變當前行數和文件名稱,它們是在編譯程式中預先定義的標識符。命令的基本形式如下:
#line number["filename"]
#pragma 指令的作用是設定編譯器的狀態或者是指示編譯器完成一些特定的動作。
#和##都是預處理命令。
斷言assert
#if !defined(NDBUG) #define assert(p) if(!(p)){fprintf(stderr,\ "Assertion failed: %s, file %s, line %d\n",\ #p, __FILE__, __LINE__);abort();} #else #define assert(p) #endif
main函數
無參的寫法
int main(void)
有參的寫法
int main(int argc, char *argv[]) int main(int argc, char **argv)
argc -- 命令行參數總個數,包括 可執行程式名
argv[0] -- 可執行程式名
argv[i] -- 第 i 個參數
例子
# ./a.out Love Live !
該例子中 argc 為4,argv[0]=a.out, argv[1]=Love, argv[2]=Live, argv[3]=!
數組 int a[5];
定義一個數組 a 時,編譯器根據指定的元素個數和元素的類型分配確定大小的一塊記憶體,並把這塊記憶體的名字命名為 a
名字 a 一旦與這塊記憶體匹配就不能被改變。a[0],a[1]等為 a 的元素,但並非元素的名字。數組的每一個元素都是沒有名字的。
&a[0]和&a 的區別[I]
a[0]是一個元素,a 是整個數組,雖然&a[0]和&a的值一樣,但其意義不一樣。
前者是數組首元素的首地址,而後者是數組的首地址。
數組名 a 作為左值和右值的區別
a 作為右值時其意義與&a[0]是一樣,代表的是 數組首元素的首地址,而不是數組的首地址。
a 不能作為左值!只能訪問數組的某個元素而無法把數組當一個總體進行訪問。
&a[0]和&a 的區別[II]
int main() { char a[5] = {'A','B','C','D'}; char (*p3)[5] = &a; char (*p4)[5] = a; return 0; }
p3 和 p4 都是數組指針,指向的是整個數組。p3 這個定義的“=”號兩邊的數據類型完全一致,而 p4 這個定義的“=”號兩邊的數據類型就不一致了。左邊的類型是指向整個數組的指針,右邊的數據類型是指向單個字元的指針。但由於 &a 和 a 的值一樣,而變數作為右值時編譯器只是取變數的值,所以運行並沒有什麼問題。
p3+1 和 p4+1 的值又是多少呢?
C 語言中,當一維數組作為函數參數的時候,編譯器總是把它解析成一個指向其首元素首地址的指針。
指針
野指針產生的原因
定義指針變數時未初始化;指針釋放後之後未置空。free和delete只是把指針所指的記憶體給釋放掉,但並沒有把指針本身幹掉。此時指針指向的就是“垃圾”記憶體。釋放後的指針應立即將指針置為NULL,防止產生“野指針”。
指針的使用
1. 定義指針變數的同時最好初始化為 NULL,
char *p = NULL;
2. 用完指針之後也將指針變數的值設置為 NULL,
free(p);
p = NULL;