13

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

#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

4

7 回答 7

18

第1部分:

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

表达式a + 2不会自行修改a,但是当您这样做时a++,相当于a = a + 1尝试修改数组名称 --lvalue 错误。第二个 printf 中的表达式a++是错误的 - 语义阶段错误的一个例子。阅读以下语言标准:

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

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

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

第2部分:

注意大多数表达式中的数组名称在第一个元素的地址中衰减(阅读一些异常,其中数组名称没有衰减为指向第一个元素的指针? @H 2 CO 3巧妙地回答了)。

当你这样做时,a + 2它的结果是第三个元素的地址(或索引处元素的地址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,值是位于 index 的第三个元素的地址2。因此,假设您的系统中的 int 大小为 4 个字节,那么根据您的地址值为 2010a + 2的假设,stat 指向位置 2018 。a

要了解阅读10.2 指针和数组;指针算术指针算术

于 2013-10-02T05:01:04.553 回答
4
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.

于 2013-10-02T05:06:14.257 回答
2

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

于 2013-10-02T05:25:14.803 回答
2

首先,这个程序调用了未定义的行为,我一点也不气馁,有这么多答案,没有一个人提到这一点。在您的两个printf调用中,您的参数都是一个指针,但您正在指定%d预期的格式,int应该是 %pC99 标准草案第9 节中提到的格式字符串第97.19.6.1 的 fprintf 函数说:printf

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

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

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

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

[...]可修改的左值是没有数组类型的左值[...]

于 2013-10-02T12:31:11.397 回答
2

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

a = &var;  /*Illegal*/
a++;       /*Illegal*/
a = a-1;   /*Illegal*/
于 2017-01-01T17:14:02.367 回答
1

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

于 2013-10-02T05:05:52.083 回答
0

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

printf("%d\n", *(a + 2));
于 2013-10-02T06:40:37.447 回答