initializing a struct array with array inside - c

So I made a struct with a with an uninitialized array inside but the outer struct is an array that is initialized. I then loop through and print the values but I'm not getting anything. NUM is already defined as 12.
#include "header.h"
#include <stdio.h>
#include <stdlib.h>
void make() {
struct suit {
char *type;
int people[];
} deck[4] = {"Hunter", NUM,
"Fighter", NUM,
"Jumper", NUM,
"Strider", NUM};
};
//print type and numbers 1-12
for (int i = 0; i < 4; i++) {
for (int j = 0; j < NUM; i++) {
printf(deck[i].type);
printf(deck[i].people[j]);
}
}
}

Allocate the memory of int people[]; array, So, your struct should look like this, since it is an object definition:
struct suit {
char *type;
int people[10]; //compile time allocation
} deck[4] = {"Hunter", NUM,
"Fighter", NUM,
"Jumper", NUM,
"Strider", NUM};

people is a flexible array member and Standard C does not allow initialization of flexible array member. Though, GCC allows static initialization of flexible array as an extension. So,
struct suit {
char *type;
int people[];
} deck = {"Hunter", NUM};
is valid snippet as per GCC, but at the same time GCC doesn't allow nested array initialization when flexible array member is involved and therefore the initializer for deck[4] is not valid.
Of course, this extension only makes sense if the extra data comes at the end of a top-level object, as otherwise we would be overwriting data at subsequent offsets. To avoid undue complication and confusion with initialization of deeply nested arrays, we simply disallow any non-empty initialization except when the structure is the top-level object. For example:
struct foo { int x; int y[]; };
struct bar { struct foo z; };
struct foo a = { 1, { 2, 3, 4 } }; // Valid.
struct bar b = { { 1, { 2, 3, 4 } } }; // Invalid.
struct bar c = { { 1, { } } }; // Valid.
struct foo d[1] = { { 1, { 2, 3, 4 } } }; // Invalid.
Also note that you should use appropriate format specifiers in printf for different data types.

Related

Struct array typedef in struct shows incomplete data

I'm having trouble with a piece of code where a typedef array is created of a struct. That typedef is then used in another struct.
When receiving the typedef in a function and initialising the struct with the typedef in it, I only get data of the first element in the array.
Below I have a simplified example of what I'm getting at the moment.
struct simple_struct {
double a;
};
typedef struct simple_struct arr_typedef[2];
struct struct_with_typedef {
const arr_typedef typedef_arr;
};
void foo(const arr_typedef arg_s) {
struct struct_with_typedef test = {
*arg_s
};
int i;
for (i = 0; i < 2; i++) {
printf("value: %f \n", test.typedef_arr[i].a);
}
}
int main(int argc, char* argv[]) {
arr_typedef d_test = { {1}, {2} };
foo(d_test);
return 1;
}
When compiled, using gcc 4.4, and run I see the following output:
~/public > ./test
value: 1.000000
value: 0.000000
Would someone be able to explain why the value of the second item isn't available?
If I leave out the dereference I get the following error whilst compiling, which I also don't get:
test.c:82: error: incompatible types when initializing type 'double' using type 'const struct simple_struct *'
I have removed the typedef and the same result persists. Sort of understand that indeed that one initialiser value is given. But there is only one member in the struct, or are they expanded in the background?
If so, how would you initialise both values?
struct simple_struct {
double a;
};
struct struct_with_arr {
const struct simple_struct struct_arr[2];
};
void foo(const struct simple_struct arg_s[2]) {
struct struct_with_arr test = {{*arg_s}};
int i;
for (i = 0; i < 2; i++) {
printf("value: %f \n", test.struct_arr[i].a);
}
}
int main(int argc, char* argv[]) {
struct simple_struct d_test[2] = { {1}, {2} };
foo(d_test);
return 1;
}
In this declaration
struct struct_with_typedef test = {
*arg_s
};
there is used an object of the type struct simple_struct to initialize an array of the type const arr_typedef.
Firstly you need to enclose the initializer in braces and add an initializer for the second element of the array if you want to do so.
A correct way to initialize the array is the following
#include <stdio.h>
struct simple_struct
{
double a;
};
typedef struct simple_struct arr_typedef[2];
struct struct_with_typedef
{
const arr_typedef typedef_arr;
};
void foo( const arr_typedef arg_s )
{
struct struct_with_typedef test =
{
{ arg_s[0], arg_s[1] }
};
for ( int i = 0; i < 2; i++ )
{
printf("value: %f \n", test.typedef_arr[i].a);
}
}
int main( void )
{
arr_typedef d_test = { {1}, {2} };
foo(d_test);
return 0;
}
The program output is
value: 1.000000
value: 2.000000
You can write the initializers also the following way
struct struct_with_typedef test =
{
{ *arg_s, *( arg_s + 1 ) }
};
Take into account that an array designator used as an initializer expression is implicitly converted to pointer to its first element. Dereferencing the pointer you get the first element itself.
There is no syntax in C for initializing an array with a single initializer representing another array to copy values from.
To fix your code you could do one of these options:
List the members: struct struct_with_arr test = {{arg_s[0], arg_s[1]}};
Change the function to accept struct struct_with_arr as the parameter type, in which case you can use struct struct_with_arr test = arg;
Copy without an initializer: struct struct_with_arr test; memcpy(&test.struct_arr, arg_s, sizeof test.struct_arr);. (Actually you can't use this option since you have defined the struct element as const ... not really a great idea in the first place in my opinion)
For completeness I will mention the code:
struct struct_with_arr foo = *(struct struct_with_arr *)arg_s;
This is one of those things that is technically undefined behaviour (if the argument source was not actually a struct_with_arr) but is likely to work on any actual compiler that exists. My advice would be to not do this.

Assign value to field in array of nested structs

I have a function test that accepts a pointer to a structure. How can I set the value of a field in a structure in the nested structure array? The structures are created and deleted elsewhere, I just want to set the value.
typedef struct {
int a;
} inner_struct_t;
typedef struct {
int b;
inner_struct_t innerStructsArr[];
} outer_struct_t;
void test(outer_struct_t *outerStruct);
void test(outer_struct_t *outerStruct) {
outerStruct->b = 123; // set a value in the outer struct
(outerStruct->innerStructsArr)[0].a = 456; // but this DOESN'T work
}
Here's a complete example that should work for you:
#include <stdio.h>
#include <malloc.h>
typedef struct {
int a;
} inner_struct_t;
typedef struct {
int b;
inner_struct_t *innerStructsArr;
} outer_struct_t;
void test(outer_struct_t *outerStruct, int n) {
outerStruct->b = 123; // set a value in the outer struct
outerStruct->innerStructsArr = malloc(sizeof(inner_struct_t) * n); // Allocate space
outerStruct->innerStructsArr[0].a = 456; // Assign a value
}
int main (int argc, char *argv[]) {
outer_struct_t s;
test(&s, 1);
printf("b=%d, inner[0]=%d\n", s.b, s.innerStructsArr[0].a);
free(s.innerStructsArr);
return 0;
}
When you have a structure with a flexible array member (FAM) in it, you need to allocate the space for the array at the same time that you allocate the space for the structure.
ISO/IEC 9899:2011 §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.
Given:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int a;
} inner_struct_t;
typedef struct
{
int b;
inner_struct_t innerStructsArr[];
} outer_struct_t;
static void test(outer_struct_t *outerStruct)
{
outerStruct->b = 123;
outerStruct->innerStructsArr[0].a = 456;
}
int main(void)
{
outer_struct_t *os = malloc(sizeof(*os) + 4 * sizeof(os->innerStructsArr[0]));
for (int i = 0; i < 4; i++)
os->innerStructsArr[i].a = 10 * i;
test(os);
printf(" b = %d\n", os->b);
for (int i = 0; i < 4; i++)
printf("[%d].a = %d\n", i, os->innerStructsArr[i].a);
free(os);
return 0;
}
Sample output:
b = 123
[0].a = 456
[1].a = 10
[2].a = 20
[3].a = 30

qSort a Struct using Typedef with Casts, which totally confuses me

Here's the code: http://support.microsoft.com/kb/73853
/* Compile options needed: none
*
* This example program uses the C run-time library function qsort()
* to sort an array of structures.
*/
#include <stdio.h>
#include <stdlib.h>
typedef int (*compfn)(const void*, const void*);
struct animal { int number;
char name[15];
};
struct animal array[10] = { { 1, "Anaconda" },
{ 5, "Elephant" },
{ 8, "Hummingbird" },
{ 4, "Dalmatian" },
{ 3, "Canary" },
{ 9, "Llama" },
{ 2, "Buffalo" },
{ 6, "Flatfish" },
{ 10, "Zebra" },
{ 7, "Giraffe" } };
void printarray(void);
int compare(struct animal *, struct animal *);
void main(void)
{
printf("List before sorting:\n");
printarray();
qsort((void *) &array, // Beginning address of array
10, // Number of elements in array
sizeof(struct animal), // Size of each element
(compfn)compare ); // Pointer to compare function
printf("\nList after sorting:\n");
printarray();
}
int compare(struct animal *elem1, struct animal *elem2)
{
if ( elem1->number < elem2->number)
return -1;
else if (elem1->number > elem2->number)
return 1;
else
return 0;
}
void printarray(void)
{
int i;
for (i = 0; i < 10; i++)
printf("%d: Number %d is a %s\n",
i+1, array[i].number, array[i].name);
}
I don't understand the way this typedef with casts work. We have "typedef int" and the part "(compfn)(const void, const void*)" is what I really don't understand.
And shouldn't (compfn)compare be compare(compfn)? Why exactly doesn't the function compare have any parameters infront of it?
I checked wiki, the only examples were in C++ and I am going to start C++ after C. Didn't find much here either.
Thanks in advance.
Edit: I see you guys aren't much active, I will get some sleep and try to understand it tomorrow. I might make a tutorial after.
typedef int (*compfn)(const void*, const void*);
Return type: int
Argument 1: pointer
Argument 2: pointer
int compare(struct animal *, struct animal *);
Return type: int
Argument 1: pointer
Argument 2: pointer
As you can see, they are compatible with each other, the type checking is a little weaker in C.
When you type (compfn)compare, you tell the compiler to switch to the other function signature, left hand boxing, which indeed matches in this case.

How to use pointers in an union in C?

I want to initialize this structure:
typedef struct
{
int num;
union
{
const char** ppStrList;
const char* pStr;
};
union
{
int num1;
int num2;
};
} tMyStruct;
If I try to initialize this structure when I declare the variable I get an error: For example;
const char *gpStr = "str";
const char *gpStrList[2] =
{
{"str1"},
{"str2"}
};
tMyStruct myStruct[2] =
{
{0,{gpStrList},{3}},
{1,{gpStr},{4}}
};
The variable gpStr can´t be used to initialize the structure
But it can be initialized inside of a function without problem:
int main(int argc, char *argv[])
{
myStruct[0].num = 0;
myStruct[0].ppStrList = gpStrList;
myStruct[0].num1 = 3;
myStruct[1].num = 0;
myStruct[1].pStr = gpStr;
myStruct[1].num2 = 3;
}
Why the structure can't be initialized when it is declared?
I think the union has a special behavior because if I don’t use an union the problem doesn’t exist. For example:
typedef struct
{
int num;
union /* Union to contain ppStrList and pStr pointers */
{
const char** ppStrList;
const char* pStr;
};
union
{
int num1;
int num2;
};
} tMyStruct1;
typedef struct
{
int num;
/* I don´t use an union */
const char** ppStrList;
const char* pStr;
union
{
int num1;
int num2;
};
} tMyStruct2;
const char gStr[] = "str";
const char *gpStrList[2] =
{
{"str1"},
{"str2"}
};
tMyStruct1 myStruct1[2] = /* Structure with union inside */
{
{0,{gpStrList},{3}},
{1,{gStr},{4}} /* <--- Error here if I use gStr address with union */
};
tMyStruct2 myStruct2[2] = /* Structure without union inside */
{
{0,gpStrList,NULL,{3}},
{1,NULL,gStr,{4}} /* <--- No poblem here if I use gStr address */
};
Variables initialized at file scope (whether static or not) and variables initialized at block scope with static duration can only be initialized with constants. Automatic variables (necessarily at block scope) can be initialized with expressions.
Also, when a union is initialized, the initializer must match the first member unless a designated initializer is used. With C99 or later, you could write:
typedef struct
{
int num;
union
{
const char** ppStrList;
const char* pStr;
};
union
{
int num1;
int num2;
};
} tMyStruct;
const char gpStr[] = "str";
const char *gpStrList[2] =
{
"str1",
"str2"
};
tMyStruct myStruct[2] =
{
{ .num = 0, { .ppStrList = gpStrList }, { .num1 = 3 } },
{ .num = 1, { .pStr = gpStr }, { .num2 = 4 } },
};
Note the tweaked type for gpStr. You don't have to use the designated initializers for all the elements, but consistency suggests you probably should. Also note that a union of two differently named int members is modestly pointless. The different elements of a union should normally be of different types.
The unscientific answer:
I think you can only initialize with constants. In the first instance you are initializing (i.e. allocating a value before the program runs) with a variable; by definition variables don't have a "accessible" value until the program runs. In your second example the "initialization" is really an "assignment" with a variable, and that's OK. I don't think it has anything to do with the fact that you have a union.
Simplest example:
#include <stdio.h>
int one = 1;
int two = one;
int main(void) {
printf("one is %d; two is %d\n", one, two);
}
When I try to compile, I get
consts.c:3: error: initializer element is not constant
I hope this clarifies things.
The problem is that you can only initialize the FIRST element of a union, unless you use an explicit designator. So the following works:
tMyStruct myStruct[2] =
{
{0,{gpStrList},{3}},
{1,{.pStr = "str"},{4}}
};

Initializing a Struct of a Struct

If I have a struct in C that has an integer and an array, how do I initialize the integer to 0 and the first element of the array to 0, if the struct is a member another struct so that for every instance of the other struct the integer and the array has those initialized values?
Initialisers can be nested for nested structs, e.g.
typedef struct {
int j;
} Foo;
typedef struct {
int i;
Foo f;
} Bar;
Bar b = { 0, { 0 } };
I hope this sample program helps....
#include <stdio.h>
typedef struct
{
int a;
int b[10];
}xx;
typedef struct
{
xx x1;
char b;
}yy;
int main()
{
yy zz = {{0, {1,2,3}}, 'A'};
printf("\n %d %d %d %c\n", zz.x1.a, zz.x1.b[0], zz.x1.b[1], zz.b);
return 0;
}
yy zz = {{0, {0}}, 'A'}; will initialize all the elements of array b[10] will be set to 0.
Like #unwind suggestion, In C all instances created should initialized manually. No constructor kind of mechanism here.
You can 0-initialize the whole struct with {0}.
For example:
typedef struct {
char myStr[5];
} Foo;
typedef struct {
Foo f;
} Bar;
Bar b = {0}; // this line initializes all members of b to 0, including all characters in myStr.
C doesn't have constructors, so unless you are using an initializer expression in every case, i.e. write something like
my_big_struct = { { 0, 0 } };
to initialize the inner structure, you're going to have to add a function and make sure it's called in all cases where the structure is "instantiated":
my_big_struct a;
init_inner_struct(&a.inner_struct);
Here is an alternative example how you would do things like this with object-oriented design. Please note that this example uses runtime initialization.
mystruct.h
#ifndef MYSTRUCT_H
#define MYSTRUCT_H
typedef struct mystruct_t mystruct_t; // "opaque" type
const mystruct_t* mystruct_construct (void);
void mystruct_print (const mystruct_t* my);
void mystruct_destruct (const mystruct_t* my);
#endif
mystruct.c
#include "mystruct.h"
#include <stdlib.h>
#include <stdio.h>
struct mystruct_t // implementation of opaque type
{
int x; // private variable
int y; // private variable
};
const mystruct_t* mystruct_construct (void)
{
mystruct_t* my = malloc(sizeof(mystruct_t));
if(my == NULL)
{
; // error handling needs to be implemented
}
my->x = 1;
my->y = 2;
return my;
}
void mystruct_print (const mystruct_t* my)
{
printf("%d %d\n", my->x, my->y);
}
void mystruct_destruct (const mystruct_t* my)
{
free( (void*)my );
}
main.c
int main (void)
{
const mystruct_t* x = mystruct_construct();
mystruct_print(x);
mystruct_destruct(x);
return 0;
}
You don't necessarily need to use malloc, you can use a private, statically allocated memory pool as well.

Resources