字符串的存儲方式有字符數組和字符指針。
因為字符串是由多個字符組成的序列,所以要想存儲一個字符串,可以先把它拆成一個個字符,然后分別對這些字符進行存儲,即通過字符數組存儲。字符數組是一個數組,且是存儲字符的數組,該數組中一個元素存放字符串的一個字符。
字符數組的定義
因為字符數組首先是一個數組,所以前面講的數組內容通通都適用。其次它是存放字符的數組,即數組的類型是char型。比如:
1 char name[10];
表示定義了10字節的連續內存空間。
1)如果字符串的長度大於10,那么就存在語法錯誤。這里需要注意的是,這里指的“字符串的長度”包括最后的‘\0’。也就是說,雖然系統會自動在字符串的結尾加‘\0’,但它不會自動為‘\0’開辟內存空間。所以在定義數組長度的時候一定要考慮‘\0’。
2)如果字符串的長度小於數組的長度,則只將字符串中的字符賦給數組中前面的元素,剩下的內存空間系統會自動用‘\0’填充。
字符數組的初始化
字符數組的初始化與數組的初始化一樣,要么定義時初始化,要么定義后初始化,下面寫一個程序來說明這個問題:
1 #include <stdio.h> 2 #include <stdlib.h> 3 int main(void) 4 { 5 char a[10]; 6 a[0] = 'i'; a[1] = ' '; a[2] = 'l'; a[3] = 'o'; a[4] = 'v'; 7 //空格字符的單引號內一定要敲空格 8 a[5] = 'e'; a[6] = ' '; a[7] = 'y'; a[8] = 'o'; a[9] = 'u'; 9 //空格字符的單引號內一定要敲空格 10 a[10] = '\0'; 11 char b[10]; 12 b[0] = 'i'; b[1] = ' '; b[2] = 'm'; b[3] = 'i'; b[4] = 's'; 13 //空格字符的單引號內一定要敲空格 14 b[5] = 's'; b[6] = ' '; b[7] = 'y'; b[8] = 'o'; b[9] = 'u'; 15 //空格字符的單引號內一定要敲空格 16 char c[] = "i believe you"; 17 char d[] = {'i', ' ', 'l', 'i', 'k', 'e', ' ', 'y', 'o', 'u','\0'}; 18 //空格字符的單引號內一定要敲空格 19 char e[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; 20 //空格字符的單引號內一定要敲空格 21 char f[] = "上課睡覺覺, 下課打鬧鬧, 考試死翹翹"; 22 char g[10] = ""; 23 printf("a = %s\n", a); //輸出字符串用%s, 輸出參數必須寫數組名 24 printf("b = %s\n", b); 25 printf("c = %s\n", c); 26 printf("d = %s\n", d); 27 printf("e = %s\n", e); 28 printf("f = %s\n", f); 29 printf("g = %s\n", g); 30 return 0; 31 }
首先要說明的是,這個程序只有在.cpp文件中才能運行,在.c文件中會有很多錯誤。因為我們在前面講過,C89標准規定變量的定義只能在程序的開頭,或者說定義變量的前面不能有其他非聲明或者非定義的語句。而.cpp文件是編寫C++程序的,C++向下完全兼容C,而且它對變量定義的位置有特殊要求,只要在使用位置之前即可。
數組a是先定義后初始化。一方面與以前講的數值型數組一樣,先定義后初始化必須一個一個地進行賦值,不能整體賦值;另一方面與以前講的數值型數組又不一樣,對於字符串,先定義后初始化也可以整體賦值,但是要調用strcpy函數,這點稍后再講。
總之上面這個程序中給數組a一個一個進行初始化的方式很麻煩。而且這樣寫需要注意:前面講過系統會在字符串的最后自動添加結束標識符‘\0’,但是當一個一個賦值時,系統不會自動添加‘\0’,必須手動添加。如果忘記添加,雖然語法上沒有錯誤,但是程序將無法達到我們想要的功能。數組b就是這樣的例子。
此外,空格字符必須要在單引號內"敲"一個空格,不能什么都不“敲”,什么都不“敲”就是語法錯誤。也不能多“敲”,因為一個單引號內只能放一個字符。“敲”多個空格就是多個字符了。
數組b就是最后沒有手動添加‘\0’的例子。程序是希望數組b輸出“i miss you”,但輸出結果是“i miss youi love you”.原因就是系統沒有在最后添加‘\0’。
雖然程序中對數組b的長度進行了限制,即長度為10,但是由於內存單元是連續的,對於字符串系統只要沒有遇到‘\0’,就會認為該字符串還沒有結束,就會一直往后找,直到遇到‘\0’為止。被找過的內存單元都會輸出,從而超過定義的10字節。
數組c是定義時初始化。定義時初始化可以整體賦值。整體賦值有一個明顯的優點——方便。定義初始化可以不用指定數組的長度,而先定義后初始化自必須要指定數組的長度,如數組a和數組b。不用指定數組長度有一個好處:不用人為確定需要多少字節的內存空間,系統會根據初始化的內容自動分配數量正好的內存空間。而且對於數組c的寫法系統會自動在最后添加標識符‘\0’,必須人為添加。忘記添加就會出現與數組b同樣的錯誤。從數組e的輸出結果可以看出這一點。
數組 f 是存儲漢字,漢字不能像數組 a 或數組 d 那樣分開一個一個賦值。因為一個漢字占 2 字節,若分開賦值,由於一個單引號內只能放一個字符,即一字節,所以將占 2 字節的漢字放進去當然就出錯了。因此如果用字符數組存儲漢字的話必須整體賦值,即要么定義時初始化,要么調用 strcpy 函數。
數組 g 初始化為一對雙引號,表示該字符數組中 10 個元素的內容都為 '\0'。下面寫一個程序驗證一下:
1 # include <stdio.h> 2 int main(void) 3 { 4 char str[3] = ""; 5 str[2] = 'a'; 6 printf("str = %s\n", str); 7 return 0; 8 }
輸出結果是:
str =
程序中定義了一個長度為 3 的字符數組,然后給第三個元素賦值為 'a',然后將整個字符數組輸出。但是輸出結果什么都沒有,原因就是其直接初始化為一對雙引號,此時字符數組中所有元素都是 '\0'。所以雖然第三個元素為 'a',但因為第一個元素為 '\0',而 '\0' 是字符串的結束標志符,所以無法輸出。
需要注意的是,使用此種初始化方式時一定要指定數組的長度,否則默認數組長度為 1。