在C中,数组变量可以用作标量。例如:
char A[5];
if(A) printf("True\n");
将打印为True。鉴于:
struct S { int i; } s;
if(s) printf("True\n");
实际上无法编译,给出错误:
错误:使用了需要标量的结构类型值
这是为什么?
为什么数组变量可以用作指针而不是结构 变量
谢谢。
编辑:也许这是改写问题的更好方法 为什么C赋予A(标量)意义而不是S?
编辑:我的问题本质上更具哲学性。我试图理解为什么C的设计方式如此。为什么数组会像指针一样,但结构却不是。它们都代表连续的内存块。记忆的结构不同,但为什么要重要。
我对编译失败的原因不感兴趣,我理解(我证明它不是我)。
答案 0 :(得分:1)
为什么数组变量可以用作指针但不能用作结构变量?
数组名称转换为指向其第一个元素的指针。
...具有类型''数组类型''的表达式将转换为类型为''指向类型'的指针的表达式,指向数组对象的初始元素而不是左值。
结构不是这样。
答案 1 :(得分:1)
还有一件事:struct是一种聚合类型。指向数组第一个元素的指针是标量类型。
编辑
我认为这可能是重点:
struct是一种聚合数据类型,就像数组一样。
但是,数组具有某种规则性,而结构却没有 有。数组是一些包含某些东西的数组,都是一样的。 例如。 100个整数的数组。每个数组成员都是一个int。你可以索引 你想用任意的100个整数中的哪一个 表达。这是唯一可能的,因为所有元素都是 相同的尺寸,并按顺序排列。这种观察与此类似 数组索引是指针算术的语句 另一方面,结构是元素可以在其中的聚合 各不相同。它们是按名称引用的,没有 索引的非常量表达式的类比。
答案 2 :(得分:0)
在C
中A
的值将是指向数组第一个元素的指针。
因此if(A) printf("True\n");
表示此指针的值不是0
做某事。这是完全合法的C
(尽管指向静态数组的指针永远不会是0
)。另一方面,S
是结构的名称,if (S)
没有意义。
答案 3 :(得分:0)
命名数组的符号是指向数组第一项的常量:A
等同于&A[0]
。而且这个指针不是NULL
您使用该指针而不是int
期望的if()
表达式,因此它被转换为整数常量。指针不是NULL
,因此它变为非零整数,因此满足if()
条件并调用print
。
而你的struct
与指针相对,没有默认转换为int
,所以不能以类似的方式使用。
答案 4 :(得分:0)
如果问题是为什么当struct
类型没有时,数组表达式会衰减为指针,答案基本如下:
丹尼斯·里奇(Dennis Ritchie)将C的设计基于一种早期的语言B(go figure)。在B中,当您分配了N个元素的数组时,如
auto arr[N];
编译器将分配N + 1个单元格,其中一个单元格将绑定到标识符arr
并且将包含到数组的第一个元素的偏移量,类似于:
+---+
arr: | | ----+
+---+ |
... |
+---+ |
arr[0]: | | <---+
+---+
arr[1]: | |
+---+
arr[2]: | |
+---+
...
+---+
arr[N-1]: | |
+---+
Ritchie最初保留了这些语义,但在他将struct
类型引入语言时遇到了问题。如果他定义了像
struct foo {
int inode;
char name[14];
};
他希望struct foo
的一个实例有一个双字节int
,紧跟一个14字节的char
数组;他不希望数组指针卡在中间。最终他决定完全消除数组指针,并设计语言,以便每当它在源代码中看到数组表达式时(表达式不是sizeof
或一元&
运算符的操作数),它将将转换类型为“T
的N元素数组”转换为“指向T
的指针”,并将其计算为第一个元素的地址。因此,当您在C中分配N个元素的数组时,您将获得
+---+
arr[0]: | |
+---+
arr[1]: | |
+---+
arr[2]: | |
+---+
...
+---+
arr[N-1]: | |
+---+
没有单独的arr
对象用于将偏移量存储到第一个元素。
此转换操作对于数组是唯一的,这是为什么您可以将数组表达式用作标量(技术上,作为指针)。结构变量本身是类型的实例,而不是struct
对象向量的偏移量。
要更深入地了解C的为什么,请查看Ritchie的this essay。