我不明白以下代码的结果:
1 2 3 4 5 6 7 8 9 10 11
| #include <stdio.h>
#include <conio.h>
int main ()
{
int a [4]={1, 3, 5, 6};
//suppose a is stored at location 2010
printf("%d\
", a + 2);
printf("%d", a ++);
return 0;
} |
为什么第二个printf函数会产生以下错误?
error: lvalue required as increment operand
-
这说明了有关数组的所有内容。如果您真的想了解数组,请阅读全文以帮助自己。
-
您是否不相信在编译该代码时收到的错误消息,或者在此处发布之前是否不费心地编译它?
-
@KeithThompson我在对位之前先对其进行了编译。想知道错误的原因。
-
@ user221458问题强烈建议我在发布之前尚未对其进行编译,但事实并非如此。我怀疑编译器的行为。
-
@ user221458我理解这一点,但问题并未反映出来,因此您如何就SO提出问题很重要。
-
好吧,我会记住这一点。反正我也不在乎要点。我在乎知识。
-
@ShafikYaghmour感谢您提供的信息。幸运的是,到目前为止,我提出的两个问题都没有被评为差或没有被解决。以后问我时会注意的。
-
下次,请在您的问题中提供确切的(复制并粘贴)错误消息。实际上,最好更新您的问题以立即执行此操作。
-
@KeithThompson完成..
-
我了解数组名称不被视为l值,因此您无法修改其状态。但是,为什么可以在数组argv上使用增量和减量运算符呢?
-
实际上,我只是想到编译器正在将argv数组作为指针传递,因此它等效于char *(* argv)[]。
第1部分:
数组名称是常量(不可修改的左值),您可以为数组名称添加值,但不能修改它。
表达式a + 2不会修改a本身,但是当您执行a++等效于a = a + 1时,请尝试修改数组名称--lvalue错误。第二个printf中的表达式a++是错误的-语义阶段错误的示例。阅读以下语言标准:
6.3.2.1 Lvalues, arrays, and function designators
724 A modifiable lvalue is an lvalue that does not have array type,
does not have an incomplete type, does not have a const-qualified
type, and if it is a structure or union, does not have any member
(including, recursively, any member or element of all contained
aggregates or unions) with a const-qualified type.
729 Except when it is the operand of the sizeof operator or the unary & operator,
or is a string literal used to initialize an array, an expression that
has type"array of type" is converted to an expression with type
"pointer to type" that points to the initial element of the array
object and is not an lvalue.
第2部分:
请注意,大多数表达式中的数组名称的第一个元素的地址都会衰减(请阅读某些例外,其中数组名称不会衰减为指向第一个元素的指针?可以通过@H 2 sub> CO 3 sub>可靠地回答)。
当您执行a + 2时,其结果是第三个元素的地址(或元素在索引2处的地址),因此a + 2与&a[2]相同,这是地址不是索引处的值。
要打印地址,请使用%p而不是%d,并按如下所示将地址转换成void*:
1
| printf("address (a + 2) = %p , &a[2] = %p", (void*)(a + 2), (void*)(&a [2])); |
要打印值,您需要防御运算符*,如下所示:
1
| printf("address *(a + 2) = %d , a[2] = %d", *(a + 2), a [2]); |
第三部分:
suppose a is stored at location 2010, Is the output of first printf function 2012?
不,指针算法与整数算法不同。众所周知,在大多数表达式中,数组名称都会衰减为第一个元素的地址,因此当您执行a + 2时,该值就是索引为2的第三个元素的地址。因此,假设您系统中的int大小为4个字节,则根据a地址值为2010的假设,a + 2 stat指向位置2018。
要理解,请阅读10.2指针和数组;指针算术和指针算术。
-
好。因此,a ++将更改存储a的初始内存地址,因此是不允许的。对?
-
@ user221458 a++尝试更改,但这是编译时错误,因为我说过将在语义阶段检测到。
-
@ user221458如果您了解编译器(或计算机科学)的学生,那么您应该知道错误的操作数是语义错误。
-
我知道。产生错误。但是我说的是a ++的意思吗?如果不考虑第二个printf,第一个printf的输出将是什么?是2012年吗?
-
@ user221458不,请允许我添加我的答案。
-
我知道它不是左值。我问的是不同的东西问题倾向于为什么它不是左值。你是绝对正确的。 Manoj Kumar已经回答了我的问题。
-
@ user221458这就是我所说的话!
-
@ user221458理解为我写在printf表达式中的数组名称,如果您最后一个数组地址用于通过索引访问数组元素,那么您将丢失完整的数组,因此编译器(语言标准)施加的约束是数组名称为unmodified-lvalue。
-
@ user221458取决于系统中int的大小,假设它是4个字节,那么如果a是2010,则a + 2给出2018。
-
@ user221458阅读10.2指针和数组;指针算术和指针算术。
-
假设a是数组对象的名称,则a++没有任何意义。
-
@KeithThompson我的意思是说a++不同于a + 1 ++指令试图修改a,这会在语义分析阶段(但在语法上正确)导致左值错误,但是它当然是编译时间错误。
-
@GrijeshChauhan:如果a是标量(数字或指针)对象,则a + 1和a++均有效,但含义不同。但是,如果a是数组名称,则a + 1是有效的(并等效于&a[1]),但是a++的含义不超过42++或米色的平方根。
-
@KeithThompson那正是我所解释的。
1 2 3 4 5 6
| int a [4]={1,3,5,6};
printf("%d\
",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.
首先,该程序会调用未定义的行为,而我不感到沮丧,因为答案如此之多,没有一个人提到这一点。在两个printf调用中,参数都是一个指针,但您将格式指定为期望的%d,而int则应为%p。 7.19.6.1部分中的C99草案标准printf部分针对格式字符串第9段引用的fprintf函数表示:
If a conversion specification is invalid, the behavior is undefined.[...]
回到您的问题,a++表达式会产生错误,因为后缀增量要求它的操作数是可修改的左值,6.5.2.4后缀增量和减量运算符第1段中的标准草案说(强调我):
The operand of the postfix increment or decrement operator shall have qualified or
unqualified real or pointer type and shall be a modifiable lvalue.
我们可以从set 6.3.2.1值,数组和函数指示符中看到,第1段说:
[...]A modifiable lvalue is an lvalue that does not have array type[...]
我认为第一个输出将取决于您的计算机如何表示整数类型。如果单个整数在内存中占用4个字节,则输出应为2018,即2010 + 2 * 4。第二个printf可能导致编译错误。
数组的名称是一个常量指针,因此它将始终指向该数组的第0个元素。它不是变量,因此我们也不能为其分配其他地址,也不能通过递增或递减来移动它。
因此
1 2 3
| a = &var; /*Illegal*/
a++; /*Illegal*/
a = a-1; /*Illegal*/ |
阵列内存地址保持不变,因此无法更改。这就是您在++语句中所做的。所以编译器会抛出错误。
a不是int类型的变量,它是指向整数的指针,因此要打印它,需要先取消引用它