结构变量的值只是一个地址(就像数组一样)?

时间:2013-02-12 21:21:28

标签: c pointers

在C中,以下是合法的:

int a[] = {27,2};
int *b;
int c;

b = a;
c = *b; /* c == 27 */

关键是a只是数组的地址,所以我可以将它分配给指针。 为什么结构不一样,我会假设结构变量的值只是地址,因此我应该能够将其分配给指针,如下所示:

struct foo bar;
struct foo *doo;
bar.x = 0;
doo = bar; //is this legal?
doo.x = 0; //why can't I use the dot?

换句话说,如果struct变量的值只是第一个组件的地址(我想这就像数组一样),上面的代码应该是合法的。

6 个答案:

答案 0 :(得分:3)

  

关键是a只是数组的地址,所以我可以将它分配给指针。

这不太正确:编译器数组的名称转换为指向数组初始元素的指针。这是自动发生的,无需演员或“地址”运算符&。但是,a 只是地址,可以通过将其大小设为sizeof(a)来证明。

这可以解释为什么struct的情况不同(即因为数组不是这样)。对于struct s,“地址”运算符&是强制性的:

doo = &bar;
  

doo.x = 0; //为什么我不能用点?

C具有通过指针访问struct元素的不同语法:您需要使用->运算符而不是点.运算符。

答案 1 :(得分:2)

正如其他人所指出的,数组的语义与结构的语义不同。至于为什么就是这种情况,你必须记住C是从早期语言(BCPLB)派生出来的,这两种语言都是“无类型”语言作为固定长度“单词”或“单元格”的线性阵列。在那些较旧的语言中,当您声明一个类似

的数组时
auto V[10]; 

预留了11个存储单元;一个用于名为V的对象,然后另外一个用于数组元素;数组的第一个元素的地址存储在V中。

来自Dennis Ritchie的论文The Development of the C Language

当我尝试扩展类型表示法时,问题变得明显,特别是添加结构化(记录)类型。结构似乎应该以直观的方式映射到机器中的内存中,但是在包含数组的结构中,没有好地方存放包含数组底部的指针,也没有任何方便的方法来安排它。初始化。例如,早期Unix系统的目录条目可能在C中描述为

struct {
    int     inumber;
    char    name[14];
};
我希望结构不仅可以表征抽象对象,还可以描述可能从目录中读取的位集合。编译器在哪里可以隐藏指向语义要求的名称的指针?即使结构被认为更抽象,并且指针的空间可能以某种方式隐藏,我如何处理在分配复杂对象时正确初始化这些指针的技术问题,也许是指定包含包含任意深度结构的数组的结构?

该解决方案构成了无类型BCPL和类型C之间的演化链中的关键跳跃。它消除了存储中指针的实现,而是在表达式中提到数组名称时导致指针的创建。在今天的C中存活的规则是,数组类型的值在表达式中出现时转换为指向构成数组的第一个对象的指针。

强调我的。这就是为什么C中的数组表达式与所有其他表达式类型(包括结构类型)的区别对待。

答案 2 :(得分:1)

  

doo = bar; //这是合法的吗?

不,试试:

doo = & bar;
     ^^
  

doo.x = 0; //为什么我不能用点?

因为doo是一个指针。尝试:

doo->x = 0;
   ^^

答案 3 :(得分:1)

不,不是。你想要做的是:

doo = &bar; 
doo->x = 0;

如果数组有效,因为T数组可以隐式转换为T*,但结构不是这种情况。指针可以存储struct objext(&bar)的地址。为了使用指针间接访问struct元素,应该使用 - >运营商。 a->b相当于(*a).b

答案 4 :(得分:1)

  doo = bar; //is this legal?

不,它无效。左操作数是结构类型,右操作数是指针类型。

这是合法的:

 doo = &bar;

&barstruct foo的指针类型。

现在:

  doo.x = 0; //why can't I use the dot?

因为操作数必须是结构类型,但它是指针类型。使用->访问指针对象到结构类型的元素。

  doo->x = 0;  // this is valid

答案 5 :(得分:1)

不,结构的值是结构本身,而不是它的地址。这允许你做这样的事情:

struct foo a;
struct foo b;
b = a;  /* this does a memberwise copy of all fields from a to b */

如果您需要结构的地址,请使用&运算符:

struct foo a;
struct foo* b = &a
struct foo c;
c = *b;  /* this does a memberwise copy of all fields from a to c */