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);
}

结果:

时间: 2024-10-09 16:58:49

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

c++中的左值与右值

++(a++) a++相当于 int a; { int temp=a; a++; teturn temp; } 所以我们可以将++(a++)看成++temp;而temp 显然是一个右值,所以不能用啊~~ L-value中的L指的是Location,表示可寻址.The "l" in lvalue can be though of as locationR-value中的R指的是Read,表示可读.The "r" in rvalue can be thought of

C++中让人忽视的左值和右值

前言 为了了解C++11的新特性右值引用,不得不重新认识一下左右值.学习之初,最快的理解,莫过于望文生义了,右值那就是赋值号右边的值,左值就是赋值号左边的值.在中学的数学的学习中,我们理解的是,左值等价于等号左边的值,右值等价于等号右边的值:当我们继续学习C语言时,等号=不再叫等号,盖头换面叫做赋值号:那么来到C++我们还能这么理解吗?答案是部分否定的. 假如你现在还是这样理解,那么请继续往下...... C++中何为左值lvalue和右值rvalue? 左值lvalue:可被引用的数据对象,例

4.1 中的左值和右值

摘要:  引自---http://www.cnblogs.com/catch/p/3500678.html 左值 (lvalue)和右值 (rvalue) 是 c/c++ 中一个比较晦涩基础的概念,有的人可能甚至没有听过,但这个概念到了 c++11 后却变得十分重要,它们是理解 move, forward 等新语义的基础. 左值右值的定义 左值与右值这两概念是从 c 中传承而来的,在 c 中,左值指的是既能够出现在等号左边也能出现在等号右边的变量(或表达式),右值指的则是只能出现在等号右边的变量

C++中的左值和右值

左值和右值的定义 在C++中,可以放到赋值操作符=左边的是左值,可以放到赋值操作符右边的是右值.有些变量既可以当左值又可以当右值.进一步来讲,左值为Lvalue,其实L代表Location,表示在内存中可以寻址,可以给它赋值(常量const类型也可以寻址,但是不能赋值),Rvalue中的R代表Read,就是可以知道它的值.例如: int a=3; a在内存中有地址,而3没有,但是可以read到它的值. 3=4; 这个是错误的,因为3的内存中没有地址,不能当作左值. 下面这个语句不容易出错 a++

[转] 左值和右值

http://www.cnblogs.com/dejavu/archive/2012/09/02/2667640.html#commentform <C/C++> 左值和右值, L-value和R-value 一直以为左值是可以出现在赋值表达式左边(the left side of an assignment expression)的值,Left-value;右值即Right-value. 今天看到一个说法,觉得有点味道: L-value中的L指的是Location,表示可寻址. The &q

c++ -- 左值和右值

总结--C++ primer 5 一.左值和右值(P121) 1. 概念 C++的表达式,要不然是右值,要不然是左值. 这两个名词继承与C语言,在C中是为了帮助记忆:左值可以位于赋值语句的左侧,右值则不能.在C++中,二者的区别没那么简单:当一个对象被用作右值的时候,用的是对象的值(内容):当对象被用作左值的时候,用的是对象的身份(在内存中的位置). 一个重要的原则(P470有一个例外):在需要右值的地方可以用左值来代替,但是不能把右值当成左值(也就是位置)使用.当一个左值被当成右值使用时,实际

对左值与右值的一些个人思考

今天重温C语言的指针,看的书是<C和指针>,关于左值和右值以及指针表达式的内容看得甚是迷惑与煎熬,怎么会这么难理解,指针表达式又是作为左值又一会作为右值,而且二者有着不一样的含义,为什么当年学习C语言的时候没有遇到这些头疼的问题呢?这就是没有学好C的原因吧. 功夫不负有心人,认真思考,对比总结,竟有些头绪,记录下来吧.以免以后又忘了没有参考. 先谈谈左值与右值的定义吧. 左值就是那些能够出现在赋值符号左边的东西:因此,右值就是那些可以出现在赋值符号右边的东西. 举个例子: a = b + 25

(C++)关于i++和i++的左值、右值问题

1.什么是左值和右值? 左值就是出现在表达式左边的值(等号左边),可以被改变,他是存储数据值的那块内存的地址,也称为变量的地址: 右值是指存储在某内存地址中的数据,也称为变量的数据. 左值可以作为右值,但右值不可以是左值. 因此也只有左值才能被取地址. 2.举两个问题: int i = 0; (i++)+=i; //错误 (++i)+=i; //正确 int *ip = &(i++); //错误 int *ip = &(++i); //正确 3.为什么i++不能作左值? 我们来看i++和i

C++11之右值引用:从左值右值到右值引用

C++98中规定了左值和右值的概念,但是一般程序员不需要理解的过于深入,因为对于C++98,左值和右值的划分一般用处不大,但是到了C++11,它的重要性开始显现出来. C++98标准明确规定: 左值是可以取得内存地址的变量. 非左值即为右值. 从这里可以看出,可以执行&取地址的就是左值,其他的就是右值. 这里需要明确一点,能否被赋值不是区分C++左值和右值的区别. 我们给出四个表达式: string one("one"); const string two("two&