C 語言看似簡單,實則暗藏眾多陷阱。本文整理七道經典面試題,涵蓋字串複製越界、陣列指標特性、動態記憶體管理、堆棧區別等核心考點,並提供健壯的修正方案。
void test1() {
char string[10];
char* str1 = "0123456789";
strcpy(string, str1);
}
錯誤分析:源字串長度為 11(含結束符 \0),目標陣列僅 10 字節,導致緩衝區溢出。
健壯修正:
int StrCpy(const char* source, char dest[], size_t destSize) {
if (!source || !dest || strlen(source) >= destSize)
return 1; // 複製失敗
strcpy(dest, source);
return 0; // 複製成功
}
關鍵點:傳入目標緩衝區大小,檢查源長度嚴格小於目標容量。
void test2() {
char string[10], str1[10];
for (int i = 0; i < 10; i++)
str1 = 'a'; // 錯誤:陣列名為常量指標
strcpy(string, str1);
}
錯誤分析:
str1 是常量指標,不可作左值賦值str1 缺少結束符,strcpy 同樣越界修正版:
void test2() {
char string[10], str1[10];
for (int i = 0; i < 9; i++) // 預留結束符位置
str1[i] = 'a';
str1[9] = '\0';
strcpy(string, str1);
}
void test3(char* str1) {
char string[10];
if (strlen(str1) <= 10) // 應為 < 10
strcpy(string, str1);
}
錯誤分析:strlen 不含 \0,當源長度為 10 時實際佔 11 字節,仍會溢出。
修正:if (strlen(str1) < 10 && str1 != NULL)
void GetMemory(char* p) {
p = (char*)malloc(100); // 只修改區域副本
}
void Test() {
char* str = NULL;
GetMemory(str);
strcpy(str, "hello world"); // str 仍為 NULL
}
核心問題:C 語言參數傳值,函數內修改 p 不影響外部 str。需傳遞二級指標或返回指標。
修正方案一(二級指標):
void GetMemory(char** p) {
char* temp = (char*)malloc(100);
if (temp) *p = temp;
}
void Test() {
char* str = NULL;
GetMemory(&str);
// ...
free(str);
}
方案二(返回值):
char* GetMemory() {
return (char*)malloc(100);
}
char* GetMemory() {
char p[] = "hello world"; // 區域陣列在堆疊上
return p; // 函數返回後記憶體失效
}
原理:區域變量(auto)分配在堆疊,函數結束自動釋放。malloc 分配在堆上,需手動 free。
修正:動態分配並返回堆記憶體指標。
同樣演示二級指標正確傳遞動態記憶體。
void Test() {
char* str = (char*)malloc(100);
strcpy(str, "hello"); // 若 malloc 失敗返回 NULL,這裡崩潰
free(str);
}
鐵律:動態分配必檢查返回值。
malloc 維護空閒鏈表,尋找合適塊分割分配;free 回收並嘗試合併相鄰塊。長期運行會產生碎片,大塊分配可能觸發整理延遲。若無合適塊返回 NULL,故必須檢查。
這七道題揭示了 C 語言四大核心陷阱:
strncpy/snprintf 或手動檢查長度掌握這些原理,配合嚴格的防禦性編程習慣,方能寫出健壯的 C 代碼。