左值:出現在賦值符左邊的符號有時稱為左值。
右值:出現在賦值符右邊的符號有時稱為右值。
編譯器為每個變量分配一個地址(左值),這個地址在編譯時可知,而且該變量在運行時一直保存於這個地址。相反,存儲於變量中的值(它的右值)只有在運行時才可知。如果需要用到變量中存儲的值,編譯器就發出指令從指定地址讀入變量值並將它存於寄存器。
可以看到,每個符號的地址在編譯時可知。
對比一下幾個式子:
//常規變量
int a=1;//這裡a作為左值出現,代表的是地址,即在a表示的這個內存地址存入數值1。即a代表的內存地址這個地方的數據或是值,為1。
int b=a;//這裡a作為右值出現,代表的是數值,即a表示的這個內存地址上的數據,即數值1。
//指針
int *p=a;//這裡p作為左值出現,代表的是地址。把左邊看做一個整體,相當於在(*p)表示的內存地址的地方存入a的值,而p則是存的是(*p)所表示的地址。即p作為左值,本身代表一個內存地址,在該內存地址存的值即(*p)——是個數值,但該數值表示內存地址。然後在(*p)代表的內存地址地方存的是數值——即a的值。
int *pb=p;//這裡p作為右值出現,代表的是數值。即把p這個內存地址地方上的數值賦給pb內存地址,所以pb和p內存地址上數據相同,即指向了同一地方。
//char 數組
char arr[]="abcdefg";//這裡arr作為左值出現,代表的是地址。因為符號本身作為左值,代表的就是一個內存地址。所以,用數組名取元素時相當於對內存是直接引用。
printf("%s",arr);//這裡arr作為右值出現,代表的則是數值,即整個字符串。
對比數組名和指針取元素。數組名,就是一個內存地址。如果編譯器需要一個地址(可能還需要加上偏移量)來執行某種操作,它就可以直接進行操作,並不需要增加指令首先取得具體的地址。相反,對於指針,必須首先在運行時取得它的當前值,然後才能對它進行解除引用操作。數組是對內存直接引用,指針是對內存間接引用。
這樣的話,就可以理解下面代碼為什麼錯誤:
//file1
int a[10];
//file2
extern int *a;
即文件2希望用到文件1裡定義的一些變量。但是上述代碼是錯誤的。因為在文件1裡把a聲明為數組,實際上它是以直接引用的方式存取內存。而在文件2中把a外部聲明為指針,在a[i]進行取元素時,由於文件2看到的a是指針,則是對內存間接引用,則先取得a地址的數據,並把該數組作為地址再進行取數據,這樣當然是錯的。
以下是一些測試代碼:
可以看到數組名在printf函數中,作為右值出現時,如果是按%#x來打印的話,打印的還是地址。即按%#x打印,ga和&ga輸出的地址相同。(我的理解是,ga這個數組名本身代表的就是內存地址,作為右值出現時,是代表字符串,但這裡是按地址打印的;而&ga即取這個符號ga所在的地址。——解釋得不太好。)
但是對於指針,按%#x打印,指針名打出的是該地址的值(即指向地方的地址,因為指針作為右值出現,取的是值);取址指針名,即&指針名,打印的則是指針名代表的地址,即指針這個符號本身代表的地址。
#include結果:#include void my_array_func(char ca[]); void my_pointer_func(char *pa); char ga[] = "abcdefghijklmn"; int main() { printf(" ga = %#x \n",ga); printf(" addr of global array &ga = %#x \n", &ga); //printf(" &(&ga) = %#x \n", &(&ga));//(最左邊的)&必須是對左值進行操作 printf(" ga c = %c\n",ga); printf(" ga s = %s\n",ga); printf(" addr (ga[0]) &(ga[0]) = %#x \n", &(ga[0])); printf(" addr (ga[1]) &(ga[1]) = %#x \n\n", &(ga[1])); my_array_func(ga); my_pointer_func(ga); system("pause"); return 0; } void my_array_func(char ca[10]){ printf(" addr of array param &ca = %#x \n",&ca); printf(" addr (ca[0]) &(ca[0]) = %#x \n",&(ca[0])); printf(" addr (ca[1]) &(ca[1]) = %#x \n",&(ca[1])); printf(" ca = %#x \n",ca); printf(" ++ca = %#x \n", ++ca); } void my_pointer_func(char *pa){ printf(" addr of ptr param &pa = %#x \n",&pa); printf(" addr (pa[0]) &(pa[0]) = %#x \n",&(pa[0])); printf(" addr (pa[1]) &(pa[1]) = %#x \n",&(pa[1])); printf(" pa = %#x \n",pa); printf(" ++pa = %#x \n",++pa); }