数组名称不是左值是否有原因?
Is there a reason why an array name is not an lvalue?
例如,
int x[10];
int i = 0;
x = &i; //error occurs!
根据C - A Reference Manual,数组名不能是左值。因此,x 不能是左值。但是,数组名称不能是左值的原因是什么?比如第三行为什么会出错?
数组名是 C 中不可修改的左值。:)
数组被命名为放置其元素的内存范围。因此,您不能用一个内存范围替换另一个内存范围。最初为数组声明分配的每个内存范围都有自己唯一的名称。每个数组名称都以其自己的内存范围为界。
数组是左值,但它是不可修改的左值。
这很可能与类型的兼容性有关。例如,您可以这样做:
struct ss {
char c[10];
};
...
struct ss s1 = { { "hello" } };
struct ss s2 = s1;
但不是这个:
char s1[10] = "hello";
char s2[10] = s1;
您的参考资料不正确。数组可以是左值(但不能是 modifiable 左值),而 "array name" (标识符)是 always 左值。
举个例子:
int x[10];
int i = 0;
x = &i; //error occurs!
应用 C11 6.5.1,第 2 段:
An identifier is a primary expression, provided it has been declared
as designating an object (in which case it is an lvalue) ...
我们看到 x
是一个主表达式并且是一个左值,因为它之前被声明为指定一个数组对象。
但是,C 语言规则规定,各种上下文中的数组表达式(包括赋值表达式的左侧)将转换为指向数组第一个元素的指针,而不是一个指针左值,即使数组是。具体来说:
Except when it is the operand of the sizeof operator, the _Alignof 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. If the array object has
register storage class, the behavior is undefined.
(C11 6.3.2.1 第 3 段)。
上面指定的转换结果指针不是左值,因为左值指定一个对象,没有合适的对象保存指针值;数组对象保存数组的元素,而不是指向这些元素的指针。
您在问题中使用的示例暗示您了解数组表达式衰减(转换为)指针值,但我认为您没有认识到转换后指针值和数组是两个不同的东西。指针不是左值;该数组可能是(在您的示例中,它是)。数组是否是左值实际上与您的示例无关;它是您要分配给的指针值。
如果您要问:为什么数组在赋值运算符的左侧时会衰减为指针? - 那么我怀疑有没有特别好的答案。从历史上看,C 只是不允许对数组赋值。
在许多情况下,数组名称确实会产生指针值。但是 &
运算符也是如此,您不希望它是可分配的。
int i = 42;
int *j = malloc(sizeof *j);
&i = j; /* obviously wrong */
int a[] = {1,2,3};
&a[0] = j; /* also obviously wrong */
a = j; /* same as the previous line! */
所以在学习数组和指针之间的关系时,请记住 a
通常与 &a[0]
相同,这样您就不会认为左值性是规则的例外 - 它完全遵循规则。
例如,
int x[10];
int i = 0;
x = &i; //error occurs!
根据C - A Reference Manual,数组名不能是左值。因此,x 不能是左值。但是,数组名称不能是左值的原因是什么?比如第三行为什么会出错?
数组名是 C 中不可修改的左值。:)
数组被命名为放置其元素的内存范围。因此,您不能用一个内存范围替换另一个内存范围。最初为数组声明分配的每个内存范围都有自己唯一的名称。每个数组名称都以其自己的内存范围为界。
数组是左值,但它是不可修改的左值。
这很可能与类型的兼容性有关。例如,您可以这样做:
struct ss {
char c[10];
};
...
struct ss s1 = { { "hello" } };
struct ss s2 = s1;
但不是这个:
char s1[10] = "hello";
char s2[10] = s1;
您的参考资料不正确。数组可以是左值(但不能是 modifiable 左值),而 "array name" (标识符)是 always 左值。
举个例子:
int x[10];
int i = 0;
x = &i; //error occurs!
应用 C11 6.5.1,第 2 段:
An identifier is a primary expression, provided it has been declared as designating an object (in which case it is an lvalue) ...
我们看到 x
是一个主表达式并且是一个左值,因为它之前被声明为指定一个数组对象。
但是,C 语言规则规定,各种上下文中的数组表达式(包括赋值表达式的左侧)将转换为指向数组第一个元素的指针,而不是一个指针左值,即使数组是。具体来说:
Except when it is the operand of the sizeof operator, the _Alignof 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. If the array object has register storage class, the behavior is undefined.
(C11 6.3.2.1 第 3 段)。
上面指定的转换结果指针不是左值,因为左值指定一个对象,没有合适的对象保存指针值;数组对象保存数组的元素,而不是指向这些元素的指针。
您在问题中使用的示例暗示您了解数组表达式衰减(转换为)指针值,但我认为您没有认识到转换后指针值和数组是两个不同的东西。指针不是左值;该数组可能是(在您的示例中,它是)。数组是否是左值实际上与您的示例无关;它是您要分配给的指针值。
如果您要问:为什么数组在赋值运算符的左侧时会衰减为指针? - 那么我怀疑有没有特别好的答案。从历史上看,C 只是不允许对数组赋值。
在许多情况下,数组名称确实会产生指针值。但是 &
运算符也是如此,您不希望它是可分配的。
int i = 42;
int *j = malloc(sizeof *j);
&i = j; /* obviously wrong */
int a[] = {1,2,3};
&a[0] = j; /* also obviously wrong */
a = j; /* same as the previous line! */
所以在学习数组和指针之间的关系时,请记住 a
通常与 &a[0]
相同,这样您就不会认为左值性是规则的例外 - 它完全遵循规则。