《C和指針》學習小記

下面的內容主要是個人的學習筆記,以便日後複習使用,內容比較簡單,大牛們可以略過了,初學者可以互相交流。

1.關於/* */註釋符的使用

註釋符不能嵌套,在一段代碼中,第一個/*和第一個*/直接的所有內容都是註釋,包括註釋符/*。所以假如有一段代碼: 

int a;

/*

int b;

*/

int c;

我們想註釋這段代碼,於是在int a;和int c;之前之後分別加上/* */,會發現註釋是錯的。解決辦法可以用預處理指令#if,改爲:

#if 0

...

#endif

另外和註釋符相關的一個問題是運算符問題,int a=b/*p;本意是b/(*p),結果由於詞法分析的貪心原則,導致/*結合爲註釋符,因此在編程時候需要注意下。上述這兩個問題在編輯器裏面寫錯了都可以直接看出來,就算不用注意也不會導致錯誤的發生,除非編輯器的字體沒有顏色標識。


2.在使用函數getchar() getc() fgetc()時候,接收返回值的變量應該聲明爲int,即int a=getchar();因爲getchar()的返回值爲int類型,且結束符EOF也是值爲-1的int類型,使用char類型變量來接收返回結果時,如果編譯器沒有做處理容易出現錯誤。


3.關於指針的const聲明

int const *p;//p是指向整型常量的指針,可以修改p的值,不能修改p指向內容的值

int * const p;//p是一個常量指針,可以修改p指向內容的值,不能修改p的指向

int  const * const p;//這種聲明也是正確的,效果參考上述


4.關於static的聲明

當static用於修飾代碼塊之外的變量或者函數時,static用於修改標識符的鏈接屬性,由external改爲internal,被修飾標識符只能在其聲明的源文件中被訪問。

當static用於修飾代碼塊內部的變量時,static修改的是標識符的存儲類型,爲靜態存儲,不影響變量的鏈接屬性和作用域。用這種方式聲明的變量在程序執行之前創建,在程序的執行期間一直存在。


5.sizeof 的一個問題,sizeof是判斷表達式的長度,因此並不需要對錶達式求值,因此sizeof(a=b+1)並沒有對a賦值。


6.關於運算符的求值順序

a*b+c*d+e*f 在這個表達式中,編譯器只保證乘法操作在其相鄰的加法操作之前進行,並不保證先算a*b還是先算c*d,因此c+(--c)這樣的表達式很容易出現錯誤。

另外,在表達式f()+g()+k()中,編譯器只保證左邊的加號先於右邊的加號執行,但並不能保證三個函數的調用順序,因此如果三個函數間存在數據耦合,那麼這樣的書寫方式是存在風險的。


7.關於移位符的一個應用 點擊打開鏈接


8.C中函數的可變參數列表實現方法點擊打開鏈接


9.strlen()返回的是size_t類型的值,它是一個無符號整數類型,因此表達式

if( strlen(x) - strlen(y) >=0) ...中,if的判斷值始終爲真,因爲兩個無符號整數做運算結果還是無符號整數,不會爲負數


10.char *strncpy(char *dst ,char *src, size_t len),該函數總是正好向dst寫入len個字符,src長度如果不夠len,就用NUL填充,如果大於等於len,就寫入len個字符,但是不會在複製結尾插入NUL。因此在程序中可以在len-1處賦值'\0'。使用此函數時要注意確定好len的值,不要越界。

char *strncat(char *dst ,char *src, size_t len),該函數至多向dst添加len個字符並在結尾添加'\0',如果超出dst的剩餘空間了仍會在dst尾部添加字符,產生越界,因此len的大小也需要確定好。


11.字符串查找函數:

char *strchr(char const *str, int ch);//從左向右

char *strrchr(char const *str, int ch);//從右向左

char *strpbrk(char const *str, char const *group);//匹配組中任何一個 

char *strstr(char const *str1, char const *str2);//如果str2爲空字符串,則返回str1


size_t strspn(char const *str, char const *group);//返回str開頭部分屬於group的元素個數,即返回第一個不在group中的元素的下標

size_t strcspn(char const *str, char const *group);//返回str開頭部分不屬於group的元素個數

char *strtok(char *str, char const *sep);//根據sep分隔str,會修改str


12.如果要初始化union類型變量,初始值必須是union變量的第一個成員的類型。struct類型變量作爲函數參數使用時大多數情況下傳遞一個struct類型的指針更爲合適,因爲C的函數參數是傳值的,如果傳遞一個struct類型的變量,那麼需要把整個變量拷貝到棧中,效率很低。


13.所有用於對數值表達式進行求值的宏定義都應該加上括號,避免在使用宏時,由於參數中操作符之間產生不可預料的相互作用。例如 #define DOUBLE(x) ((x) + (x))


14.條件編譯,可以用來調試程序。在程序中如果有如下語句:

#if expr

    statements

#endif

expr是常量表達式,一般通過#define 定義,該表達式的值在預處理時進行求值,如果爲真,則statements部分被編譯,否則被忽略。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章