struct mystruct s[10] = {{0}};
This appears to initialize an array of structs to 0. How does the nested braces syntax work?
Any fields not specified are initialized to zero. So here you have an array of structs. You're initializing the first element of the array with a structure initializer that initializes the first element of the structure to zero. The rest of the first structure and the rest of the array elements will all be zero too. It's a nice idiom.
As shown?
Basically, you should enclose each compound type - array, structure, etc - inside its own level of braces.
Consider:
struct mystruct
{
int i;
double d;
char s[10];
int a[5];
} s[10] =
{
{ 0, 0.0, "abc", { 1, 2, 3, 4, 5 } },
{ 1, 1.0, "def", { 2, 3 } }, // Partially initialized array
{ 2, 2.0, { 'x', 'y', 'z' }, { 0 } }, // Strings are a shorthand
[9] = { 9, 99, 0, { 9, 8, 7, 6, 5 } }, // C99 - initialize row 9
};
But you can also omit braces if you insist (bad, archaic practice):
struct mystruct t[3] =
{ // You cannot avoid using these outside braces
0, 0.00, "abc", 1, 2, 3, 4, 5, // Omitted braces
1, 1.11, "bcd", 2, 3, 4, 5, 4,
2, 2.34, // Omitted values
};
Any omitted initializers are treated as zeroes.
It is not the nested braces that initializes. The outer braces are indicating that an array is being initialized:
struct mystruct s[10] = { };
Since this is an array of structures, each structures can be initialized with further braces:
struct mystruct { int x, y, z};
struct mystruct s[10] = { {0, 1, 2}, // <-- initializes s[0].x, s[0].y, s[0].z
{1, 2, 3}, // <-- initializes s[1].x, s[1].y, s[1].z
{2, 3, 4} // <-- initializes s[2].x, s[2].y, s[2].z
};
Notice that only first three elements are initialized. According to C standard the rest 7 elements must be initialized to 0. This is what happens to your code too. As xscott mentioned in his reply, everything omitted in initializer list is initialized to 0.
It's useful to note that while the inner braces are optional, the compiler will check to ensure that opening braces only appear where they ought, and that no nested item has too many initializers. Further, one may leave out some fields of a structure and have the compiler automatically zero them, even if the structure is not at the end of the array. Note that implementations vary in their efficiency of handling this; some will divide the initialization record into small pieces, while others will simply insert lots of zeroes in the code. For example, if each struct looked like:
typedef struct {
char name[8];
char more_stuff[1016];
} THINGIE;
THINGIE my_array[] = {{"Fred"},{"George"},{"Mark"}};
some compilers would generate 3K worth of const data, while others would generate three relatively-small 'const-init' records.
Related
I'm new to c, and currently making chess program.
There's the code.
#include <stdio.h>
int spider[8][2] = {{0, 1}, {1, 1}, {1, 0}, {1, -1},
{0, -1}, {-1, -1}, {1, 0}, {-1, 1}};
int jump[8][2] = {{1, 2}, {2, 1}, {2, -1}, {1, -2},
{-2, -1}, {-1, -2}, {-1, 2}, {-2, 1}};
typedef struct
{
int color;
int type;
char symbol;
int unit[8][2];
} piece;
void add_piece(piece piece, int color, int type, char symbol, int unit[8][2])
{
piece.color = color;
piece.type = type;
piece.symbol = symbol;
for(int i = 0; i < 8; i++)
{
for(int j = 0; j < 2; j++)
{
piece.unit[i][j] = unit[i][j];
}
}
}
int main(void)
{
piece wk;
add_piece(wk, 0, 0, 'K', spider);
printf("%d", wk.color);
return 0;
}
expected output : 0
console output : 8388608
I found that 8GB = 8388608KB.
What's the meaning of that output?
Is there any problem of initializing property of structure or elsewhere?
Can you see some not good habits in this code?
Remember that in C all arguments are passed by value.
That means the value of the argument in the call is copied into the functions argument value.
So in the call
add_piece(wk, 0, 0, 'K', spider);
the value (current uninitialized contents) of the structure object wk will be copied into the argument variable piece inside the add_piece function.
When you modify the local argument variable, for example through an assignment like
piece.color = color;
you only modify the local copy. The original value used in the call will not be modified.
You can solve this in two ways:
Return the structure, and assign to a variable when doing the call; Or
Emulate pass by reference by using pointers.
Option number 2 is the most common it seems, so I will show it here.
First you need to modify the function to take a pointer to the structure object:
void add_piece(piece *piece, int color, int type, char symbol, int unit[8][2])
{
...
}
Then you need to use the "pointer to structure" syntax using the "arrow" to access structure members:
piece->color = color;
piece->type = type;
// And so on for all access to piece members...
Finally, when you call the function you need to pass a pointer to the wk variable, using the "pointer to" or "address of" operator &:
add_piece(&wk, 0, 0, 'K', spider);
I described the pass by reference emulation because it's so common and because you need to learn to recognize it. For your specific case I would rather recommend that you define a new structure object in the function and return it:
piece add_piece(int color, int type, char symbol, int unit[8][2])
{
piece piece;
piece.color = color;
piece.type = type;
// And so on, much like your current function...
// Return the structure
return piece;
}
Now you can use it as such:
piece wk = add_piece(0, 0, 'K', spider);
Note that sometimes it's not possible, or desirable, to return structures like this, and you still need to emulate pass by reference. So you need to learn both ways.
Lastly a note about the output you get: Uninitialized local (non-static) variables really are uninitialized. They will have indeterminate (read: garbage) values.
Since in your current code doesn't really initialize the original wk structure object, all its members will have such indeterminate values.
Depending on type and use, using such indeterminate values could lead to undefined behavior.
I have a struct with a single member. This member is actually a pointer to pointer to integer, in order to represent a 2-dimensional integer array.
Can I use scalar initialization while creating an instance of that struct?
I am trying to create a 2-dimensional array to represent a collection of pixels for an algorithm exercise.
I should represent something like this:
{
{ 0, 0, 1, 0, 0 },
{ 0, 1, 1, 1, 0 },
{ 1, 1, 1, 1, 1 }
}
In order to represent a generic abstraction of an image, I tried to create a struct with the following structure:
struct image_t
{
unsigned short int** pixels;
};
And so I try to init an instance of that by using:
int
main()
{
struct image_t image = {
{
{0, 0, 1, 0, 0},
{0, 1, 1, 1, 0},
{1, 1, 1, 1, 1},
}
};
return 0;
}
When I try to compile, the following warnings are given:
gcc -I src src/main.c -o bin/flood-fill.bin
src/main.c: In function ‘main’:
src/main.c:41:5: warning: braces around scalar initializer
{
^
src/main.c:41:5: note: (near initialization for ‘image.pixels’)
src/main.c:42:7: warning: braces around scalar initializer
{0, 1, 0},
^
src/main.c:42:7: note: (near initialization for ‘image.pixels’)
src/main.c:42:11: warning: excess elements in scalar initializer
{0, 1, 0},
^
src/main.c:42:11: note: (near initialization for ‘image.pixels’)
src/main.c:42:14: warning: excess elements in scalar initializer
{0, 1, 0},
After making some research, I realized that, as it is gonna be an image representation, each row will have the same total of columns. Due that, I can just use a single array and store everything in a single block of memory. It resolves my problem.
However, as a curious guy, I would like to know if there is any way to use scalar initialization for such cases - if so, how can I do that?
Most likely I'm missing some critical basic concept from C language, so explanations are more than welcome. I really want to understand better the way it works under the hood.
It probably isn't a good idea, but you can use compound literals to create the structure you want, like this:
struct image_t
{
unsigned short int **pixels;
};
int main(void)
{
struct image_t image =
{
(unsigned short *[]) {
(unsigned short []){ 0, 0, 1, 0, 0 },
(unsigned short []){ 0, 1, 1, 1, 0 },
(unsigned short []){ 1, 1, 1, 1, 1 },
}
};
return image.pixels[1][4];
}
Note that one of the problems with the data structure shown is that there is no information about how many rows are in the array of pointers, nor how many items are in each row (and there's no guarantee that each row is the same length as the other rows). That alone is reason enough to think that the structure is broken (badly designed, at any rate). If you added information about the rows and columns, then it could be OK.
Note that unsigned short **pixels; is not a pointer to a 2D array. It is a pointer to (an array of) pointer(s), which is quite different.
How I can initialize an element in a struct? I have this struct:
typedef struct { int mat[x][x]; int res; } graphe;
graphe g;
I was expecting this to work:
g.mat = {{0, 1}, {1, 0}, {1, 1}, {0, 1}};
but it does not.
The main problem is that arrays are not assignable, and by the time you want to set g.mat, it has already been default initialized. What you are attempting is to assign values to the members of an existing instance. A lesser problem is some missing braces.
Instead of default-initializing g and then attempting to assign values to its members, you can initialize the graphe object with the desired values for the members:
graphe g = {{{0, 1}, {1, 0}, {1, 1}, {0, 1}}};
This will also implicitly initialize g.res to 0, but you can also initialize it to a specific value:
graphe g = {{{0, 1}, {1, 0}, {1, 1}, {0, 1}}, 42};
Here's an example using designated initializers. This might be easier to read than the previous examples, and you can change the order of the fields:
graphe g = { .mat = {{0, 1}, {1, 0}, {1, 1}, {0, 1}}, .res = 42};
You can initialize your g at the point of definition, as shown in #juanchopanza's answer.
However, you can also assign a new value to g later (if the need arises) by using a similar syntax in combination with the compound literal feature of C language
g = (graphe) { { { 0, 1 }, { 1, 0 }, { 1, 1 }, { 0, 1 } }, 42 };
Note that the assignment operator will only work for the entire struct object. If you want to assign a new value only to the g.mat array, not touching any other fields of g, then the assignment operator won't work for that purpose since arrays in C are not assignable. However, you can still use memcpy in combination with a compound literal to copy new values into g.mat
memcpy(g.mat, (int [x][x]) { { 0, 1 }, { 1, 0 }, { 1, 1 }, { 0, 1 } }, sizeof g.mat);
This is actually what you tried to do in your question.
In C, I need to statically pre-allocate an array of numbers, each associated with a different array of strings. Will a code like the following do the trick:
struct number_and_strings {
int nnn;
char **sss;
}
static struct number_and_strings my_list[] = {
{12, {"apple","banana","peach","apricot","orange",NULL}},
{34, {"tomato","cucumber",NULL}},
{5, {"bread","butter","cheese",NULL}},
{79, {"water",NULL}}
}
sss is a pointer to pointer. So an array of pointers can't be directly assigned to it. You can assign as follows using compound literals (which is a C99 feature):
static struct number_and_strings my_list[] = {
{12, (char*[]){"apple","banana","peach","apricot","orange",NULL}},
{34, (char*[]){"tomato","cucumber",NULL}},
{5, (char*[]){"bread","butter","cheese",NULL}},
{79, (char*[]){"water",NULL}}
};
I have a problem, I was asked to declare an array of structures, with one structure inside like so:
typedef struct {
int a;
int b;
int c;
}blah;
int main()
{
blah arr[1] = {{0, 0, 0}};
//...
}
Is the above initialization correct?
Yes, it's totally correct.
Array of length 1 is not much different from those containing multiple elements: they all are aggregate types and their initialization should be enclosed in curly braces. If your array had 2 elements, the initialization would be like
blah arr[2] = { {0, 0, 0}, {0, 0, 0} };
Yes.
You don't need to specify the size if you're going to have an explicit initializer, let the compiler figure it out:
blah arr[] = { { 0, 0, 0 } };
I've also included spaces to make the nesting a bit clearer.