【问题标题】:Can one element in struct access another element of itself in C?struct 中的一个元素可以访问 C 中自身的另一个元素吗?
【发布时间】:2015-09-04 14:01:01
【问题描述】:

我想在结构 S 中声明一个 int num。那么同一个结构也应该有一个大小为 num 的数组 B(所以B 将从它自己的结构中访问num)。

在函数中,我可以做到,

func(int A)
{
    int max=A; //I could use A directly, I am just trying to explain my plan.
    int B[max];
}

同样不适用于结构体,

struct S {
    int num;
    int data[num]; //this is wrong, num is undeclared
};

有什么办法可以做到吗?

【问题讨论】:

  • 对象不能访问 C 中的其他对象。这不是 OOP。但是您不是“访问”一个对象,而是使用可变数组大小的值。使用 灵活的数组成员 并将其大小存储在 'max' 中(尽管我将其称为 length 或类似名称)..
  • 结构不能是动态的,它将是固定值..
  • 即使在结构之外,像int data[num]; 这样的声明并不意味着data 会在您更改num 时改变大小...这意味着data 将具有一个固定大小,具体取决于num 的值是在声明data

标签: c pointers struct


【解决方案1】:

使用灵活的数组成员:

struct S {
    int num;
    int data[];
};

int x = 42; 

struct S *p = malloc(sizeof (struct S) + sizeof (int [x]));
p->num = x;

【讨论】:

  • 如果num是数组的长度,最好使用那个名字。它的类型应该是size_t
  • @Olaf 我正在重用 OP 使用的成员名称,如果 int 对于 OP 值足够宽,则不需要 numsize_t
【解决方案2】:

有几个问题

struct S {
    int num;
    int data[num]; 
};

这会导致它无法按您想要的方式工作。

首先是数组成员声明中使用的num 与结构类型的成员num 不同;编译器将数组声明中的 num 视为常规标识符(ie,它假定在与 struct 声明相同的范围内有一个名为 num 的不同变量)1

第二个问题是structunion 类型可能没有可变长度数组作为成员2。但是,结构中的最后一个成员可能具有 incomplete 数组类型:

struct S {
    int num;
    int data[]; 
};

不幸的是,您仍然有点卡在这里;如果您创建struct S 的实例,就像

struct S foo;

它实际上并没有为数组分配任何空间。您需要动态分配结构:

/**
 * Note that sizeof doesn't try to actually dereference foo below
 */
struct S *foo = malloc( sizeof *foo + N * sizeof *foo->arr );

为数组本身分配空间。请注意,如果最后一个成员的数组类型不完整,则不能声明 struct S 数组或将其用作另一个结构或联合类型的成员。 3

老实说,您最好的选择是将结构定义为

struct S {
  size_t num;
  int *data;
};

然后为 data 分配内存作为与为结构对象本身分配内存的单独操作:

struct S foo;
foo.num = some_value();
foo.data = malloc( sizeof *foo.data * foo.num );

由于struct S 现在具有已知大小,您可以声明它的数组,并且可以将其用作另一个结构或联合类型的成员:

struct S blah[10];

struct T {
  struct S s;
  ...
};


1。 C 支持四种不同的名称空间 - 标签名称(通过标签语法消除歧义)、struct/union/enum 标记名称(通过存在 structunionenum 关键字消除歧义) 、structunion 成员名称(由 .-> 组件选择运算符消除歧义),以及其他所有内容。由于数组声明中的 num 不是 .-> 的操作数,因此编译器会将其视为常规变量名。

2. 6.7.2.1/9:“结构或联合的成员可以具有除可变修改类型之外的任何完整对象类型。”

2. 6.2.7.1/3:结构或联合不应包含不完整或函数类型的成员(因此, 结构不应包含自身的实例,但可以包含指向实例的指针 本身),除了具有多个命名成员的结构的最后一个成员 可能有不完整的数组类型;这样的结构(以及任何包含,可能 递归地,作为这种结构的成员)不应是结构的成员或 数组的元素。

【讨论】:

    【解决方案3】:

    首先,成员num直到结构定义结束时才被声明,该结构定义在最后一个}结束。

    其次,将数组大小设置为未初始化变量的值有什么意义?

    我认为您尝试使用 int B[max] 做的是创建一个可变长度数组 (VLA)。但这也行不通,因为它们在结构中被明确禁止。 6.7.2.1/9:

    结构或联合的成员可以具有任何完整的对象类型,而不是 可变修饰类型。

    您可以做的是声明一个灵活的数组成员,如 Ouah 的回答所示。

    【讨论】:

      【解决方案4】:

      当您在全局内存中“灵活地声明”结构中的数组时,编译器抱怨的原因是,全局内存只能在编译时分配(声明),并且在编译时必须知道所有大小。 (根据定义,在编译时变量的值是未知的。)

      它在函数中接受灵活数组的原因是因为函数的局部变量是在输入函数的那一刻创建的,然后编译器可以接受可变大小。 (归结为编译器在堆栈上分配更多内存并使用大小偏移对局部变量的所有访问 - 但不同的编译器可能有不同的方法。)

      #include <stdio.h>
      int size;
      struct S {
          int num;
          int a[size];    // illegal: size must be known at compile time
      };
      
      int f(int size)
      {
          int a[size];   // legal as a is allocated on the stack
          ....
      }
      

      以下是合法的:

      #include <stdio.h>
      #define A_SIZE 10
      struct S {
          int num;
          int a[A_SIZE];    // legal: A_SIZE is known at compile time
      };
      

      P.s.:我不是 C99 程序员;我这里可能有一些错误。

      【讨论】:

      • OP 的 struct 没有定义对象。这只是struct 类型定义。但是,语法是不可能的,但[]灵活的数组成员)是允许的。
      • 但是当我创建 struct 变量时,我会提供 num 为 struct S={10};。那它不应该工作吗?
      • 我不明白你的语法,或者它是一个初始化器,但它没有足够的字段来初始化 S。所以不,它不会工作。但是你可以使用一个常量——我会更新我的帖子给你看。
      • 我的意思是我会将它初始化为struct S={var};。我以 10 为例,实际上该值将由用户输入。我想我只能从 struct 中初始化几个元素。我错了吗?
      • 代码无法编译的原因有很多。说这只是因为num 不是编译时常量是不正确的。编译器报错num没有定义,那是因为引用num时struct定义还没有完成。
      猜你喜欢
      • 1970-01-01
      • 2018-06-17
      • 2023-03-15
      • 2021-08-02
      • 1970-01-01
      • 1970-01-01
      • 2019-01-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多