深入 理解char * ,char ** ,char a[ ] ,char *a[] 的區(qū)別

C語言中由于指針的靈活性著拭,導致指針能代替數組使用荷愕,或者混合使用衡怀,這些導致了許多指針和數組的迷惑,因此安疗,刻意再次深入探究了指針和數組這玩意兒抛杨,其他類型的數組比較簡單,容易混淆的是字符數組和字符指針這兩個荐类。怖现。。下面就開始剖析一下這兩位的恩怨情仇玉罐。屈嗤。。

〉跏洹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所保存的字符串的地址要出。鸳君。。

? ? ? ? ? 比如

? ? ? ? #include <stdio.h>

? ? ? int main()

? ? ? {

? ? ? ? char *s;

? ? ? ? s = "hello";

? ? ? ? printf("%p\n",s);

? ? ? ? return 0;

? ? ? }


其實做為一個開發(fā)者患蹂,有一個學習的氛圍跟一個交流圈子特別重要這里我推薦一個C語言C++交流群583650410或颊,不管你是小白還是轉行人士歡迎入駐,大家一起交流成長传于。免費的公開課供你學習囱挑!

可以看到 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語言中數組名可以復制給指針表示地址煞茫, 但是卻不能賦給給數組名,它是一個常量類型摄凡,所以不能修改续徽。。

? ? ? 當然也可以這樣:

? ? ? ? char? a [ ] = "hello";

? ? ? ? char *s =a;

? ? ? ? for(int i= 0; i < strlen(a) ; i++)

? ? ? ? ? ? printf("%c", s[i]);

? ? ? ? 或? printf("%c",*s++);

? ? ? ? 字符指針可以用 間接操作符 *取其內容亲澡,也可以用數組的下標形式 [ ]钦扭,數組名也可以用 *操作,因為它本身表示一個地址 床绪。客情。

? ? ? 比如 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é)了

? ? ? ? ? ? 看一下實例:

? ? ? ? ? ? #include <stdio.h>

   int main()

   {

   char *a [ ] = {"China","French","America","German"};

   printf("%p %p %p %p\n",a[0],a[1],a[2],a[3]);

   return 0;

   }


其實做為一個開發(fā)者极谊,有一個學習的氛圍跟一個交流圈子特別重要這里我推薦一個C語言C++交流群583650410诡右,不管你是小白還是轉行人士歡迎入駐,大家一起交流成長轻猖。免費的公開課供你學習帆吻!

可以看到數組中的四個元素保存了四個內存地址,這四個地址中就代表了四個字符串的首地址咙边,而不是字符串本身猜煮。次员。。

? ? ? 因此sizeof(a)當然是16了王带。淑蔚。

? ? ? 注意這四個地址是不連續(xù)的,它是編譯器為"China","French","America","German" 分配的內存空間的地址愕撰, 所以刹衫,四個地址沒有關聯。

? ? ? ? #include <stdio.h>

   int main()

   {

   char *a [ ] = {"China","French","America","German"};

? ? ? ? ? printf("%p %p %p %p\n",a[0],a[1],a[2],a[3]); //數組元素中保存的地址

   printf("%p %p %p %p\n",&a[0],&a[1],&a[2],&a[3]);//數組元素單元本身的地址

   return 0;

   }


可以看到 0012FF38 0012FF3C 0012FF40 0012FF44,這四個是元素單元所在的地址搞挣,每個地址相差四個字節(jié)绪妹,這是由于每個元素是一個指針變量占四個字節(jié)。柿究。邮旷。

? ? ? char **s;

? ? ? char **為二級指針, s保存一級指針 char *的地址蝇摸,關于二級指針就在這里不詳細討論了 婶肩,簡單的說一下二級指針的易錯點。?

? ? ? 舉例:

? ? ? char *a [ ] = {"China","French","America","German"};

? ? ? char **s =? a;

? ? ? 為什么能把 a賦給s,因為數組名a代表數組元素內存單元的首地址貌夕,即 a = &a[0] = 0012FF38;

? ? ? 而 0x12FF38即 a[0]中保存的又是 00422FB8 ,這個地址律歼, 00422FB8為字符串"China"的首地址。

? ? ? 即 *s = 00422FB8 = "China";

? ? ? ? 這樣便可以通過s 操作 a 中的數據

? ? ? printf("%s",*s);

? ? ? printf("%s",a[0]);

? ? ? printf("%s",*a);

? ? ? 都是一樣的啡专。险毁。。

? ? ? 但還是要注意们童,不能a = s畔况,前面已經說到,a 是一個常量慧库。跷跪。

? ? ? 再看一個易錯的點:

? ? ? char **s = "hello world";

? ? ? 這樣是錯誤的,

? ? ? 因為? s 的類型是 char **? 而 "hello world "的類型是 char *

? ? ? 雖然都是地址齐板, 但是指向的類型不一樣吵瞻,因此,不能這樣用甘磨。橡羞,從其本質來分析,"hello world",代表一個地址济舆,比如0x003001,這個地址中的內容是 'h'

? ,為 char 型卿泽,而 s 也保存一個地址 ,這個地址中的內容(*s) 是char * 吗冤,是一個指針類型又厉, 所以兩者類型是不一樣的∽滴粒 覆致。。

  如果是這樣呢肺蔚?

  char? **s;

? ? ? *s = "hello world";

? ? ? 貌似是合理的煌妈,編譯也沒有問題,但是 printf("%s",*s),就會崩潰

? ? ? why??

? ? ? 咱來慢慢推敲一下宣羊。璧诵。

? ? ? printf("%s",*s); 時,首先得有s 保存的地址仇冯,再在這個地址中找到 char *? 的地址之宿,即*s;

? ? ? 舉例:

? ? ? s = 0x1000;

? ? ? 在0x1000所在的內存單元中保存了"hello world"的地址 0x003001 , *s = 0x003001;

? ? ? 這樣printf("%s",*s);

? ? ? 這樣會先找到 0x1000,然后找到0x003001;

? ? ? 如果直接 char? **s;

? ? ? *s = "hello world";

? ? ? s 變量中保存的是一個無效隨機不可用的地址苛坚, 誰也不知道它指向哪里比被。。泼舱。等缀。,*s 操作會崩潰娇昙。尺迂。

? ? ? 所以用 char **s 時,要給它分配一個內存地址冒掌。

? ? ? char? **s ;

? ? ? s = (char **) malloc(sizeof(char**));

? ? ? *s =? "hello world";

? ? ? 這樣 s 給分配了了一個可用的地址噪裕,比如 s = 0x412f;

? ? ? 然后在 0x412f所在的內存中的位置,保存 "hello world"的值股毫。州疾。

? ? 再如:

? ? #include? <stdio.h>

? void? buf( char **s)

? ? {

? ? ? ? ? *s = "message";

? ? }

? ? int main()

? ? {

? ? ? ? char *s ;

? ? ? ? buf(&s);

? ? ? ? printf("%s\n",s);

? ? }

? ? 二級指針的簡單用法。皇拣。严蓖。。氧急,說白了颗胡,二級指針保存的是一級指針的地址,它的類型是指針變量吩坝,而一級指針保存的是指向數據所在的內存單元的地址毒姨,雖然都是地址,但是類型是不一樣的钉寝。弧呐。闸迷。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市俘枫,隨后出現的幾起案子腥沽,更是在濱河造成了極大的恐慌,老刑警劉巖鸠蚪,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件邻吭,死亡現場離奇詭異澄港,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門论笔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來男公,“玉大人噪伊,你說我怎么就攤上這事囚戚。” “怎么了酌摇?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵窖维,是天一觀的道長。 經常有香客問我妙痹,道長铸史,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任怯伊,我火速辦了婚禮琳轿,結果婚禮上,老公的妹妹穿的比我還像新娘耿芹。我一直安慰自己崭篡,他們只是感情好,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布吧秕。 她就那樣靜靜地躺著琉闪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪砸彬。 梳的紋絲不亂的頭發(fā)上颠毙,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機與錄音砂碉,去河邊找鬼蛀蜜。 笑死,一個胖子當著我的面吹牛增蹭,可吹牛的內容都是我干的滴某。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼霎奢!你這毒婦竟也來了户誓?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤幕侠,失蹤者是張志新(化名)和其女友劉穎帝美,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體橙依,經...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年硕旗,在試婚紗的時候發(fā)現自己被綠了窗骑。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡漆枚,死狀恐怖创译,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情墙基,我是刑警寧澤软族,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站残制,受9級特大地震影響立砸,放射性物質發(fā)生泄漏。R本人自食惡果不足惜初茶,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一颗祝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧恼布,春花似錦螺戳、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至爽待,卻和暖如春损同,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鸟款。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工揖庄, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人欠雌。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓蹄梢,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子禁炒,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內容

  • 在C語言中,五種基本數據類型存儲空間長度的排列順序是: A)char B)char=int<=float C)ch...
    夏天再來閱讀 3,325評論 0 2
  • 一而咆、框架 1、Mac系統(tǒng)及常用工具幕袱、進制;C數據類型暴备、常量變量、運算符们豌、表達式涯捻、格式化輸入輸出 2、關系運算符望迎、邏...
    師景福閱讀 682評論 0 1
  • 數組在程序設計中障癌,為了處理方便, 把具有相同類型的若干變量按有序的形式組織起來辩尊。這些按序排列的同類數據元素的集合稱...
    朱森閱讀 3,895評論 2 13
  • 1.基本概念 1.1 存儲單元 存儲單元一般應具有存儲數據和讀寫數據的功能,以8位(bit)二進制作為一個存儲單元...
    Robinone閱讀 45,095評論 5 15
  • C語言大總結 一胸墙、基礎: 1我注、進制、位權迟隅、1字節(jié)等于8位(位是計算機的最小儲存單位仓手,字節(jié)是計算機最小存儲單元)、十...
    霧中探雪閱讀 2,818評論 1 36