Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can one element in struct access another element of itself in C?

Tags:

c

pointers

struct

I want to declare a int num in struct S. Then the same struct should also have a array B of size num(So B will access num from it's own struct).

while in a function, I can do,

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

same won't work for struct as such,

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

Is there any way I can do this?

like image 896
Registered User Avatar asked Sep 04 '15 14:09

Registered User


People also ask

Can a struct have itself as a member?

Although a structure cannot contain an instance of its own type, it can can contain a pointer to another structure of its own type, or even to itself. This is because a pointer to a structure is not itself a structure, but merely a variable that holds the address of a structure.

Can we assign one structure variable to another in C?

In C/C++, we can assign a struct (or class in C++ only) variable to another variable of same type. When we assign a struct variable to another, all members of the variable are copied to the other struct variable.

Can you set one struct equal to another?

Yes, you can assign one instance of a struct to another using a simple assignment statement. In the case of non-pointer or non pointer containing struct members, assignment means copy. In the case of pointer struct members, assignment means pointer will point to the same address of the other pointer.

Can you equate structures in C?

In C, the only operation that can be applied to struct variables is assignment. Any other operation (e.g. equality check) is not allowed on struct variables.


2 Answers

Use a flexible array member:

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

int x = 42; 

struct S *p = malloc(sizeof (struct S) + sizeof (int [x]));
p->num = x;
like image 178
ouah Avatar answered Sep 21 '22 23:09

ouah


There are several problems with

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

that cause it to not work the way you want to.

The first is that the num being used in the array member declaration isn't the same num that's the member of the struct type; the compiler treats the num in the array declaration as a regular identifier (i.e., it assumes there's a different variable named num in the same scope as the struct declaration)1.

The second problem is that a struct or union type may not have a variable-length array as a member2. However, the last member in the struct may have an incomplete array type:

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

Unfortunately, you're still kind of stuck here; if you create an instance of struct S like

struct S foo;

it doesn't actually allocate any space for the array. You'd need to allocate the struct dynamically:

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

to allocate space for the array itself. Note that you cannot declare an array of struct S or use it as a member of another structure or union type if the last member has an incomplete array type. 3

Honestly, your best option is to define the struct as

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

and then allocate the memory for data as a separate operation from allocating memory for the struct object itself:

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

Since struct S now has a known size, you can declare arrays of it, and you can use it as a member of another struct or union type:

struct S blah[10];

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


1. C supports four different name spaces - label names (disambiguated by label syntax), struct/union/enum tag names (disambiguated by the presence of the struct, union, or enum keyword), struct and union member names (disambiguated by the . and -> component selection operators), and everything else. Since the num in your array declaration is not an operand of . or ->, the compiler treats it as a regular variable name.

2. 6.7.2.1/9: "A member of a structure or union may have any complete object type other than a variably modified type."

2. 6.2.7.1/3: A structure or union shall not contain a member with incomplete or function type (hence, a structure shall not contain an instance of itself, but may contain a pointer to an instance of itself), except that the last member of a structure with more than one named member may have incomplete array type; such a structure (and any union containing, possibly recursively, a member that is such a structure) shall not be a member of a structure or an element of an array.
like image 27
John Bode Avatar answered Sep 22 '22 23:09

John Bode