首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言字串陣列陷阱:char* 陣列與 scanf 的記憶體佈局誤區

     編輯:關於C語言

問題現場

int main() {
    char *key[2];
    scanf("%s", &key[0]);
    scanf("%s", &key[1]);
    printf("%s\n", &key[0]);
    return 0;
}

錯誤現象

輸入輸出說明
whos whowhoswho第一字串 4 字元 + \0 正好 4 位元組 (32 位指標大小)
wwwwww ddddddwwwwdddddd6 字元超出 4 位元組,溢位覆蓋

根本原因分析

1. 記憶體佈局

char *key[2];  // 棧上分配 2 個指標 (32位系統各 4 bytes,共 8 bytes)
/*
記憶體圖示 (位址遞增向右):
key[0] (4 bytes) | key[1] (4 bytes)
   指標值         指標值
*/

key[0] 與 key[1] 僅是兩個指標變數,各佔 4 位元組 (32 位系統),未分配任何字串儲存空間。

2. scanf 寫入過程

  • scanf("%s", &key[0]) 將字串寫入 key[0] 所在的 4 位元組空間
  • 字串長度 ≤ 3 字元 (+ \0) 時,勉強放入指標空間
  • 超過 3 字元時,溢位寫入相鄰的 key[1] 空間
  • key[0] 的結束符 \0 被覆蓋,導致 printf 繼續讀取 key[1] 區域

3. 為何最後一個字串正常?

最後輸入的字串寫入 key[1],其後無其他變數被覆蓋,結束符保留,故能正確輸出。

正確做法對比

錯誤:指標陣列未分配空間

char *key[2];
scanf("%s", &key[0]);  // 寫入指標變數本身,非指向的記憶體

正確 1:二維字元陣列 (靜態分配)

char key[2][100];  // 2 個 100 字元緩衝區
scanf("%99s", key[0]);
scanf("%99s", key[1]);

正確 2:指標陣列 + 動態分配

char *key[2];
key[0] = malloc(100);
key[1] = malloc(100);
scanf("%99s", key[0]);
scanf("%99s", key[1]);
// 使用後 free(key[0]); free(key[1]);

正確 3:單一緩衝區 + 指標陣列指向

char buffer[200];
char *key[2] = {buffer, buffer + 100};
scanf("%99s", key[0]);
scanf("%99s", key[1]);

核心概念釐清

宣告記憶體含義可直接存字串?
char *p;1 個指標 (4/8 bytes)否,需 malloc
char p[100];100 字元緩衝區是
char *p[2];2 個指標 (8/16 bytes)否,各需指向有效記憶體
char p[2][100];2×100 字元緩衝區是

編譯器警告提示

現代編譯器 (GCC/Clang/MSVC) 對 scanf("%s", &key[0]) 會發出警告:

warning: format '%s' expects argument of type 'char *', but argument 2 has type 'char **' [-Wformat=]

永遠不要忽略編譯器警告,這正是型別不匹配的鐵證。

結語

char *key[N] 僅建立 N 個指標,不包含字串儲存空間。初學者常混淆「指標陣列」與「二維字元陣列」。牢記:指標需指向有效記憶體才能存取資料,否則必然導致未定義行為與難以診斷的 Bug。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved