左值:出现在赋值符左边的符号有时称为左值。
右值:出现在赋值符右边的符号有时称为右值。
编译器为每个变量分配一个地址(左值),这个地址在编译时可知,而且该变量在运行时一直保存于这个地址。相反,存储于变量中的值(它的右值)只有在运行时才可知。如果需要用到变量中存储的值,编译器就发出指令从指定地址读入变量值并将它存于寄存器。
可以看到,每个符号的地址在编译时可知。
对比一下几个式子:
//常规变量
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<stdio.h> #include<stdlib.h> 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); }
结果: