&符号
(1)int &r = i; 在声明中,表示引用
(2)p = &i; 在表达式里,是取址运算符
*符号
(1)int *p; 在声明中,表示指针
(2)*p = i; 在表达式里,是解引用运算符
左值和右值
一般来说,赋值操作等号左边是(可修改的)左值,右边取右值
变量
一块有名字的存储区域,是左值
值
某种类型的二进制数据,是右值
左值/右值示例
int i,j;
(1)左值=右值(√) i = 0;
(2)右值=左值(×) 0 = i;
(3)左值=“左值”(√)i = j;
左右值转换 lvalue-to-rvalue conversion
问:为什么(3)是对的?
答:当赋值操作右侧是左值时,会自动将左值转换为右值,即对变量j进行一次读取
表达式与左右值
问:如果我只输出一个表达式而没有赋值操作,比如只简单输出一个变量 cout << a; 那么怎么理解a?
答:C语言中,表达式(expression)的结果是一个“值”,所以此时a也是右值,同样做了lvalue-to-rvalue conversion,对a的值进行了一次读取
数组名
(1)变量的一种,是一块存储区域,存储的“按理说”是整个数组
(2)是左值,但是不可修改
(3)作为右值是“数组首元素的首地址”(见下文)
指针变量
(1)变量的一种,是一块存储区域,存储的是某个指针,也就是地址
(2)是左值,可修改
数组名使用实例
(1)查看整个数组所占的空间
int arr[5] = { 1,2,3,4.5 };
cout << sizeof(arr) << endl; //结果是20
cout << sizeof(arr[0]) << endl; //结果是4
(2)数组名赋给指针变量
int arr[5] = {1,2,3,4.5};
int *p = arr;
数组指针转换 array-to-pointer conversion
问:(1)算出来是20说明数组名存储的是整个数组,那为什么在(2)里可以赋值给指针变量?
答:当数组名作为右值时,会转化为“数组首元素的首地址”
数组首地址与首元素的首地址
(1)数组首地址 &arr
(2)数组首元素首地址 &arr[0]
(3)作为右值时,arr等同于&arr[0]
(4)&arr与&arr[0]的值相同,即arr和&arr与&arr[0]的值三者均相同
(5)&arr+1 跨越整个数组 地址加20 (4*sizeof(int))
(6)arr+1 跨越一个元素 地址加4 (sizeof(int))
结论
(1)数组名作为右值时,等同于“数组首元素首地址”,而不是“数组首地址”
(2)“数组名等同于数组首元素首地址”这种说法并不严谨,或者说会产生误解,如无法解释sizeof(arr)