字串?字元陣列?指標?傻傻分不清楚
首先我們來看一下下面這個程式,不妨先猜猜它會輸出什麼喲。
#include<stdio.h> #include<string.h> int main(void) { int a[5] = {1,2,3,4,5}; int i = 1; char str1[] = "HelloWorld\n";//陣列除了在被運算子sizeof操作的時候不是直接看作地址外,其餘都是可以直接等同於這個陣列首元素的地址的。即一個指向首元素的指標 char *str2 = "HelloWorld\n"; char *str6 = {"HelloWorld\n"}; char str3[] = {"HelloWorld\n"};//事實上等同於第一種 char str4[] = {'H','e','l','l','o','W','o','r','l','d','\n','\0'}; char str5[] = {'H','e','l','l','o','W','o','r','l','d','\n'};//末尾沒有加 \0 結束符 最後可能會輸出該陣列外記憶體裡的東西 printf("%d %d %d\n",a[i],i[a],3[a]);//當執行a[i]時 事實上等同於*(a+i); 而a + i == i + a; 所以,我們用i[a]也可以達到目的 同樣的 3[a]也是 //str1[2] = 'M'; // 位置1 printf(str1); //str1[2] = 'M'; // 位置2 //str2 = "This a Test"; // 位置3 printf(str2); printf(str3); printf(str4); printf(str5); printf("strlrnResult: %d %d %d %d %d\n",strlen(str1),strlen(str2),strlen(str3),strlen(str4),strlen(str5)); printf("sizeofResult: %d %d %d %d %d\n",sizeof(str1)/sizeof(str1[0]),sizeof(str2)/sizeof(str2[0]),sizeof(str3)/sizeof(str3[0]),sizeof(str4)/sizeof(str4[0]),sizeof(str5)/sizeof(str5[0])); }
前面各個字串的輸出結果相信大家應該都很清楚,第五個的結果在不同機器上執行的到的結果可能會不同,事實上也存在一定的偶然性,這裡我們不討論它們,我們主要一起討論一下定義以及最後兩行輸出的結果分析。
我們在C語言裡,想要定義一個所謂的字串,事實上是通過定義一個字元陣列來實現的:像系統申請一塊記憶體,然後可以再定義的時候一次性給它們都放入元素,也可以事後另外再一個個給它們賦值,要注意,如果不在定義的時候一次性賦值,後面就不要嘗試偷懶直接把用雙引號包住的東西直接給它了喲。
通常我們想使用字串時定義使用比較多的方式主要是這兩種:1、通過定義一個字元陣列,並在初始的時候直接把一個字串常量的值給它或者是通過一個個字元的形式賦值,如果是後者,一定不要忘記’\0‘符號。在定義一維字元陣列的時候,如果直接給它賦初值了,那麼陣列的長度可以不顯示給出 2、定義一個字元指標,並讓它指向字串常量。(注意,是常量喲,如果非刻意如此,不建議這麼做)或者是讓它指向另一個數組。(這也是指標的靈活性所在)
當我們使用字元指標來操作時,大家可千萬別讓它直接指向了一個常量!為什麼?因為如果你非刻意需要一個常量的話,那你這麼做的確是有點多餘了。
這個指標指向的這個常量你不知道它在哪,你也不知道怎麼修改值。當你需要做出改變的時候,你會發現無從下手,最後你只能無奈的放棄讓這個指標指向它從而重新弄一塊記憶體重新的到一片可控的空間。不妨試試把位置1、位置2和位置3分別取消註釋看看結果,並想想為什麼。
你可能要說,我本來就需要這麼一個常量,我就喜歡這麼做。那為什麼不考慮考慮巨集定義,就一定要吊死在字元指標這一棵樹上呢?或許那是個更好的選擇。
關於定義我們就討論這麼多啦,接下來看看最後的兩個輸出結果吧。
strlrnResult: 11 11 11 11 23 sizeofResult: 12 4 12 12 11
用函式strlen與運算子sizeof分別求得的結果為什麼會不一樣呢?我們簡單分析一下就知道了:
str1和str3兩種方式輸出的結果不一樣 是因為我們在定義字元陣列的時候,如果非第四、五種定義方式,會自動為你補上一個NUL結束符作為字元的結束符。函式strlen是以’\0’(即NUL,注:並不存在這樣的保留字)為結束條件的,所以strlen未計算結束符’\0‘。而運算子sizeof(str)是計算這個陣列總共花費的記憶體大小/陣列每個元素大小,也就是它包括了結束符在裡面。 故後者得到的結果比前者大1.
str2兩種方式輸出的結果不一樣 是因為str2是採用了字元指標的方式定義的,指標的長度在同一臺電腦上所佔的長度是一致的。(在32位電腦中應該是4)。因為不管是什麼指標,它事實上就是一個地址,使用4個位元組可以存下。故sizeof(str2)得到的是這個指標本身所佔的記憶體的大小。而strlen是將這個指標作為字元陣列來對待的,因此計算的是字元陣列真正的長度。
str5兩種方式輸出的結果不一樣,是因為前者未在自己本來地盤(也就是自己申請的那塊記憶體)的末尾加上’\0’,因此使用strlen會一直往後找,判斷後面的是不是’\0’,直到找到或者產生錯誤。(注:極可能發生嚴重的錯誤,儘管我自己電腦並沒有,它找到了str4的結束符停止了並把str5與str4、str4的整體都包含進來了)。 而sizeof計算時,當時系統是為其分配了11個sizeof(str5[0])長度 所以結果自然就為11咯。