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

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?

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;

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.

First of all, the member num is not declared until the end of the struct definition, which ends at the last }.
Second, how would it make sense to set the array size to be the value of an uninitialized variable?
What I think you attempt to do with int B[max] is to create a variable length array (VLA). But that won't work either, as they are explicitly forbidden inside structs. 6.7.2.1/9:
A member of a structure or union may have any complete object type other than a
variably modified type.
What you could do instead is to declare a flexible array member, as demonstrated in the answer by Ouah.

The reason the compiler complains when you "flexibly declare" the array in the struct in global memory, is because global memory can only be allocated (declared) at compile-time and at compile time all sizes must be known. (The value of a variable is not known at compile time by definition.)
The reason it accepts a flexible array in a function, is because the function's local variables are created at the moment the function is entered and then the compiler can accept a variable size. (It boils down to the compiler allocating more memory on the stack and offsetting all accesses to local variables with the size - but different compilers could have a different approach.)
#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
....
}
The following would be legal:
#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.: I am not a C99 programmer; I may have some mistakes here.

Related

"Inheritance" in C's structs?

Here I'm a bit confused about this code:
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
struct test_struct {
uint8_t f;
uint8_t weird[];
};
int main(void) {
struct {
struct test_struct tst;
uint8_t weird[256];
} test_in = {};
printf("%u\n", test_in.weird[0]); // 0
test_in.tst.weird[0] = 1;
printf("%u\n", test_in.weird[0]); // 1
return 0;
}
I didn't know that it is possible to use struct's fields this way, so I have two questions:
How is it called in C?
And, of course, how does it work? (Why weird field was changed when I don't change it directly, I thought these are two different fields?)
Here I'm a bit confused about this code:
The short answer is: the code has undefined behavior.
How is it called in C? How does it work?
struct test_struct is defined with its last member as an array of unspecified length: uint8_t weird[]; This member is called a flexible array member, not to be confused with a variable length array.
6.7.2 Type specifiers
[...]
20     As a special case, the last member of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. In most situations, the flexible array member is ignored. In particular, the size of the structure is as if the flexible array member were omitted except that it may have more trailing padding than the omission would imply. However, when a . (or ->) operator has a left operand that is (a pointer to) a structure with a flexible array member and the right operand names that member, it behaves as if that member were replaced with the longest array (with the same element type) that would not make the structure larger than the object being accessed; the offset of the array shall remain that of the flexible array member, even if this would differ from that of the replacement array. If this array would have no elements, it behaves as if it had one element but the behavior is undefined if any attempt is made to access that element or to generate a pointer one past it.
if you allocate such a structure from the heap with extra space for array elements, these elements can be accessed via the weird member up to the number of elements thus allocated.
The C Standard mandates that such a structure can only be defined as a member of another structure or union if it appears as the last member of said aggregate. In the posted code, the programmer violates this constraint, so accessing elements of test_in.tst.weird has undefined behavior, and so does accessing elements of test_in.weird.
The programmer also assumes that the test_in.tst.weird array and the test_in.weird array overlap exactly, which may be the case but is not guaranteed, nor supported: code relying on this type of aliasing has undefined behavior as well.
In your example, assuming the compiler accepts the empty initializer {} (part of the next C Standard and borrowed from C++), it seems to work as expected, but this is not guaranteed and alignment issues may cause it to fail as shown in the modified version below:
#include <stdint.h>
#include <stdio.h>
struct test_struct {
uint8_t f;
uint8_t weird[];
};
struct test_struct1 {
int x;
uint8_t f;
uint8_t weird[];
};
int main(void) {
struct {
struct test_struct tst;
uint8_t weird[256];
} test_in = {};
struct {
struct test_struct1 tst;
uint8_t weird[256];
} test_in1 = {};
printf("modifying test_in.weird[0]:\n");
printf("%u\n", test_in.weird[0]); // 0
test_in.tst.weird[0] = 1;
printf("%u\n", test_in.weird[0]); // 1
printf("modifying test_in1.weird[0]:\n");
printf("%u\n", test_in1.weird[0]); // 0
test_in1.tst.weird[0] = 1;
printf("%u\n", test_in1.weird[0]); // 0?
return 0;
}
Output:
chqrlie$ make 220930-flexible.run
clang -O3 -std=c11 -Weverything -o 220930-flexible 220930-flexible.c
220930-flexible.c:17:28: warning: field 'tst' with variable sized type 'struct test_struct' not at
the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
struct test_struct tst;
^
220930-flexible.c:19:17: warning: use of GNU empty initializer extension [-Wgnu-empty-initializer]
} test_in = {};
^
220930-flexible.c:22:29: warning: field 'tst' with variable sized type 'struct test_struct1' not
at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
struct test_struct1 tst;
^
220930-flexible.c:24:18: warning: use of GNU empty initializer extension [-Wgnu-empty-initializer]
} test_in1 = {};
^
4 warnings generated.
modifying test_in.weird[0]:
0
1
modifying test_in1.weird[0]:
0
0
struct test_struct {
uint8_t f;
uint8_t weird[];
};
int main(void) {
struct {
struct test_struct tst;
uint8_t weird[256];
} test_in = {};
Effectively, before there were FAM's in the language, what you've declared is:
int main(void) {
struct {
struct { uint8_t f; } tst;
union {
uint8_t weird0[1]; // any non-zero size up to 256
uint8_t weird1[256];
} overlay;
} test_in = {};
On the contrary as described in the comments section above, a declaration like
int array[];
is not a Variable Length Array, it's either called Arrays of unknown size (cppreference) or Arrays of Length Zero (gcc).
An example of a VLA would be:
void foo(size_t n)
{
int array[n]; //n is not available at compile time
}
Based on the comment below (from the cppreference - see provided link):
Within a struct definition, an array of unknown size may appear as the last member (as long as there is at least one other named member), in which case it is a special case known as flexible array member. See struct (section Explanation) for details:
struct s { int n; double d[]; }; // s.d is a flexible array member
struct s *s1 = malloc(sizeof (struct s) + (sizeof (double) * 8)); // as if d was double d[8]
The provided code is just invalid.
You declared a structure with a flexible array member
struct test_struct {
uint8_t f;
uint8_t weird[];
};
From the C Standard (6.7.2.1 Structure and union specifiers)
18 As a special case, the last element of a structure with more than
one named member may have an incomplete array type; this is called a
flexible array member.
As it is seen from the quote such a member must be the last element of a structure. So the above structure declaration is correct.
However then in main you declared another unnamed structure
int main(void) {
struct {
struct test_struct tst;
uint8_t weird[256];
} test_in = {};
//...
that contains as member an element of the structure with the flexible array element that now is not the last element of the unnamed structure. So such a declaration is invalid.
Secondly, you are using empty braces to initialize an object of the unnamed structure. Opposite to C++ in C you may not use empty braces to initialize objects.

How do we create an array of structure, which has the flexible array as its last field?

Let's say we have:
struct A {
int i;
char c[1];
};
Usually I would use malloc() to create an instance of A, like:
#define LEN 10
struct A *my_A = malloc(sizeof(A) + LEN * sizeof(char));
But this would not work if I try to create an array of A
A struct with a flexible array member cannot be a member of an array. This is explicitly stated in section 6.7.2.1p3 of the C standard:
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.
What you would need to do instead is declare the struct with a pointer instead of a flexible array member, and allocate space for each instance.
For example:
struct A {
int i;
char *c;
};
struct A arr[100];
for (int i=0; i<100; i++) {
arr[i].c = malloc(LEN);
}
We don't.
One of the key characteristics of an array is that you know the offset between one element and the next, and you can't do that if the elements are variably-sized.
What you can create is an array of pointers to your flexibly-sized type. How each of the pointed-to objects is allocated is up to you.
It is possible to do what you have shown in your code just using a custom allocation / array iteration mechanism (you won't be able to use the default [] operator, though, because it determines the offset based on the size of the member), but I think that you don't want to do that.
In C/C++, a "flexible" array is just a pointer to an allocated piece of memory in the heap. What you would want to do in this case is this:
struct A {
int i;
char* c; // A pointer to an array
};
#define LEN 10
#define FLEX_ARRAY_LEN 20
struct A* my_A = malloc(sizeof(A) * LEN);
// initialize each array member
for (int i = 0; i < LEN; ++i) {
// allocating new memory chunk for the flexible array of ith member
my_A[i].c = malloc(sizeof(char) * FLEX_ARRAY_LEN);
}

Is there a way to initialize an array of strings in a struct when you don't know how many elements you will put in the string?

I have this struct:
typedef struct SomeStruct {
char someString[];
} SomeStruct;
This produces an error since someString's size is not defined when initialized.
I want to make someString an array of strings, but I will not know the size of the array at the time of initialization. (The elements that will be in the array will depend on user input later in the program).
Is it possible to initialize this as an array of strings without knowing the size of the array?
Yes, the C standard talks about this in 7.2.18-26. What you are describing is known as a flexible array member of a struct. From the standard:
As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member.
Essentially what it is saying is, if the last member of the struct is an array of undefined size (as might be the case for runtime sizes), then when using the struct, you would allocate the appropriate size of your struct including how large you want the string to be. For example:
typedef struct SomeStruct {
char someString[];
} SomeStruct;
has the flexible array member someString. A common way to use this is:
SomeStruct *p = malloc(sizeof (SomeStruct) + str_size);
Assuming that the call to malloc succeeds, the object pointed to by p behaves, for most purposes, as if p had been declared as:
struct {char someString[str_size]; } *p;
Read the standard for more detail. The buzzword flexible array member will show up a lot of information too. The wikipedia is a good place to start.
You can use a structure with flexible array. For example
typedef struct SomeStruct
{
size_t n;
char someString[];
} SomeStruct;
where n is used to store the number of elements in the array.
Then you can create objects of the structure the following way
SomeStruct *s = malloc( sizeof( SomeStruct ) + 10 * sizeof( char[100] ) );
s->n = 10;
If you can't use a dynamic array (it sounds like this, if you get a compile error for it), you can actually overrun the array, as long as it's at the end of the struct, and as long as you can actually access that memory. Example:
#include <stdio.h>
#include <stdlib.h>
typedef struct SomeStruct {
char someString[10];
} SomeStruct;
int main (void)
{
// Allocate 4x space, so we have room to overrun
SomeStruct *p = malloc(sizeof(SomeStruct) * 4);
p->someString[38] = 'a';
printf("%c\n", p->someString[38]);
}
Of course, you still have to actually allocate the space, so it may not be so useful to you depending on your case.

Limitations in "struct inside struct"

There are 2 struct definitions A and A. I know that there is OK to struct A contain a POINTER to struct A but I don't understand why struct A cannot contains struct A (not a pointer)
Because when you put structs inside each other, you're putting another copy of that struct into the struct at that point. For example:
struct A {
int q;
int w;
};
struct B {
int x;
struct A y;
int z;
};
This will be laid out in memory like this:
int /*B.*/x;
int /*A.*/q;
int /*A.*/w;
int /*B.*/z;
But if you try to put a struct inside itself:
struct A {
int x;
struct A y;
};
you have an A, which contains an int and another A, which contains an int and another A, and now you have an infinite number of ints.
Because in that case, it will take infinite storage as it will have to recursively store the data member of its own type. So, it is not possible. Whereas, Size of a pointer is fixed and hence causes no problem.
Let's suppose it could contain an object of its own type:
struct A_
{
A_ a;
int b;
} A;
What's sizeof(A) ? Answer: sizeof(A)+sizeof(int): impossible.
Because the structure definition is not finished until the closing curly-brace }. To declare a structure member the compiler need the full definition, as it uses that information to calculate things like space and padding and alignment etc. For a pointer to something the size of the pointer is the size of the pointer, and all the compiler needs os the name of the type, not its full definition.
Lets take a simple structure for example:
struct A // Here the compiler knows that there is a structure named A
// The compiler does not know its contents, nor its size
{
// Some members...
struct A *pointer_to_a; // All the compiler needs to know is the symbol A
// The size and alignment is that of a pointer
// and those are known by the compiler
// Some more members...
// struct A instance_of_A; // This is not possible! At this point the
// compiler doesn't have the full definition
// of the structure, and can therefore not
// know how much space it need to allocate
// for the member
// Some even more members...
}
// Now the compiler knows the full contents of the structure, its size
// and alignment requirements
;

Char with a variable length

Is it possible to define a char with a variable length?
I have a char "name" (member of a struct named "person") with a length of 25 but I want it to be a variable length between the values 1 and 25, because I want to generate random strings of that char with different sizes and not always with the same length (25). One of the parameters of the method is sizeof(n.name).
Note: n is a struct (struct person n).
The struct "person" is defined this way:
struct person{
int c;
char name[25];
};
Anyone?
struct person{
int c;
char name[]; /* Variable length array */
};
I think this should serve your purpose.
Else you can have dynamic memory allocation using
char *name;
name is a pointer and memory should be allocated and it can be done using malloc()
You can use a flexible array. It must be the last data member of a structure.
struct person{
int c;
char name[];
};
The memory for a structure with a flexible array has to be allocated dynamically.
From the C Standard (6.7.2.1 Structure and union specifiers)
the flexible array member is ignored. In particular, the size of the
structure is as if the flexible array member were omitted except that
it may have more trailing padding than the omission would imply. Howev
er, when a . (or ->) operator has a left operand that is (a pointer
to) a structure with a flexible array member and the right operand
names that member, it behaves as if that member were replaced with the
longest array (with the same element type) that would not make the
structure larger than the object being accessed; the offset of the
array shall remain that of the flexible array member, even if this
would differ from that of the replacement array. If this array would
have no elements, it behaves as if it had one element but the behavior
is undefined if any attempt is made to access that element or to
generate a pointer one past it.
And there is an example of its using
20 EXAMPLE 2 After the declaration:
struct s { int n; double d[]; };
the structure struct s has a flexible array member d. A typical way to use this is:
int m = /* some value */;
struct s *p = malloc(sizeof (struct s) + sizeof (double [m]));
and assuming that the call to malloc succeeds, the object pointed to by p behaves, for most purposes, as if
p had been declared as:
struct { int n; double d[m]; } *p;
(there are circumstances in which this equivalence is broken; in particular, the offsets of member d might
not be the same).
Or you could declare a pointer to char and dynamically allocate only the array itself
struct person{
int c;
char *name;
};
char[25] lets you store C strings of length between zero and 24, inclusive (one character is needed for '\0' terminator).
You can use one of two solutions:
Use a flexible array member, or
Use a pointer.
The first solution lets you keep the name together with the rest of the struct, but you would not be able to make arrays of these structs:
struct person{
int c;
char name[];
};
See this Q&A for more information on flexible array members. You need a compiler compatible with C99 to use flexible array members.
The second solution takes slightly more memory, but the size of your struct does not change, making it possible to use it in an array:
struct person{
int c;
char *name;
};
A better way to do this is to use the strings library and declare the variable 'name' of type string.
#include<string>
struct person{
int c;
string name;
};

Resources