大二開始學習C語言,一晃幾年過去了,一直在追趕新技術,底層的東西確總感覺沒吃透,今日有空,查閱了許多資料後,有感而發,覺得一定要寫下來,萬一忘記了,以後也可以查閱。
再論數組和指標:
(1)區分C語言中的聲明和定義
聲明只是告訴編譯器變數的類型和名字,定義才是真真決定記憶體配置的地方,在一個C程式中,定義只能有一個,而聲明卻可以有多個。
如檔案1中代碼:int a[10]; 定義數組,編譯器會為數組a分配10個整型的記憶體
如檔案2中代碼:extern int a[];聲明一個外部的數組,指向檔案1中編譯器分配了記憶體的變數a,聲明中並不進行記憶體配置,所以可以不用指定數組大小
如檔案3中代碼:extern int a[];也聲明一個外部的數組,也指向檔案1中編譯器分配了記憶體的變數a,聲明中並不進行記憶體配置,所以可以不用指定數組大小
(2)左值和右值的問題
如 a=b;這樣一條簡單的語句,蘊含著許多微妙之處,這也從另外一個方面體現了C語言中指標的精髓。指標的值(地址)與指標所的指向(地址中放的內容)
這裡a出現在等號左邊,為左值,代表的含義是a所代表的地址,在編譯時間就確定了,左值表示儲存結果的地方。
這裡的b出現在等號右邊,為右值,代表的含義是b所對應的地址的內容,右值在程式運行時才能知道。
C語言中有個非常重要的特性“可修改的左值”
如:int a=10;
int b=100;
a=b;
上面代碼是能夠正確啟動並執行,但是這個特性確對數組不適應,我們知道數組名也相當於一個地址值,也是左值,但它不能作為賦值對象
如: int a[10];
int b[10];
a=b; //錯誤,a不是可以修改的左值
我們正常的理解等號左邊的值應該都是可以賦值的,但是對數組例外,因此C語言中產生了“可修改的左值”這樣的特殊術語。
(3) char * s1=“abcdefg”與char s2[]="abcdefg"的區別
在剖析它的區別之前,有必要先分析下C程式的記憶體分布情況,
左邊為記憶體分布描述,中間為一段代碼,箭頭指向了所在的記憶體地區,右邊為在VS2010裡面調試時監視得到的個變數的值,這裡著重討論下char s1[]=“abcdefg”與char *s2="abcdefg"的區別:
s2為一個指標,指向的是字串的首地址,s1為字元數組,其值也是指向的是字串的首地址。儘管這兩個字串均為:“abcdefg”,但編譯器對它們分配的儲存空間有本質的區別,從左右邊監視的結果就可知,s1的值為0x0012ff40且s1自己地址值也為0x0012ff40,這說明s1分配在棧空間上,且對應的字串也在棧空間上。
再觀察指標變數s2其值為0x0041573c,s2本身的地址值為0x0012ff34,這說明了s2本身這個符號被分配在了棧空間上,但是其指向的內容"abcdefg"卻是在文字常量區。
正是這個本質的差別,導致了指標和數組訪問方式的不同,如下代碼:
char s1[]="abcdefg" ; char c= s1[1];編譯器符號表s1具有一個確定的地址值0x0012ff40,運行時由於取位移量1與0x0012ff40相加,取相加後地址值的內容。
char *s2="abcdefg"; char c=s2[1];編譯器符號表s2具有一個確定的地址0x0012ff34,運行時取0x0012ff34中的內容即為0x0041573c,將位移量1與0x0041573c相加,
取相加後的地址中的內容。
比較上面兩種方式,指標多了一個步驟。
指標所對應的字串是不能被修改的;而數組卻可以
也就是說下面代碼是錯誤的:
char *s2="abcdef";
s2[1]='k';
運行時會出現如錯誤:
而通過數組就可以修改,如代碼:
char s1[]="abcdef";
s1[1]='k';
導致這個區別的根本原因就在上面的記憶體配置上,一個在棧區,一個在文字常量區。