本文目錄
- [字符串回顧](http://www.cnblogs.com/mjios/archive/2013/03/18/2965750.html#label0)
- [一、用指針遍歷字符串的所有字符](http://www.cnblogs.com/mjios/archive/2013/03/18/2965750.html#label1)
- [二、用指針直接指向字符串](http://www.cnblogs.com/mjios/archive/2013/03/18/2965750.html#label2)
- [三、指針處理字符串的注意](http://www.cnblogs.com/mjios/archive/2013/03/18/2965750.html#label3)
說明:這個C語言專題,是學習iOS開發的前奏。也為了讓有面向對象語言開發經驗的程序員,能夠快速上手C語言。如果你還沒有編程經驗,或者對C語言、iOS開發不感興趣,請忽略
[回到頂部](http://www.cnblogs.com/mjios/archive/2013/03/18/2965750.html#labelTop)
### 字符串回顧
一個字符串由一個或多個字符組成,因此我們可以用字符數組來存放字符串,不過在數組的尾部要加上一個空字符'\0'。
~~~
char s[] = "mj";
~~~
上面的代碼定義了一個字符數組s來存儲字符串"mj",系統會自動在尾部加上一個空字符'\0'。
內存分布大致如右圖所示:
從上一篇文章《[十二、指向一維數組元素的指針](http://www.cnblogs.com/mjios/archive/2013/03/18/2964748.html)》中可以看出指針和數組的關系非常密切,因此我們也可以使用指針來操作字符串。
[回到頂部](http://www.cnblogs.com/mjios/archive/2013/03/18/2965750.html#labelTop)
### 一、用指針遍歷字符串的所有字符
~~~
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行后,內存分布如右圖:
有了前面[指針與數組](http://www.cnblogs.com/mjios/archive/2013/03/18/2964748.html)的基礎相信大家能看到第9行之后的代碼了:每次遍歷之前先判斷p當前指向的字符是否為空字符\0,如果不是空字符,就打印當前字符,然后執行p++讓指針p指向下一個字符元素。
最后的輸出結果:
[回到頂部](http://www.cnblogs.com/mjios/archive/2013/03/18/2965750.html#labelTop)
### 二、用指針直接指向字符串
從前面可以看出,指針確實可以指向字符串并操作字符串。不過前面的做法是:先定義一個字符串數組存放字符串,然后將數組首地址傳給指針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函數中的形參是指向字符變量的指針類型,在《[十、字符和字符串常用處理函數](http://www.cnblogs.com/mjios/archive/2013/03/15/2961759.html)》中我們可以將一個字符數組名傳進去,這一點又說明了指針與數組的密切關系,肯定有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指向的一個常量字符串,不允許修改它內部的字符。
[回到頂部](http://www.cnblogs.com/mjios/archive/2013/03/18/2965750.html#labelTop)
### 三、指針處理字符串的注意
現在想將字符串"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";定義的是一個字符串常量!
- 前言
- C語言入門教程1-概述
- C語言入門教程2-第一個C程序
- C語言入門教程3-關鍵字、標識符、注釋
- C語言入門教程4-變量與常量
- C語言入門教程5-進制
- C語言入門教程6-變量與內存
- C語言入門教程7-基本數據類型
- C語言入門教程8-運算符
- C語言入門教程9-流程控制
- C語言入門教程10-函數
- C語言入門教程11-函數的聲明定義
- C語言入門教程12-scanf與printf輸入輸出函數
- C語言入門教程13-數組-批量數據存儲
- C語言入門教程14-字符串
- C語言入門教程15-字符與字符串常用處理函數
- C語言入門教程16-指針
- C語言入門教程17-指向一維數組元素的指針
- C語言入門教程18-指針與字符串
- C語言入門教程19-預處理指令1-宏定義
- C語言入門教程20-預處理指令2-條件編譯
- C語言入門教程21-預處理指令3-文件包含
- C語言入門教程22-變量類型與作用域
- C語言入門教程23-枚舉
- C語言入門教程24-結構體
- C語言入門教程25-typedef類型別名