Variable as array size in struct - c

I implement a file's struct in my program but for some arrays in the struct I don't know the size. The size of the array is stored in another variable but it's unknown before the struct is filled in.
struct Vertex {
float x;
float y;
float z;
};
struct myFile {
ulong nVertices;
Vertex vertices[nVertices];
};
That gives an error: "error C2065: 'nVertices' : undeclared identifier".

You should store a pointer in your struct:
Vertex *vertices;
Then allocate the memory at runtime:
myFile f;
f.vertices = malloc(nVertices * sizeof(Vertex));
if (f.vertices == 0)
handle_out_of_memory();
f.nVertices = nVertices;
Remember to free the memory when done:
free(f.vertices);

C99 introduces 'flexible array members', which may be what you want to use. Your code still ends up looking remarkably like the code suggested by #frast, but is subtly different.
§6.7.2.1 Structure and union specifiers
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.
[...]
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. With two
exceptions, the flexible array member is ignored. First, the size of the structure shall be
equal to the offset of the last element of an otherwise identical structure that replaces the
flexible array member with an array of unspecified length.106) Second, 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.
EXAMPLE Assuming that all array members are aligned the same, after the declarations:
struct s { int n; double d[]; };
struct ss { int n; double d[1]; };
the three expressions:
sizeof (struct s)
offsetof(struct s, d)
offsetof(struct ss, d)
have the same value. The structure struct s has a flexible array member d.
If sizeof (double) is 8, then after the following code is executed:
struct s *s1;
struct s *s2;
s1 = malloc(sizeof (struct s) + 64);
s2 = malloc(sizeof (struct s) + 46);
and assuming that the calls to malloc succeed, the objects pointed to by s1 and s2 behave as if the
identifiers had been declared as:
struct { int n; double d[8]; } *s1;
struct { int n; double d[5]; } *s2;
Following the further successful assignments:
s1 = malloc(sizeof (struct s) + 10);
s2 = malloc(sizeof (struct s) + 6);
they then behave as if the declarations were:
struct { int n; double d[1]; } *s1, *s2;
and:
double *dp;
dp = &(s1->d[0]); // valid
*dp = 42; // valid
dp = &(s2->d[0]); // valid
*dp = 42; // undefined behavior
The assignment:
*s1 = *s2;
only copies the member n and not any of the array elements. Similarly:
struct s t1 = { 0 }; // valid
struct s t2 = { 2 }; // valid
struct ss tt = { 1, { 4.2 }}; // valid
struct s t3 = { 1, { 4.2 }}; // invalid: there is nothing for the 4.2 to initialize
t1.n = 4; // valid
t1.d[0] = 4.2; // undefined behavior
106) The length is unspecified to allow for the fact that implementations may give array members different
alignments according to their lengths.
The example is from the C99 standard.

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);
}

Initialising values for memory after dynamic allocation?

Im aware that malloc() returns a pointer to the initialised block of memory, but initialising this memory is difficult for me.
struct state{
int one;
int two;
};
struct state *one = malloc(sizeof(struct state));
*one = (struct state){.one = 10,.two = 20};
free(one);
Im aware that the above thing can be done to initialise a bunch of values for the structure without individually accessing the fields and changing the value manually.But can anyone explain how the above code works?
Also how can I do this for a pointer to several ints. The code below doesn't seem to work:
int *pointer = (int*) {1,2,3,4,5};
can anyone explain how the above code works?
In the same way that the code below works:
int *one = malloc(sizeof(int));
*one = 1020;
free(one);
The only difference is that instead of assigning a numeric value your code assigns the value of the struct, expressed through a struct aggregate. Everything else is the same: the assignment copies the content of one region of memory into another region of memory.
Also how can i do this for a pointer to several ints?
Use memcpy, like this:
int *pointer = malloc(5*sizeof(int));
static int data[] {1, 2, 3, 4, 5};
memcpy(pointer, data, sizeof(data));
free(pointer);
But can anyone explain how the above code works?
I can explain what it means.
struct state{
int one;
int two;
};
That declares a structure type with tag state, which thereafter can be referenced via the type name struct state.
struct state *one = malloc(sizeof(struct state));
That declares one as a pointer to an object of type struct state. Supposing that the malloc() succeeds, it initializes one to point to a dynamically-allocated, uninitialized block of memory exactly the size of a struct state and aligned in a manner suitable for an object of that (or any other) type.
*one = (struct state){.one = 10,.two = 20};
The right-hand side of that expression is a compound literal of type struct state. The part inside the braces is its initialization list, exactly as you might use to initialize an ordinary variable of the same type:
struct state two = { .one = 10, .two = 20 };
The .one and .two name the member initialized by each individual initializer; they are optional in this particular case because in their absence, the initializer expressions would be matched to structure members in the order the members appear in the structure type declaration. Overall, the statement copies the value of the literal struct to the object pointed-to by one.
free(one);
That releases the dynamic memory block.
Also how can i do this for a pointer to several ints[?]
There is no such thing as a pointer to several ints. There is a pointer to one int, or a pointer to specific-size array of ints, but -- and I know I'm being pedantic here -- neither of those is "a pointer to several ints".
It looks like what you want in this case is an array, not (directly) a pointer. You can initialize an array and set its size in one declaration, like so:
int array[] = {1, 2, 3, 4, 5};
Afterward, you can use array in most respects as if it were a pointer to the first int in the array.
Note, however, that unlike structures, whole arrays cannot be assigned to. Although the above code may look like it contains an assignment, it does not -- it contains an initializer. Though the syntax is similar, initializers are not assignments. The latter are executable statements; the former are not.
(struct state){.one = 10,.two = 20}; is a compound literal. It is an object that remains valid until the end of the block scope.
*one = (struct state){.one = 10,.two = 20};
Is equivalent to
struct state temp = {.one = 10,.two = 20};
*one = temp;
In the second example, the definition of the compound literal is wrong, you must specify an array type, and then you point your pointer just like normal:
int *pointer = (int[]) {1,2,3,4,5};
Again this is equivalent to:
int temp[] = {1,2,3,4,5} ;
int *pointer = temp;
It's best to have a function (or macro if you're into those):
struct state{
int one;
int two;
};
struct state* alloc_state(int one, int two)
{
struct state s = {one, two}; // order is per struct definition!
struct state* p = malloc(sizeof(struct state));
memcpy(p, &s, sizeof(s));
return p;
}
This function will always stay 4 lines of code regardless of how many argument are used.
The same principle can be used with other types.
Macro version:
#define ALLOC_STATE(p, ...) \
{ \
struct state s = {__VA_ARGS__}; \
p = malloc(sizeof(struct state)); \
memcpy(p, &s, sizeof(s));\
}
Usage:
struct state* p;
ALLOC_STATE(p, 3, 4);

Complicated structure offsets in contiguous space

I would like to know if there is an elegant alternative to this:
struct A{
uint64_t w;
uint64_t x;
uint64_t y;
uint64_t z;
};
struct B{
uint32_t a;
uint16_t b;
};
void function(uint32_t length){
//we have one struct A at the head and multiple struct B.
struct B *ptr = malloc (length * sizeof B + sizeof A);
//we set random values in the head:
struct A * tmp = (struct A*)ptr;
tmp->w = 1000;
tmp->x = 1200;
tmp->y = 99;
tmp->z = ~(0ULL);
/*then we set the first element of type B.
*this is where my question lies
*/
// put the pointer at the right position:
tmp++;
//convert that position again:
struct B * right_position = (struct B*)tmp;
...// do things with B type.
}
Obviously, it would be simpler to have those fitted like so:
struct root{
struct A child1;
struct B *child2;
}
But my question is much more about the way to mark those offset down properly without writing the tmp++.
How could I directly access the first B element on that array without using tmp++?
Again, this is not how I would do it in real code. This is just.. kind of art we are discussing here, if you will :)
Perhaps struct B * right_position = (struct B*)((char *)ptr + sizeof(A));. The (char *) cast will make the calculation be performed in bytes.
struct A *a_ptr = malloc(sizeof(struct A) + length * sizeof(struct B));
struct B *b_ptr = (struct B *)(a_ptr + 1);
Maybe you should create a structure type with a flexible array member:
struct Both
{
struct A a;
struct B b[];
};
struct Both *c = malloc(sizeof(*c) + length * sizeof(c->b[0]));
c->a.w = 1000;
c->a.x = 1200;
c->a.y = 99;
c->a.z = ~(0ULL);
c->b[0].a = 37;
c->b[0].b = 59;
This guarantees alignment and doesn't require any casting or other chicanery. It's a part of C99 and C11 and replaces the struct hack. The standard (ISO/IEC 9899:2011) says:
§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. 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.
The standard then has paragraphs 20-25 with examples discussing aspects of the use of flexible array members.

Can one element in struct access another element of itself in 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.

Resources