指標和字串
字串回顧
一個字串由一個或多個字元組成,因此我們可以用字元陣列來存放字串,不過在陣列的尾部要加上一個空字元'\0'。
char s[] = "mj";
上面的程式碼定義了一個字元陣列s來儲存字串"mj",系統會自動在尾部加上一個空字元'\0'。
記憶體分佈大致如右圖所示:
從上一篇文章《十二、指向一維陣列元素的指標》中可以看出指標和陣列的關係非常密切,因此我們也可以使用指標來操作字串。
回到頂部一、用指標遍歷字串的所有字元
1 // 定義一個指標p 2 char *p; 3 4 // 定義一個數組s存放字串 5 char s[] = "mj"; 6 7 // 指標p指向字串的首字元'm'8 p = s; // 或者 p = &s[0]; 9 10 for (; *p != '\0'; p++) { 11 printf("%c \n", *p); 12 }
執行完第8行後,記憶體分佈如右圖:
有了前面指標與陣列的基礎相信大家能看到第9行之後的程式碼了:每次遍歷之前先判斷p當前指向的字元是否為空字元\0,如果不是空字元,就列印當前字元,然後執行p++讓指標p指向下一個字元元素。
最後的輸出結果:
回到頂部二、用指標直接指向字串
從前面可以看出,指標確實可以指向字串並操作字串。不過前面的做法是:先定義一個字串陣列存放字串,然後將陣列首地址傳給指標p,讓p指向字串的首字元。
1.我們也可以直接用指標指向一個字串,省略定義字元陣列這個步驟
1 #include <string.h> 2 3 int main() 4 { 5 // 定義一個字串,用指標s指向這個字串 6 char *s = "mj"; 7 8 // 使用strlen函式測量字串長度 9 int len = strlen(s); 10 11 printf("字串長度:%D", len); 12 return 0; 13 }
注意第6行,我們直接用指標s指向了字串"mj",並沒有先建立一個字元陣列。看第9行,將指標s傳入到strlen函式中,說明之前所學習的字串處理函式依然可以正常使用。輸出結果:
2.我們再來看看strlen函式在string.h中的宣告
size_t strlen(const char *);
strlen函式中的形參是指向字元變數的指標型別,在《十、字元和字串常用處理函式》中我們可以將一個字元陣列名傳進去,這一點又說明了指標與陣列的密切關係,肯定有JQ。其實,呼叫strlen函式時,你傳一個地址給它就行了,它會從這個地址開始計算字元的個數,直到遇到空字元'\0'位置,因此傳入指標變數或者陣列名都可以。
其他字串處理函式也是一樣的:
1 char *strcpy(char *, const char *); // 字串拷貝函式 2 char *strcat(char *, const char *); // 字串拼接函式 3 int strcmp(const char *, const char *); // 字串比較函式
它們的引數都是指向字元變數的指標型別,因此可以傳入指標變數或者陣列名。
因此printf函式依然可以正常使用:
char *s = "mj"; printf("%s", s);
輸出結果:
3.指標指向字串的其他方式
char *s; s = "mj";
上面的指向方式也是正確的:先定義指標變數,再指向字串。如果是字元陣列就不允許這樣做,下面的做法是錯誤的:
1 char s[10]; 2 s = "mj";
編譯器肯定報第2行的錯,因為s是個常量,代表陣列的首地址,不能進行賦值運算。
還需要注意的是,下面的做法也是錯誤的:
1 char *s = "mj"; 2 3 *s = "like";
第3行程式碼犯了2個錯誤:
- 第3行程式碼相當於把字串"like"存進s指向的那一塊記憶體空間,由第1行程式碼可以看出,s指向的是"mj"的首字元'm',也就是說s指向的一塊char型別的儲存空間,只有1個位元組,要"like"存進1個位元組的空間內,肯定內存溢位
- 由第1行代碼可以看出,指標s指向的是字串常量"mj"!因此是不能再通過指標來修改字串內容的!就算是*s = 'A'這樣"看起來似乎正確"的寫法也是錯誤的,因為s指向的一個常量字串,不允許修改它內部的字元。
三、指標處理字串的注意
現在想將字串"lmj"的首字元'l'改為'L',解決方案是多種的
1.第一種方案
1 // 定義一個字串變數"lmj" 2 char a[] = "lmj"; 3 4 // 將字串的首字元改為'L' 5 *a = 'L'; 6 7 printf("%s", a);
程式正常執行,輸出結果:
2.應該有人能馬上想到第二種方案
1 char *p2 = "lmj"; 2 *p2 = 'L'; 3 4 printf("%s", p2);
看起來似乎是可行的,但這是錯誤程式碼,錯在第2行。首先看第1行,指標變數p2指向的是一塊字串常量,正因為是常量,所以它內部的字元是不允許修改的。
有人可能搞蒙了,這裡的第1行程式碼char *p2 = "lmj";跟第一種方案中的第2行程式碼char a[] = "lmj";不是一樣的麼?這是不一樣的。
- char a[] = "lmj";定義的是一個字串變數!
- char *p2 = "lmj";定義的是一個字串常量!