char *与char []
由于指針的靈活性,導致指針能代替數組使用,或者混合使用,這些導致了許多指針和數組的迷惑,因此,刻意再次深入探究了指針和數組這玩意兒,其他類型的數組比較簡單,容易混淆的是字符數組和字符指針這兩個。。。下面就開始剖析一下這兩位的恩怨情仇。。。
1 數組的本質
數組是多個元素的集合,在內存中分布在地址相連的單元中,所以可以通過其下標訪問不同單元的元素。。
2 指針。
指針也是一種變量,只不過它的內存單元中保存的是一個標識其他位置的地址。。由于地址也是整數,在32位平臺下,指針默認為32位。。
3 指針的指向?
指向的直接意思就是指針變量所保存的其他的地址單元中所存放的數據類型。
int? * p ;//p 變量保存的地址所在內存單元中的數據類型為整型
?????????? float *q;// ........................................浮點型
?????????? 不論指向的數據類型為那種,指針變量其本身永遠為整型,因為它保存的地址。
????4? 字符數組。。。
????????字面意思是數組,數組中的元素是字符。。確實,這就是它的本質意義。
????? ?? char??str[10];?
???????? 定義了一個有十個元素的數組,元素類型為字符。
???????? C語言中定義一個變量時可以初始化。
???????? char? str[10] = {"hello world"};
???????? 當編譯器遇到這句時,會把str數組中從第一個元素把hello world\0 逐個填入。。
???????? 由于C語言中沒有真正的字符串類型,可以通過字符數組表示字符串,因為它的元素地址是連續(xù)的,這就足夠了。
???????? C語言中規(guī)定數組代表數組所在內存位置的首地址,也是 str[0]的地址,即str = &str[0];
???????? 而printf("%s",str); 為什么用首地址就可以輸出字符串。。
????????? 因為還有一個關鍵,在C語言中字符串常量的本質表示其實是一個地址,這是許多初學者比較難理解的問題。。。
????????? 舉例:
????? ??? char? *s ;
??????????s = "China";
????????? 為什么可以把一個字符串賦給一個指針變量。。
????????? 這不是類型不一致嗎???
????????? 這就是上面提到的關鍵 。。
????????? C語言中編譯器會給字符串常量分配地址,如果 "China", 存儲在內存中的 0x3000 0x3001 0x3002 0x3003 0x3004 0x3005 .
????????? s = "China" ,意識是什么,對了,地址。
????????? 其實真正的意義是 s ="China" = 0x3000;
????????? 看清楚了吧 ,你把China 看作是字符串,但是編譯器把它看作是地址 0x3000,即字符串常量的本質表現是代表它的第一個字符的地址。。。。。。。。。。
??????????s = 0x3000
??????????這樣寫似乎更符合直觀的意思。。。
????????? 搞清楚這個問題。。
????????? 那么 %s ,它的原理其實也是通過字符串首地址輸出字符串,printf("%s ", s);?? 傳給它的其實是s所保存的字符串的地址。。。
????????? 比如
? ? ? ??
[cpp]?view plaincopy print???????????????????????????
??????????
?
????? 可以看到 s = 0x00422020 ,這也是"China"的首地址
????? 所以,printf("%s",0x00422020);也是等效的。。
?????
?????? 字符數組:
???????char? str[10] = "hello";
?????? 前面已經說了,str = &str[0] , 也等于 "hello"的首地址。。
?????? 所以printf("%s",str); 本質也是 printf("%s", 地址");
????????C語言中操作字符串是通過它在內存中的存儲單元的首地址進行的,這是字符串的終極本質。。。
????5? char *? 與 char? a[ ];
???????char? *s;
?????? char? a[ ] ;
?????? 前面說到 a代表字符串的首地址,而s 這個指針也保存字符串的地址(其實首地址),即第一個字符的地址,這個地址單元中的數據是一個字符,
?? 這也與 s 所指向的 char 一致。
????? 因此可以 s =?a;
?????? 但是不能 a = s;
?????? C語言中數組名可以復制給指針表示地址, 但是卻不能賦給給數組名,它是一個常量類型,所以不能修改。。
?????? 當然也可以這樣:
? ? ? ?
????????字符指針可以用 間接操作符 *取其內容,也可以用數組的下標形式?[ ],數組名也可以用 *操作,因為它本身表示一個地址 。。
?????? 比如 printf("%c",*a);? 將會打印出 'h'
?????? char * 與 char a[ ] 的本質區(qū)別:
?????? 當定義 char a[10 ]? 時,編譯器會給數組分配十個單元,每個單元的數據類型為字符。。
?????? 而定義 char *s 時,? 這是個指針變量,只占四個字節(jié),32位,用來保存一個地址。。
?????? sizeof(a) = 10 ;
???????sizeof(s)? = ?
???????當然是4了,編譯器分配4個字節(jié)32位的空間,這個空間中將要保存地址。。。
??????? printf("%p",s);
??????? 這個表示 s 的單元中所保存的地址。。
??????? printf("%p",&s);
??????? 這個表示變量本身所在內存單元地址。。。。,不要搞混了。。
??????? 用一句話來概括,就是 char *s 只是一個保存字符串首地址的指針變量, char a[ ] 是許多連續(xù)的內存單元,單元中的元素為char ,之所以用 char *能達到
?char a? [ ] 的效果,還是字符串的本質,地址,即給你一個字符串地址,便可以隨心所欲的操所他。。但是,char* 和 char a[ ] 的本質屬性是不一樣的。。
????
???? 6????? char **? 與char? * a[ ] ;
??????????? 先看 char? *a [ ] ;
??????????? 由于[ ] 的優(yōu)先級高于* 所以a先和 [ ]結合,他還是一個數組,數組中的元素才是char * ,前面講到char * 是一個變量,保存的地址。。
??????????? 所以 char *a[ ] = {"China","French","America","German"};
??????????? 同過這句可以看到, 數組中的元素是字符串,那么sizeof(a) 是多少呢,有人會想到是五個單詞的占內存中的全部字節(jié)數 6+7+8+7 = 28;
??????????? 但是其實sizeof(a) = 16;
????????????為什么,前面已經說到, 字符串常量的本質是地址,a 數組中的元素為char * 指針,指針變量占四個字節(jié),那么四個元素就是16個字節(jié)了
??????????? 看一下實例:
? ? ? ??
[cpp]?view plaincopy print?
????? 可以看到數組中的四個元素保存了四個內存地址,這四個地址中就代表了四個字符串的首地址,而不是字符串本身。。。
????? 因此sizeof(a)當然是16了。。
????? 注意這四個地址是不連續(xù)的,它是編譯器為"China","French","America","German" 分配的內存空間的地址, 所以,四個地址沒有關聯。
? ? ? ?
[cpp]?view plaincopy print????????????
????? 可以看到 0012FF38 0012FF3C 0012FF40 0012FF44,這四個是元素單元所在的地址,每個地址相差四個字節(jié),這是由于每個元素是一個指針變量占四個字節(jié)。。。
?????? char **s;
???????char **為二級指針, s保存一級指針 char *的地址,關于二級指針就在這里不詳細討論了 ,簡單的說一下二級指針的易錯點。??
?????? 舉例:
? ? ? ?
[cpp]?view plaincopy print??????? 為什么能把 a賦給s,因為數組名a代表數組元素內存單元的首地址,即 a = &a[0] = 0012FF38;
?????? 而 0x12FF38即 a[0]中保存的又是 00422FB8 ,這個地址, 00422FB8為字符串"China"的首地址。
???????即 *s = 00422FB8 = "China";
???????? 這樣便可以通過s 操作 a 中的數據
? ? ??
[cpp]?view plaincopy print???????都是一樣的。。。
????? 但還是要注意,不能a = s,前面已經說到,a 是一個常量。。
??????再看一個易錯的點:
? ? ??
[cpp]?view plaincopy print?????? 這樣是錯誤的,
?????? 因為? s 的類型是 char **? 而 "hello world "的類型是 char *
???????雖然都是地址, 但是指向的類型不一樣,因此,不能這樣用。,從其本質來分析,"hello world",代表一個地址,比如0x003001,這個地址中的內容是 'h'
? ,為 char 型,而 s 也保存一個地址 ,這個地址中的內容(*s) 是char * ,是一個指針類型, 所以兩者類型是不一樣的?! ?。
如果是這樣呢?
??
? ???? 貌似是合理的,編譯也沒有問題,但是 printf("%s",*s),就會崩潰
??? ?? why??
????? 咱來慢慢推敲一下。。
???? ??printf("%s",*s); 時,首先得有s 保存的地址,再在這個地址中找到 char *??的地址,即*s;
??? ??舉例:
? ? ??
[cpp]?view plaincopy print???????在0x1000所在的內存單元中保存了"hello world"的地址 0x003001 , *s = 0x003001;
????? 這樣printf("%s",*s);
????? 這樣會先找到 0x1000,然后找到0x003001;
????? 如果直接 char? **s;
? ? ??
[cpp]?view plaincopy print??????? s 變量中保存的是一個無效隨機不可用的地址, 誰也不知道它指向哪里。。。。,*s 操作會崩潰。。
?????? 所以用 char **s 時,要給它分配一個內存地址。
? ? ??
[cpp]?view plaincopy print???? ? 這樣 s 給分配了了一個可用的地址,比如 s = 0x412f;
????? 然后在 0x412f所在的內存中的位置,保存 "hello world"的值。。
??? 再如:
? ?
[cpp]?view plaincopy print???? 二級指針的簡單用法。。。。,說白了,二級指針保存的是一級指針的地址,它的類型是指針變量,而一級指針保存的是指向數據所在的內存單元的地址,雖然都是地址,但是類型是不一樣的。。。
轉自:http://blog.csdn.net/daiyutage/article/details/8604720
總結
以上是生活随笔為你收集整理的char *与char []的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 流产当月竟然又怀孕了能要吗
- 下一篇: Mat详解-OpenCV