1. 程式人生 > >C語言中字串的幾種定義方式和有沒有’\0‘

C語言中字串的幾種定義方式和有沒有’\0‘

( 主要解決 什麼時候是 “abcd\0” 什麼時候是 “abcd” 的問題 )

幾種常用方式
1.char* str = “abcd”;
2.char str[] = { “abcd” };
3.char str[] = { ‘a’, ‘b’, ‘c’, ‘d’ }; //要使用者自己加入’\0‘,應為str[] = { ‘a’, ‘b’, ‘c’, ‘d’ ,’\0’};
4.char str[5];scanf(“%s”,str);
5.char str[5];gets(str);

其中第2,3種方式沒有指定陣列的大小,如果正確指定當然更好。
那麼問題來了;
怎麼算是正確指定呢?
如果沒有正確指定,字串是什麼樣子呢?
第4,5種由使用者輸入的方法生成的字串,會有‘\0’嗎?
為了理清其中關係,我們搞幾個字串試一試;
首先,我們約定一個比較簡單的字串,比如:字串 “abcd” ,加上 ‘\0’ 是 “abcd\0” 5個字元的字串;
接下來,上程式碼:
程式碼


可以看到,第60行有報錯,第55行有警告;
警告我們先不管;
報錯的是 char str22[3] = { ‘a’,’b’,’c’,’d’ }; 這一句,原因是“初始值設定項太多”
於是我們就得到一個結論:在字元陣列進行逐一賦值時,字元個數不能大於陣列容量。

將報錯的語句註釋掉,重新編譯,警告不理會,於是:
程式碼

接下來,我們執行程式碼,並且在執行到scanf()和gets()函式時,我們都輸入 abcd
(說明:fflush()函式用來清空緩衝區,防止之前輸入字串後按的Enter鍵停留在緩衝區,gets()讀取鍵盤時直接將其讀走,導致gets()無法正確讀取鍵盤輸入 的問題)
執行結果:
這裡寫圖片描述


列印各字串的大小或者字元陣列的大小(用sizeof()操作符):
這裡寫圖片描述
看到這個結果,就發現其中幾個字串的列印是有問題的,那麼是什麼問題呢?

(說明:在Debug 模式下,VC 會把未初始化的棧記憶體全部填成0xcc,0xcc超過了ASCII碼0-127這個範圍,於是這個“字串”被系統當成了寬字元組成的字串,即兩個位元組資料組成一個字元,而0xCCCC表示的寬字元正好是個“燙”字。當字串看就是 燙燙燙燙……會把未初始化的堆記憶體全部填成0xcd,當字串看就是 屯屯屯屯……。Release 模式下,那塊記憶體裡本來裝的什麼值就是什麼值。)

這時我們做一個假設:因為字串沒有結束標誌‘\0’,從而在解析字串時沒法停下來,直到遇到了下一個字串的‘\0’。
接下來,我們來看一看,我們的假設是否正確。

在本圖中,我將每個字串的地址都放在了語句後面,並且在記憶體視窗中直接檢視每個字串對應的記憶體,以這種方式來分析各種字串的生成方式的差別。
這裡寫圖片描述

接下來,我們分析上圖:
1.為什麼不看字串 str0 呢?
str0是型別為 char* 指標,它指向“abcd”這個字串常量,而且這個字串常量被放置在此程式的記憶體靜態區,它與棧中的記憶體的地址距離甚遠,所以在圖中無法找到。我將其單獨放在這裡:
這裡寫圖片描述
從str0的記憶體來看,我們可以發現,字串常量 “abcd” 我們並沒有給它賦‘\0’,但是它 “abcd” 後面自動跟了四個位元組,四個位元組中都存了0,也就是‘\0’。而且sizeof(str0) == 4;也就是說,這個字串中並不包含‘\0’,但它仍是以‘\0’為結束標誌的字串。
2.字元陣列整體賦值
a.當不指定陣列大小時
str1[] = {“abcd”};
字元陣列自動跟了個‘\0’,並且本字串sizeof(str1)==5;也就是說這個字串是包含‘\0’,也就是“abcd\0”
b.當指定陣列大小 == 字元個數+1時
和不指定陣列大小的情況相同 ;“abcd\0”
c.當指定陣列大小 == 字元個數時
字串之後沒有‘\0’這個結束標誌,sizeof(str12)==字元陣列大小;“abcd”
d.當指定陣列大小 < 字元個數時
編譯器會發出警告,並且字串沒有‘\0’這個結束標誌,sizeof(str12)==字元陣列大小
e.當指定陣列大小 > 字元個數時
字元填入陣列,並且剩餘的陣列空間全為0;

3.字元陣列逐一賦值
a.當不指定陣列大小時
不會新增‘\0’,並且sizeof(str2) == 4,字串為 “abcd” 後面為隨機值
b.當指定陣列大小 == 字元個數+1時
字元陣列自動跟了個‘\0’,並且本字串sizeof(str21)==5;也就是說這個字串是包含‘\0’,也就是“abcd\0”
c.當指定陣列大小 < 字元個數時
編譯器報錯,無法進行編譯
d.當指定陣列大小 > 字元個數時
字元填入陣列,並且剩餘的陣列空間全為0;

4.由使用者輸入
字元陣列自動跟了個‘\0’,並且本字串sizeof(str1)==5;也就是說這個字串是包含‘\0’,也就是“abcd\0”

總結:
此時,我們就可以得出結論,我們的假設是正確的,而且結合第二條說明,我們可以看出,打印出不正常的字串都是沒有’\0‘的字串,也就是沒有字串結束標誌,於是將記憶體中的隨機值當字串列印了出來,直到遇到了下一個字串的’\0‘。我們應當注意這些情況,並且在定義字串時,根據這些字串生成方式的特點,結合實際需要生成更加合適的字串。