使用預處理語句「註釋掉」代碼最安全數組
#if 0 // some statements #endif
printf
返回輸出的長度(包括不可見字符),scanf
只返回1(成功)或0(失敗)scanf
讀取輸入到數組時,直接寫數組名和&數組名效果相同安全
int array[10]; // 如下兩種方式效果一致 scanf("%s", array); scanf("%s", &array);
賦值運算符的返回值大機率爲左值(C)或左值的引用(C++),但歸根究竟是一個undefined行爲,取決於編譯器的實現。但如下用法一般能夠接受:函數
while ((ch = getchar()) != EOF && ch != '\n') // clear input buffer ; // 分號單獨寫一行,以避免把下一行代碼當成循環體
且此處ch
一般被聲明爲int
,由於EOF
其實是一個int
編碼
const
,能夠防止意外修改數組中的數據gets
函數的安全性問題在於,它讀取字符串時沒法知道其長度,當遇到超長字符串時很容易溢出程序的編譯與執行操作系統
首先看幾個容易混淆的擴展名指針
.out / .exe
可執行文件,Linux和Unix下用.out
,Windows下用.exe
.o / .obj
編譯後產生的還沒有連接的中間文件,機器碼的初步形式,Linux和Unix下用.o
,Windows下用.obj
.bin
單純二進制文件,多是代碼,也多是數據編譯code
.c
生成對應的.o / .obj
).o / .obj
文件生成一個完整的.out / .exe
)執行生命週期
字面值內存
數字作用域
字符
使用L
前綴指定字符爲寬字符常量(unicode只是寬字符編碼的一種,二者並不相等!)
wchar_t = L'X';
字符串
⚠️指向字符串常量的指針能夠被指向別的地方,但字符串常量是不能被改變的!
char* strPtr = "blahblah"; strPtr[2] = 'D'; // 非法操做!! strPtr = "Hmmm"; // It's Okay..
聲明指針時,把星號緊挨變量寫是一個好習慣:
int* a, b, c; // 很容易誤解爲a、b、c三個指針,而實際只有a是指針,b和c僅僅是int
在聲明字符串指針的同時賦值實際意味將該指針指向字符串的首地址,畢竟C中根本沒有真正的字符串類型
char *message = "Hello"; // 實際上等價於 char *message; message = "Hello"; // 而不是 *message = "Hello";
用typedef定義指針類型
以前一直不能理解這種習慣,以爲真的很容易把指針誤認爲數據,命名時加個Ptr後綴很差嗎??如今才知道原來是方便定義函數指針時用的。。soga
#define charPtr char* // 危險! charPtr a, b, c; // 只有a被聲明爲指針,b和c爲char數據 // ------------------------------------------------------ typedef char *charPtr; // It's Okay.. charPtr a, b, c; // a、b、c的類型都爲char*
⚠️const(只表示道義上不會修改,硬要改仍是能夠用別的指針輕易繞開限制,防君子不防小人。。)
聲明常量
const int a; int const a;
聲明指針
理解: 類型 、星號、變量名,這三個部分的相對順序老是固定的,星號左邊的const
修飾數據,星號右邊的const
修飾指針
指向常量的指針變量(徹底等價)
int const * p; const int * p;
指向變量的常量指針
int * const p;
指向常量的常量指針
int const * const ptr;
⚠️連接屬性
種類
手動改變連接屬性
extern
指定爲external(代碼塊內部使用extern聲明變量能夠確保使用的是最外部的全局變量)static
將缺省屬性爲external的聲明轉變爲internal屬性⚠️聲明 vs. 定義(從新理解了這兩個名詞。。)
聲明Declaration
定義Definition
儲存類型
靜態變量 - static
用途
自動變量 - auto