Re: [問題] 二維陣列給值的問題

看板C_and_CPP (C/C++)作者 (藍影)時間14年前 (2011/08/25 02:29), 編輯推噓3(303)
留言6則, 4人參與, 最新討論串4/4 (看更多)
每次看到 char arry, string 似乎都會讓人有所誤解.. 放下 string 問題, 先看一段比較正常的程式碼 #include <stdio.h> int main() { int i, arr[3] = {0,1,2}; for(i=0; i!=3; ++i) printf("%d ", arr[i]); return 0; } 這裡沒問題,重點是 3 如果改成 5,會有什麼結果? 很讓人意外的,「通常」只是會輸出一堆莫名奇妙的數字並不會馬上當掉,但後面的數字也變得沒有意義; 改成 10 的話,運氣好程式只是輸出錯誤,並不會停掉; 改成 100 的話,大概就一定會停掉了。 若到時 release 出去,這種錯誤並不好抓, 因不是每次執行結果都一定會失敗,有時失敗,有時成功; 最難抓的 bug, 我認為是 - 程式從頭到尾都很順的執行完了,但結果就是不對,上述是原因之一。 ----- 回到正文,若以單純的「字元陣列」而言, char CharArr[5] = {'1','2','3','4','5'}; 實際上,那些 '1', '2', '3', '4', '5' ,在記憶體裡面,是存成 ASCII 數值,也就是存成 0x31 , 0x32, 0x33, 0x34, 0x35,是一堆二進位數值, 只是用 %c 或 %d 或 %u 時,會再翻譯成適當的 字元,整數。 上面 CharArr 是合法的「字元陣列」,陣列大小五個,元素也是五個, 沒問題,在輸出時我多加了一點東西進去。 for(int i=0; i!=5; ++i) { printf("%c(%hhu)\n", CharArr[i],CharArr[i]); /* 輸出字元與對應之 ascii */ } 這也沒問題。有問題的是 %s 的部份。 %s 會有一個特性,就是從第一個元素,輸出到「非 '\0' 元素」為止, 且注意到, '\0' 在 ASCII code 代表數值即為 0。 承上 CharArr,在我設定的陣列裡面,並沒有給它任何 '\0' 的元素, 在記憶體裡面,我合理假設它可能是長這樣 0x31 0x32 0x33 0x34 0x35 ???? ???? ???? ???? ???? 0x00 如果此時進行以下指令時 printf("%s", CharArr); 問題從這裡才開始產生,0x31 輸出 '1', 0x32 輸出 '2', ... 一直到那五個問號都還不是 '\0' (也就是 0),也會跟著一起輸出, 一直到最後遇到莫名的 0,才停止輸出,這也是為何你程式會有亂碼的原因。 ----- 為了避免上述這種 %s 莫名奇妙不知道輸出到哪裡,於是在習慣上, 會把字元陣列的最尾巴,加上 '\0',也就是 ASCII(0) 這字元,作為結束字元。 所以若要用 %s 的時候,記得尾巴要加上 '\0',如 char CharArry[6] = { '1', '2', '3', '4', '5', '\0' }; 注意到了,用 %s 時,最後那個 '\0' 是不會顯示出來的。 因為前面已經有 1~5 五個元素,還要再加上 1 個「結束字元」,所以才會有種說法 字元陣列的大小,至少要大於等於字串長度 + 1 才行。 當然下面三種宣告並給初值的方式都一樣的。 char CharArr[6] = { '1' , '2', '3', '4', '5', '\0'}; /* 字元設定 */ char CharArr[6] = { 0x31 , 0x32, 0x33, 0x34, 0x35, 0x00}; /* ASCII Hex */ char CharArr[6] = { 49 , 50, 51, 52, 53, 0 }; /* ASCII Dec */ 至於還會有一些常見的字串常量 (字面常量),會直接寫成 char CharArr[6] = "12345" ; 事實上,這種寫法已經有偷偷在最後補上 0 了, 表面上只有用到五個元素,實際上包含了結束字元後,它一共是六個元素。 所以下面三種 %s 寫法,在 printf - %s 時都沒問題 char Str1[100] = {'1','2','3','4','5','\0'}; /* 沒設到元素全 0 */ char Str2[100] = "12345"; /* 注意到,最後有偷補 0 進去 */ printf("%s %s %s\n", Str1, Str2, "12345"); ---- 最後整理重點出來 1. 字元陣列 與 字串,差別在於 「有沒有結束字元」 2. %s 只能輸出字串,不能輸出字元陣列;意指,一定要有結束字元。 3. 字串常量 "abcd",事實上都有偷補結束字元 '\0' 進去,所以用 %s 不會有問題。 4. 使用 strlen、strcat ... 等相關字串函式,也會以結束字元 '\0' 做參考。 看完說明後,我想你下次問題的答案,已在 13 戒之 4,有空先去逛逛。 -- YouLoveMe() ? LetItBe() : LetMeFree(); -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 180.177.78.41

08/25 02:30, , 1F
op 了... XD
08/25 02:30, 1F

08/25 02:34, , 2F
XD
08/25 02:34, 2F

08/25 03:48, , 3F
其實不一定是 ASCII... ISO 646 也是有可能的 :O
08/25 03:48, 3F

08/25 04:04, , 4F
冷知識:嚴格來說大五碼只有規定雙位元,剩下可以是ASCII
08/25 04:04, 4F

08/25 04:06, , 5F
可以不是,UTF-8則和ASCII向後相容...
08/25 04:06, 5F

08/25 04:35, , 6F
感謝T大的解說,我先看過版規了,所以不會犯13戒之4XD
08/25 04:35, 6F
文章代碼(AID): #1ELKCIxm (C_and_CPP)
文章代碼(AID): #1ELKCIxm (C_and_CPP)