字符串在C語言中實際是字符數組,因為C比其他大多數語言更底層,他並沒有提供字符串這個數據類型,而是采用相似的東西代替,這就是以字符為元素的數組。
char *s="PPYY";
上面這個字符串(我們也把它稱為字符串字面值),C會把它作為數組進行操作,
char s[]={'P','P','Y','Y'};
所以采用s[0],s[1]訪問這個字符串是被允許的,但是需要非常清醒的是,字符串字面值是不能被修改的,因為字符串字面值和字符數組在內存當中的工作方式是不一致的。
將C語言梳理一下,分布在以下10個章節中:
C++ Primer Plus 第6版 中文版 清晰有書簽PDF+源代碼 http://www.linuxidc.com/Linux/2014-05/101227.htm
我們以Linux系統為例,粗略說說為什麼他們的工作方式不一致,下圖是簡略的內存結構圖:
局部變量區域 棧 無序組合 堆 全局區 只讀存儲區 常量區 代碼區/*字符串字面值的工作工作方式*/
1、字符串字面值 "PPYY"先是存放在常量區,存放的樣子如下:
P P Y Y \0
(尾部有個\0 ,是字符串的在內存中的結束符,因為C語言並不知道字符串什麼時候結束。)
2、然後在棧上創建s這個指針變量,用以存放指向常量區"PPYY"字面值的地址。
這就解釋了為什麼我們嘗試修改字符串字面值的時候,程序會報錯,因為字符串字面值是存放在常量區的。
/*字符數組的工作方式*/
1、"PPYY"這個字符串字面值仍然先是存放在常量區。
2、在棧上創建一個字符數組,數組的長度和數組元素都和先前的字符數組一致。
這個時候我們在程序中操作這個字符數組的時候,其實是操作的這個字符串字面值在棧空間中的字符數組副本。
這裡我們順著這個思路理清楚 char *s這個指針變量和char s[]這個數組變量的不同之處在什麼地方。
char *s這個s是存放的常量區"PPYY"字面值的地址;而char s[]這個s表示棧空間中數組第一個元素的內存地址。上面兩個描述,一個是存放,一個表示,因為char *s在初始化的時候,是在內存中分配了char類型的地址變量空間的。而char s[]在初始化的時候,是沒有分配內存空間的,只是程序在編譯的時候,會把這個s替換成數組第一個元素的內存地址。
char s[]和char *s在作為函數形參時效果是一樣的,即void func_name(char s[])和void func_name(char *s)是等價的,但是此時的數組變量會退化成指針變量,作為數組變量,我們可以通過sizeof()運算符判斷數組的長度,但是指針變量我們只能得到這個指針變量本身的長度。