我我的一直比較喜歡 C 這門編程語言,大學的時候學習了單片機,剛開始學的時候一臉懵逼,特別是那個彙編語言學得簡直讓人懷疑人生。後面開始接觸使用 C 語言編寫單片機程序,而後就這麼一直愛着它了。平時工做中用到的 C 編程語言不算多,可是我一直沒有放棄它,而是在默默的學習它、研究它,人嗎怎的有個小愛好吧?!linux
在 C 語言中,字符串其實是使用字符 '\0'
終止的一維字符數組。編程
如下幾種方式表示的都是 C 字符串的正確表達方式。數組
// 要以 '\0' 結尾
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
// 要以 '\0' 結尾
char greeting[] = {'H', 'e', 'l', 'l', 'o', '\0'};
// 默認會在末尾增長'\0'
char greeting[] = {"Hello"};
// 上面的簡寫形式
char greeting[] = "Hello";
// 默認會在末尾增長'\0'
char *greeting = "Hello";
複製代碼
看下面另一種聲明方式:bash
char greeting[] = {'h', 'e', 'l', 'l', 'o'};
printf("greeting: %s\n", greeting);
複製代碼
輸出結果:編程語言
greeting: hello\376
複製代碼
這個結果在不一樣編譯器下面可能還會不同,總之輸出都不是咱們想要的結果。這種方式建立的字符串沒有 '\0'
,不算是真正的 C 字符串,因此建議你們在聲明 C 字符串的時候使用字符指針(char *)的方式。函數
string.h
裏面聲明瞭不少關於操做 C 字符串的庫函數。學習
這裏在說計算字符串長度的前提是字符編碼都是按照UTF-8(中文佔用3個字節,英文佔用1個字節)的編碼形式爲前提的。咱們先來看下面這個例子,以下:ui
char *greeting1 = "hello";
char greeting2[] = {'h', 'e', 'l', 'l', 'o'};
char greeting3[] = {'h', 'e', 'l', 'l', 'o', '\0'};
char greeting4[] = "hello";
printf("greeting1 sizeOf: %ld, strlen: %ld\n", sizeof(greeting1), strlen(greeting1));
printf("greeting2 sizeOf: %ld, strlen: %ld\n", sizeof(greeting2), strlen(greeting2));
printf("greeting3 sizeOf: %ld, strlen: %ld\n", sizeof(greeting3), strlen(greeting3));
printf("greeting4 sizeOf: %ld, strlen: %ld\n", sizeof(greeting4), strlen(greeting4));
複製代碼
若是你能說出上面 printf
的結果,基本上關於計算字符串長度的問題就迎刃而解了。編碼
按照 UTF-8 編碼,上面例子的輸出結果以下所示:spa
greeting1 sizeOf: 8, strlen: 5
greeting2 sizeOf: 5, strlen: 7
greeting3 sizeOf: 6, strlen: 5
greeting4 sizeOf: 6, strlen: 5
複製代碼
若是輸出結果令你沒法相信,能夠選擇繼續往下看或者你本身寫代碼試試。
在 linux.die 能夠查到 strlen 的說明,以下:
Synopsis:
#include <string.h>
size_t strlen(const char *s);
Description:
The strlen() function calculates the length of the string s, excluding the terminating null byte (aq\0aq).
Return Value:
The strlen() function returns the number of bytes in the string s.
複製代碼
函數 strlen
返回字符串裏的字符數,不包括終止字符 '\0'
,這裏注意 strlen
是一個 C 的函數,而 sizeof
只是一個操做符。
咱們知道,sizeof
操做符的參數能夠是數組、指針、類型、對象、函數等,函數 strlen
的參數只能是字符串。
對於 sizeof
, 其參數不一樣時,其返回的值也不同,以下:
一、數組:編譯時分配的數組空間大小; 二、指針:存儲該指針所用的空間大小(32位機器上是4,64位機器上是8); 三、類型:該類型所佔的空間大小; 四、對象:對象的實際佔用空間大小(這個指的是在 C++ 中); 五、函數:函數的返回類型所佔的空間大小。函數的返回類型不能是 void 類型;
那咱們再回頭看看上面的例子,我把要說明的寫在註釋上面了。
// 注意這裏是指針
char *greeting1 = "hello";
// 沒有結束符 '\0',其 strlen 結果不肯定
char greeting2[] = {'h', 'e', 'l', 'l', 'o'};
char greeting3[] = {'h', 'e', 'l', 'l', 'o', '\0'};
char greeting4[] = "hello";
/* 結果是 八、5 */
/* greeting1是指針,sizeOf計算的是其存儲該指針所用的空間大小,由於我使用的是64位 macOS,因此輸出是8 */
/*strlen 計算的是字符個數可是不包括結束符 '\0'*/
printf("greeting1 sizeOf: %ld, strlen: %ld\n", sizeof(greeting1), strlen(greeting1));
/* 結果是 五、7 */
/* sizeof 計算的是編譯時分配的數組空間大小,這裏是5 */
/* greeting2沒有結束符,strlen 的計算結果不肯定 */
printf("greeting2 sizeOf: %ld, strlen: %ld\n", sizeof(greeting2), strlen(greeting2));
/* 結果是 六、5 */
/* sizeof 計算的是編譯時分配的數組空間大小,這裏是6,由於多告終束符 */
/*strlen 計算的是字符個數可是不包括結束符 '\0'*/
printf("greeting3 sizeOf: %ld, strlen: %ld\n", sizeof(greeting3), strlen(greeting3));
/* 結果是 六、5,這裏相似上面的狀況,再也不贅述 */
printf("greeting4 sizeOf: %ld, strlen: %ld\n", sizeof(greeting4), strlen(greeting4));
複製代碼
小結:
一、sizeof
是一個操做符,而 strlen
是 C 語言的庫函數。
二、sizeof
的參數能夠是任意數據類型或者表達式,而 strlen
只能以結尾爲 '\0'
的字符串做參數。
三、sizeof
的結果在編譯時就計算出了,而 strlen
必須在運行時才能計算出來。
四、sizeof
計算數據類型佔內存的大小,strlen
計算字符串實際長度,要記住 strlen
計算出來的結果不包括結束符 '\0'
。
五、sizeof
反應的並不是真實字符串長度而是所佔空間大小,因此memset
初始化字符串的時候用 sizeof
較好。
六、系統函數返回值是 char *
(字符指針)類型的會在末尾加上結束符 '\0'
。
七、不管是 sizeof
仍是 strlen
計算結果的單位都是字節。
咱們還須要注意一點,strlen
函數,當數組名做爲參數傳入時,實際上數組就退化成指針了。舉個例子,以下圖所示:
在文章的開始,我給出了幾種 C 字符串的正確表達方式,那咱們再來看另一種。
char greeting[4] = "blog";
複製代碼
這種方式看起來好像很完美的樣子,實際上是不對的,寫個例子給你們,以下:
int main(int argc, const char *argv[]) {
char greeting[4] = "blog";
size_t len = strlen(greeting);
printf("greeting len: %ld\n", len);
printf("greeting: %s\n", greeting);
return 0;
}
複製代碼
編譯運行,結果以下:
greeting len: 10
greeting: blog\330\365\277\357\376
複製代碼
蒼天呀,這結果讓人無語。。。
對於 char greeting[4] = "blog"
實際上是定義一個長度爲 4 的字符數組,可是字符串 "blog"
實際是要包括結束符 \0
的,也就是說下面的代碼
char greeting[4] = "blog";
複製代碼
本質和下面代碼是同樣的,以下:
char greeting[] = {'b', 'l', 'o', 'g'};
複製代碼
顯然是不正確的,那咱們修改一下代碼,以下:
int main(int argc, const char *argv[]) {
// 注意這裏是 5
char greeting[5] = "blog";
size_t len = strlen(greeting);
printf("greeting len: %ld\n", len);
printf("greeting: %s\n", greeting);
return 0;
}
複製代碼
或者這樣寫:
int main(int argc, const char *argv[]) {
// 這裏乾脆不要寫數字
char greeting[] = "blog";
size_t len = strlen(greeting);
printf("greeting len: %ld\n", len);
printf("greeting: %s\n", greeting);
return 0;
}
複製代碼
這樣修改後,再編譯運行結果就對了,以下:
greeting len: 4
greeting: blog
複製代碼
咱們知道的東西是有限的,咱們不知道的東西則是無窮的。