[英]Pointers with increment and decrement operators
通常,當賦值運算符存在時,左操作數應該是變量而不是表達式,但是當我使用指針使左側成為表達式時,代碼不會產生任何錯誤。
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;
}
賦值的左操作數不必是變量。 例如,以下分配應該並且確實可以很好地工作(我假設您知道這一點,並且只是弄錯了):
array[index] = value;
*ptr = value;
我認為*y++ = *z++;
讓您感到困惑*y++ = *z++;
是您認為它是分配給增量操作的結果,的確沒有任何意義。 但這不是該表達式的優先級: *y++
等效於*(y++)
,而不是(*y)++
。 因此,您要取消引用y++
的結果,然后將一個值分配給該已取消引用的內存位置,就像您編寫了一樣:
int *ptr = y++;
*ptr = *z++;
通常,當賦值運算符存在時,左操作數應為變量而不是表達式...
賦值運算符的左操作數始終是一個表達式。 限制是它必須是lvalue ,它是(簡化一點)指定對象的表達式。
左值的最簡單情況是聲明的對象/變量的名稱,例如:
int n;
n = 42;
n
是一個表達式,特別是一個左值,它指定名為n
的對象。
在您的示例中,您具有:
*y++ = *z++;
運算符優先級表示++
運算符比*
運算符綁定更緊密,因此等效於:
*(y++) = *(z++);
y++
和z++
不是值-它們是產生指針值的表達式,但它們不指定任何對象。 但是,即使其操作數不是左值,一元*
運算符也會為您提供左值。 y++
產生一個指針值, *(y++)
為您提供該指針指向的對象。
在這種意義上,C標准不使用術語“變量”。 它討論對象 ,可以使用簡單名稱聲明對象,也可以不使用簡單名稱聲明對象。 an_object
, *pointer_value
, array[index]
和structure_object.member
均引用對象,並且可以出現在分配的左側。
左操作數應該是一個變量而不是一個表達
這是一個誤會。 您正在尋找的期限為左值 。 這是源自術語“左側值”的C標准亂碼。 左值的定義大致是:一個指定對象的表達式。
這里討論的各種運營商的規則是:
*
運算符的結果被定義為始終為左值,因此您可以將其用作對象,然后將其賦值。 例子:
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
本身是有效的代碼,但不能是賦值的左操作數。
假設x
地址為1000
並且sizeof(int) = 4
(對於32-bit
編譯器),則在計算表達式時:
*y++=*z++;
z的地址遞增
(因為,后遞增(x ++)的優先級高於(* x))
但在該右值之前,即由z
存儲的地址分配給指針y
。 之后,僅進行地址增加和取消引用。
*y++
的情況類似,第一個地址被分配,后遞增發生,然后被取消引用。 如果您對左值是變量感到困惑,則沒有必要,例如:用有效地址初始化指針后,在代碼中添加一條語句
*y++;
也是正確的,不會標記任何錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.