Semorphe

字串沒有了

一段文字,其實是一排字元加一個結束記號。 · ⏱ 約 35 分鐘

你會學到三件事

  1. C 的字串就是 char 陣列
  2. 結尾那個看不見的 \0 才是「字串結束」的定義
  3. strlen / strcpy / strcmp——以及它們為什麼危險

開始之前

C++ 那邊:

string s = "hello";
s = s + "!";
cout << s.size() << endl;

而 C 沒有 string一個字都沒有。

一、它其實一直都是一排字元

char s[20] = "hello";

記憶體裡長這樣:

 h    e    l    l    o   \0    ?    ?   ...
[0]  [1]  [2]  [3]  [4]  [5]  [6]  [7]      共 20 格

⚠️ 第 6 格那個 \0 是編譯器幫你放的。

它是一個值為 0 的字元,意思是「字串到這裡結束」。 螢幕上看不見它,而所有處理字串的函式都靠它。

C 的字串沒有「長度」這個欄位。 長度是每次現數的——數到 \0 為止。

所以:

C++ 的 s.size() O(1)——它記著長度
C 的 strlen(s) O(n)——它每次從頭數

⚠️ 所以 for (int i = 0; i < strlen(s); i++) 是一個經典的效能陷阱: 它每一圈都重數一次。

二、為什麼要留 20 格

char s[20] = "hello";

"hello" 只要 6 格(含 \0),而我們宣告了 20。

因為陣列的大小不能變。之後想接東西上去,空間得先留好。

⚠️ 留不夠的話,寫下去會蓋到別人的記憶體,而 C 不會攔你。 那叫緩衝區溢位,是真實世界裡最常見的一類安全漏洞。

三、三個函式

printf("%d\n", strlen(s));      // 5    ——數到 \0
char t[20];
strcpy(t, s);                   // 把 s 複製到 t
printf("%d\n", strcmp(s, t));   // 0    ——一樣就是 0
做什麼 ⚠️ 危險在哪
strlen(s) 數長度 沒有 \0 的話它會一直數下去
strcpy(t, s) 把 s 複製到 t 不檢查 t 夠不夠大
strcmp(a, b) 比較 一樣回 0,不是回 1

🔴 strcmp 回 0 代表「一樣」

這違反直覺——大部分「比較」函式回 true 代表一樣,而 strcmp 相反。

它回的是「差多少」:

0     一樣
負數  a 排在 b 前面
正數  a 排在 b 後面

所以判斷相等要寫 if (strcmp(a, b) == 0)。 ⚠️ 寫成 if (strcmp(a, b)) 的話意思正好相反

🔴 而 == 不能用

if (s == t)      // 🔴 這是在比【位址】,不是比內容

st 是兩個陣列,== 比的是它們在記憶體裡的位置—— 永遠不相等。這個錯不會報錯,只會永遠走 else。

完成的樣子

int main() {
    char s[20] = "hello";
    printf("%d\n", strlen(s));
    char t[20];
    strcpy(t, s);
    printf("%d\n", strcmp(s, t));
    return 0;
}

換你了

t 的大小改成 char t[3],執行看看。

⚠️ 它可能還是印出 0——而那正是最可怕的地方: 壞掉的程式不一定會壞給你看。

這一課你做了什麼

如果卡住了

你看到 多半是因為
strlen 得到一個很大的數字 沒有 \0——多半是 strcpy 到一個太小的陣列
兩個字串明明一樣卻判定不同 用了 ==。要用 strcmp(...) == 0
判斷相等的邏輯反了 strcmp 回 0 是一樣。if (strcmp(a,b)) 是「不一樣」
程式莫名其妙壞掉 緩衝區溢位。目標陣列留大一點
在編輯器打開這一課 →