具有增量和减量运算符的指针

时间:2019-05-16 08:04:26

标签: c

通常,当赋值运算符存在时,左操作数应该是变量而不是表达式,但是当我使用指针使左侧成为表达式时,代码不会产生任何错误。

Jdoodle在线编译器/ C

尽管编译成功,它应该抛出一个错误。

https://www.jdoodle.com/c-online-compiler

#include <stdio.h>

int main()
{
    int x = 30, *y, *z;

    y = &x; // Assume address of x is 1000 and integer is 4 byte size */
    z = y;
    *y++ = *z++;
    x++;
    return 0;
}

4 个答案:

答案 0 :(得分:2)

赋值的左操作数不必是变量。例如,以下分配应该并且确实可以很好地工作(我假设您知道这一点,并且只是弄错了):

array[index] = value;
*ptr = value;

我认为让*y++ = *z++;感到困惑的是,您认为它是分配给增量操作的结果,这的确没有任何意义。但这不是该表达式的优先级:*y++等效于*(y++),而不是(*y)++。因此,您要取消引用y++的结果,然后将一个值分配给该已取消引用的内存位置,就像您编写了一样:

int *ptr = y++;
*ptr = *z++;

答案 1 :(得分:2)

  

通常,当赋值运算符存在时,左操作数应   是变量而不是表达式...

赋值运算符的左操作数总是 一个表达式。限制是它必须是 lvalue ,它是(简化一点)指定对象的表达式。

左值最简单的情况是声明的对象/变量的名称,例如:

int n;
n = 42;

n是一个表达式,特别是一个左值,它指定名为n的对象。

在您的示例中,您有:

*y++ = *z++;

运算符优先级表示++运算符的绑定比*运算符更紧密,因此等效于:

*(y++) = *(z++);

y++z++不是值-它们是产生指针值的表达式,但它们不指定任何对象。但是,一元*运算符会为您提供左值,即使其操作数不是左值也是如此。 y++产生一个指针值,*(y++)为您提供该指针指向的对象。

从这个意义上说,C标准不使用术语“变量”。它讨论了 objects ,它可以被声明为具有简单名称的对象,也可以不被声明为对象。 an_object*pointer_valuearray[index]structure_object.member都是对象,它们可以出现在作业的左侧。

答案 2 :(得分:2)

  

左操作数应该是变量而不是表达式

这是一个误会。您要查找的术语是 lvalue 。这是源自术语“左侧值”的C标准乱码。术语 lvalue 的定义大致是:一个指定对象的表达式。

这里讨论的各种运算符的规则是:

  • 赋值运算符的左操作数必须始终为左值。
  • 一元*运算符的结果被定义为始终是左值,因此您可以像使用它一样使用它,我们可以为其赋值。
  • 但是++运算符的结果不是 一个左值,因此不能用作赋值的左操作数。

示例:

int x; int* y;

x = 5;   // Here x is both an object and an lvalue, so the code is valid
y = &x;  // y is both a (pointer) object and an lvalue, code is valid.
*y = 0;  // *y is an lvalue designating the object y, code is valid
y++ = 1; // y++ is not an lvalue, the code is invalid

关于*y++起作用的原因,这只是运算符优先级的问题。首先应用++,但是由于它是后缀,因此直到表达式末尾才进行更改。因此,将*应用于y,结果是一个左值。

如果您编写了++*y = 0;,则运算符的关联性导致*首先执行,结果*y是左值。然后,在该左值上使用++时,++的结果不是左值,因此代码无效。 ++*y本身是有效的代码,但不能是赋值的左操作数。

答案 3 :(得分:1)

假设x的地址是1000sizeof(int) = 4(对于32-bit编译器),那么当您对表达式求值时:

 *y++=*z++;

z的地址递增

(因为后递增(x ++)的优先级高于(* x))

,但在此之前右值,即z存储的地址被分配给指针y。     之后,仅进行地址增加和取消引用。

    *y++的情况类似,首先分配地址,后递增发生,然后被取消引用。如果您对左值是变量感到困惑,则没有必要例如:使用有效地址初始化指针后,在代码中添加类似代码的语句

*y++;

也是正确的,并且不会标记任何错误。