編譯器會用空格代替代碼中原來的注釋,並先於預處理指令執行
/*…*/ 這種形式的注釋不能嵌套
只要斜槓(/)和星號(*)之間沒有空格,都會被當作注釋的開始。例如這樣:
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 指令的作用是設定編譯器的狀態或者是指示編譯器完成一些特定的動作。
#和##都是預處理命令。
#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
無參的寫法
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]=!
定義一個數組 a 時,編譯器根據指定的元素個數和元素的類型分配確定大小的一塊內存,並把這塊內存的名字命名為 a
名字 a 一旦與這塊內存匹配就不能被改變。a[0],a[1]等為 a 的元素,但並非元素的名字。數組的每一個元素都是沒有名字的。
a[0]是一個元素,a 是整個數組,雖然&a[0]和&a的值一樣,但其意義不一樣。
前者是數組首元素的首地址,而後者是數組的首地址。
a 作為右值時其意義與&a[0]是一樣,代表的是 數組首元素的首地址,而不是數組的首地址。
a 不能作為左值!只能訪問數組的某個元素而無法把數組當一個總體進行訪問。
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;