C 语言中的左值和右值。以及对比数组名和指针取数组元素的区别。

左值:出现在赋值符左边的符号有时称为左值。

右值:出现在赋值符右边的符号有时称为右值。

编译器为每个变量分配一个地址(左值),这个地址在编译时可知,而且该变量在运行时一直保存于这个地址。相反,存储于变量中的值(它的右值)只有在运行时才可知。如果需要用到变量中存储的值,编译器就发出指令从指定地址读入变量值并将它存于寄存器。

可以看到,每个符号的地址在编译时可知。

对比一下几个式子:

//常规变量

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);
}
结果:



参考:

《C专家编程》


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值