C中的数组增量运算符

我不明白以下代码的结果:

#include  #include  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

第1部分:

数组名称是常量(不可修改的左值),您可以为数组名称添加值但不能修改它。

表达式a + 2不会修改自身,但是当你执行相当于a = a + 1 a++ ,尝试修改数组名称–lvalue错误。 第二个printf中的表达式a++是错误的 – 语义相位错误的一个例子。 阅读以下语言标准:

6.3.2.1左值,数组和函数指示符

724可修改的左值是一个左值,它没有数组类型,没有不完整的类型,没有const限定类型,如果是结构或联合,则没有任何成员(包括,递归,任何具有const限定类型的所有包含聚合或联合的成员或元素。

729除非它是sizeof运算符或一元&运算符的操作数,或者是用于初始化数组的字符串文字,否则将类型为“array of type”的表达式转换为类型为“指向类型的指针”的表达式指向数组对象的初始元素,而不是左值

第2部分:

注意大多数表达式中的数组名称在第一个元素的地址中衰减(读取一些exception,其中数组名称不会衰减成指向第一个元素的指针?由@H 2 CO 3 很好地回答)。

当你做a + 2它的结果是第三个元素的地址(或索引2处元素的地址)所以a + 2&a[2]相同&a[2]它是索引处的地址而不是值。

要打印地址,请将%p而不是%d和类型转换地址用于void* ,如下所示:

 printf("address (a + 2) = %p , &a[2] = %p", (void*)(a + 2), (void*)(&a[2])); 

要打印值,您需要使用防御运算符* ,如下所示:

 printf("address *(a + 2) = %d , a[2] = %d", *(a + 2), a[2]); 

部分3:

假设a存储在2010位置,是第一个printf函数2012的输出吗?

不,指针算术与整数算术不同。 我们知道数组名称在大多数表达式中衰减为第一个元素地址的地址所以当你执行a + 2该值是索引2处的第三个元素的地址。 因此,假设系统中的int size是4个字节,那么根据您假设地址值为2010的情况,指向2018位置a + 2 stat。

理解读取10.2指针和数组; 指针算术和指针算法 。

 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.

我认为第一个输出将依赖于计算机中整数类型的表示方式。 如果单个整数在内存中占用4个字节,则输出应为2018,即2010 + 2 * 4。 第二个printf可能导致编译错误。

首先,这个程序调用未定义的行为 ,我很少气馁,因为有这么多答案,其中没有一个提到这个。 在你的两个printf调用中,你的参数是一个指针 ,你的格式为%d ,期望和int 应该是%p 。 第7.19.6.1节中的C99草案标准 printf的部分引用的fprintf函数返回格式字符串第9段说:

如果转换规范无效,则行为未定义。[…]

回到你的问题, a++表达式会产生错误,因为后缀增量要求它的操作数是一个可修改的左值6.5.2.4节中的草案标准增量和减量运算符1段说( 强调我的 ):

后缀增量或减量运算符的操作数应具有限定或不合格的实数或指针类型,并且应为可修改的左值

我们可以从第6.3.2.1看到的值,数组和函数指示符1段说:

[…]可修改的左值是一个没有数组类型的左值[…]

数组内存地址保持不变,因此您无法更改它。 这就是你在++语句中所做的。 所以编译器会抛出错误。

a不是int类型的变量,它是指向整数的指针,因此要打印它,首先需要取消引用它

 printf("%d\n", *(a + 2)); 

数组的名称是一个常量指针,因此它总是指向该数组的第0个元素。 它不是一个变量,所以我们也不能为它分配一些其他地址也不能通过递增或递减来移动它。 于是

 a = &var; /*Illegal*/ a++; /*Illegal*/ a = a-1; /*Illegal*/