我不理解以下代码的结果:
#include <stdio.h>
#include <conio.h>
int main()
{
int a[4]={1, 3, 5, 6};
//suppose a is stored at location 2010
printf("%d\n", a + 2);
printf("%d", a++);
return 0;
}
为什么第二个printf
函数会产生以下错误?
error: lvalue required as increment operand
答案 0 :(得分:14)
<强>兼1:强>
数组名称是常量(不可修改的左值),您可以为数组名称添加值但不能修改它。
表达式a + 2
不会修改a
本身,但当您执行等同于a++
的{{1}}时,请尝试修改数组名称--lvalue错误。第二个printf中的表达式a = a + 1
是错误的 - 语义相位错误的一个例子。阅读以下语言标准:
6.3.2.1 Lvalues, arrays, and function designators
724 可修改的左值是一个没有数组类型的左值, 没有不完整的类型,没有const限定 类型,如果是结构或联合,则没有任何成员 (包括,递归地,包含所有成员或元素 具有const限定类型的聚合或联合。
729 除非是sizeof运算符或一元
a++
运算符的操作数, 或者是用于初始化数组的字符串文字,表达式 具有类型“数组类型”的类型转换为具有类型的表达式 “指向类型的指针”,指向数组的初始元素 对象并且不是左值。
第2部分:
注意大多数表达式中的数组名称在第一个元素的地址中衰减(读取一些由{H 2 CO 3 完全回答的exceptions where array name not decaying into a pointer to first element?)。
当你执行&
时,其结果是第三个元素的地址(或索引a + 2
处的元素的地址)所以2
与a + 2
相同它是地址而不是值在指数。
要打印地址,请使用&a[2]
代替%p
和类型转换地址到%d
,如下所示:
void*
要打印值,您需要使用防御运算符printf("address (a + 2) = %p , &a[2] = %p", (void*)(a + 2), (void*)(&a[2]));
,如下所示:
*
<强>兼3:强>
假设a存储在2010位置,是第一个printf函数2012的输出吗?
不,指针算术与整数算术不同。我们知道数组名称在大多数表达式中衰减为第一个元素地址的地址所以当你执行printf("address *(a + 2) = %d , a[2] = %d", *(a + 2), a[2]);
时,该值是索引为a + 2
的第三个元素的地址。因此,假设系统中的int大小为4字节,那么根据您2
地址值为2010的假设,a + 2
stat指向2018位置。
了解阅读10.2 Pointers and Arrays; Pointer Arithmetic和Pointer Arithmetic。
答案 1 :(得分:3)
int a[4]={1,3,5,6};
printf("%d\n",a++); // you should not modify array name
illegal in c
假设pa是整数指针
A pointer is a variable, so pa=a and pa++ are legal. But an array name is not a
variable; constructions like a=pa and a++ are illegal.
答案 2 :(得分:2)
我认为第一个输出将依赖于计算机中整数类型的表示方式。如果单个整数在内存中占用4个字节,则输出应为2018,即2010 + 2 * 4。第二个printf可能导致编译错误。
答案 3 :(得分:2)
首先,这个程序调用{{3}},我很少气馁,因为有这么多答案,其中没有一个提到这个。在您的printf
调用中,您的参数是指针,但您指定的格式为%d
,期望int
undefined behavior。 7.19.6.1
部分中的should be %p fprintf函数 printf
的部分引用的格式字符串段落 9 表示:
如果转换规范无效,则行为未定义。[...]
回到你的问题,a++
表达式产生错误,因为 postfix increment 要求它的操作数是可修改的左值 ,6.5.2.4
Postfix增量和减量运算符段落 1 中的标准草案说(强调我的):
后缀增量或减量运算符的操作数应具有限定或 不合格的真实或指针类型,应是可修改的左值。
我们可以从setion 6.3.2.1
值,数组和函数指示符段 1 中看到:
[...]可修改的左值是一个没有数组类型的左值[...]
答案 4 :(得分:1)
数组内存地址保持不变,因此您无法更改它。这就是你在++语句中所做的。所以编译器会抛出错误。
答案 5 :(得分:0)
a不是int类型的变量,它是指向整数的指针,因此要打印它,首先需要取消引用它
printf("%d\n", *(a + 2));
答案 6 :(得分:0)
数组的名称是一个常量指针,因此它总是指向该数组的第0个元素。它不是一个变量,所以也不能为它分配一些其他地址,也不能通过递增或递减来移动它。 因此
a = &var; /*Illegal*/
a++; /*Illegal*/
a = a-1; /*Illegal*/