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}}
};
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.
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.
This question already has answers here:
Passing a multidimensional array of variable size
(2 answers)
How to pass 2D array (matrix) in a function in C?
(4 answers)
Closed 4 years ago.
I'm Java developer, not a C programmer. I'm trying to invoke some function that receives a 2D array, tried like:
#include <stdio.h>
int foo(int mat[][N])
{
printf("%d",N); /* <--- here error */
}
int main()
{
int a[5][5] =
{
{1, 2, 3, 4,5},
{1, 5, 5, 5,2},
{1, 4, 30,4,2},
{1, 2, 2,2, 2},
{1,1, 1,1, 2 }
};
foo(a);
return 0;
}
But the compiler says:
'N' undeclared (first use in this function)
I must have the signature: int foo(int mat[][N])
How should I pass the 2D array then?
You can use macros to define constant numbers, i.e. #define N 5. At compile time each appearance of the defined macro name will be replaced with the given value. In our case each N would be replaced with 5.
But this would not solve your problem, because it would print 5 every time, even if you change the dimensions of your array.
Pass the dimensions of the array as parameters.
You can pass the 2D array as a pointer.
I created a printing function, with what I can show you accessing the elements from the array. So the function's prototype would look like:
void print2DMatrix(int *matrix2D, const int rowLength, const int columnLength);
where matrix2D is a pointer, there will be passed the address of the array. The other two parameters tell us the dimensions of the array.
We can access the elements in a selected row and in a selected column with matrix2D[selectedRow * maxRowLength + selectedColumn].
When you call the function, you can pass the name of the array, like print2DMatrix(*myMatrix, myRowLength, myColumnLength);, of course you shall declare and initialize it before using.
print2DMatrix(myMatrix, myRowLength, myColumnLength); would cause warning, because the passed argument and the waited one have different types, but it will run correctly. The passed one is a double pointer, when the waited one is a single pointer. Because of that you have to use print2DMatrix(*myMatrix, myRowLength, myColumnLength);, where *myMatrix will point to the first row of our array.
I would like to mention that myMatrix and *myMatrix point to the same address, the difference is: myMatrix is looked as a double pointer to an integer, when *myMatrix is looked as a pointer to an integer. Run printf("%d %d %d", myMatrix, *myMatrix, **myMatrix); to see the result. **myMatrix will point to the first element of the first row, what is 11. See the entire code below...
#include <stdio.h>
#define ROW_LENGTH 5
#define COLUMN_LENGTH 5
void print2DMatrix(int *matrix2D, const int rowLength, const int columnLength)
{
int i;
for (i = 0; i < rowLength; i++)
{
int j;
for (j = 0; j < columnLength; j++)
{
printf("%d ", matrix2D[i * rowLength + j]);
}
printf("\n");
}
}
int main(void)
{
const int myRowLength = ROW_LENGTH;
const int myColumnLength = COLUMN_LENGTH;
int myMatrix[ROW_LENGTH][COLUMN_LENGTH] =
{
{11, 12, 13, 14, 15},
{21, 22, 23, 24, 25},
{31, 32, 33, 34, 35},
{41, 42, 43, 44, 45},
{51, 52, 53, 54, 55}
};
print2DMatrix(*myMatrix, myRowLength, myColumnLength);
return 0;
}
You are trying to print a non existent value. N is not a declared variable.
The function foo is receiving a pointer. Unlike java, C deals with pointers, not objects, it does not have any information about what it received, except that it is a pointer that contains addresses to ints. Therefore, the function does not know (or care) about your array being of size N (regardless of you mentioning N) .
When you call printf there's nothing in memory called N, which explains the error.
You could always send a second argument which is an int specifying the size and print that one.
void foo(int[][] mat, int matSize){
printf("%d\n",matSize);
}
Notice how I used int[][] this is to simplify and illustrate the fact that is just a pointer.
language: C
i am trying to declare and initialize an array inside a struct and pass it to a pointer, which is itself declared in the struct xD
yes, i know my attempt is... let's say "not correct" :D
but it would be very useful if something similar would exist.
any ideas?
struct structname {
int* section_A;
int* section_B;
};
static const struct structname structvariable_a = {
.section_A = (int[]) {
[0x01] = 1,
[0x02] = 2,
[0x03] = 3
},
.section_B = (int[]) {
[0x33] = 4,
[0x34] = 5
},
};
static const struct structname structvariable_b = {
.section_A = (int[]) {
[0x01] = 10,
[0x02] = 20,
[0x03] = 30
},
.section_B = (int[]) {
[0x33] = 7,
[0x34] = 8
},
};
later, i want to access the values ...
int main()
{
struct structname* structvariablepointer;
if(foo == 1){
structvariablepointer = &structvariable_a;
} else {
structvariablepointer = &structvariable_b;
}
printf("%i", ARRAY_SIZE(structvariablepointer->section_A)); // ARRAY_SIZE(arr) equals sizeof(arr) / sizeof(arr[0]));
int b = 2;
printf("%i", structvariablepointer->section_A[b]);
}
the only error is
./include/linux/build_bug.h:29:45: Fehler: Negative Breite in Bitfeld »<anonym>«
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:(-!!(e)); }))
^
./include/linux/compiler-gcc.h:64:28: Anmerkung: bei Substitution des Makros »BUILD_BUG_ON_ZERO«
#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
^~~~~~~~~~~~~~~~~
./include/linux/kernel.h:60:59: Anmerkung: bei Substitution des Makros »__must_be_array«
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
^~~~~~~~~~~~~~~
Once you take a pointer to the first element of an array, you can no longer find the size of the array through that pointer. So you will also need to make variables to hold the array size. (Or use a sentinel value for the end of the array).
One way to solve your problem would be through ugly macros:
#include <stddef.h>
#define ARRAY_SIZE(a) ( (sizeof(a)) / sizeof((a)[0]) )
struct structname {
int* section_A;
size_t A_len;
int* section_B;
size_t B_len;
};
#define A_INIT (int[]) { 0, 1, 2, 3 }
#define B_INIT (int[]) { [0x33] = 1, [0x34] = 2 }
static const struct structname structvariable_a =
{
.section_A = A_INIT,
.A_len = ARRAY_SIZE(A_INIT),
.section_B = B_INIT,
.B_len = ARRAY_SIZE(B_INIT)
};
#undef A_INIT
#undef B_INIT
It would also be possible to define static named int arrays and then use that array's name in the initializers for structvariable_a.
Consider using int const * and int const[] respectively, if you don't intend to change the contents of the arrays at runtime. Note that if this code is in a header, each translation unit will have their own copy of the arrays.
Update (as suggested by comment): using a sentinel value would look like:
struct structname {
int* section_A;
int* section_B;
};
static const struct structname structvariable_a =
{
.section_A = (int[]) { 0, 1, 2, 3, INT_MAX },
.section_B = (int[]) { [0x33] = 1, [0x34] = 2, INT_MAX }
};
and the in main or whatever, you look for INT_MAX to know where the end of the array is, e.g.:
size_t a_len;
for (a_len = 0; structvariable_a.section_A[a_len] != INT_MAX; ++a_len) { }
Obviously this means the range of valid data for the array needs to exclude the sentinel value.
The error you're getting is because ARRAY_SIZE expects an array, and structvariablepointer->section_A is not an array but a pointer.
Since your structs effectively have fixed size arrays, just declare them as arrays instead of pointers:
struct structname {
int section_A[4];
int section_B[0x35];
};
Then initialize like this:
static const struct structname structvariable_a = {
.section_A = {
[0x01] = 1,
[0x02] = 2,
[0x03] = 3
},
.section_B = {
[0x33] = 4,
[0x34] = 5
},
};
i am trying to declare and initialize an array inside a struct and pass it to a pointer, which is itself declared in the struct xD
That doesn't make any sense whatever, but your actual code is almost completely correct in C99 and later. In particular, this:
(int[]) {
[0x01] = 1,
[0x02] = 2,
[0x03] = 3
}
Is neither a declaration of nor (quite) an initialization of an array; rather, it is a compound literal of type array of int. Because arrays decay to pointers in the context given, as in most, such a compound literal can indeed be used to initialize a structure member of type int * (to point to the first element of the array). Having successfully initialized those two struct structname objects, you can certainly obtain their addresses and record those in variables.
HOWEVER, a pointer to an array element does not carry information about the number of elements in the array. If that's all you have, as is the case in your main() function, then you cannot determine the number of array elements from it. You need to be able to determine that from the content (this is why C strings must be null-terminated), or you must have that information from some other source, such as a function argument, a variable, or clairvoyance.
yes, i know my attempt is... let's say "not correct" :D but it would be very useful if something similar would exist.
If you declare the members of struct structname to be bona fide arrays then you can access and use their declared lengths. If you prefer, you can store the number of array elements in additional members of that struct. Both of those approaches are used in the wild, as are approaches based on the contents of the pointed to elements. But I don't foresee C ever gaining a facility for making your ARRAY_SIZE() macro work with pointers as it seems you would like.
I'm trying to initialize a const struct with a designated initializer. However, one of the struct elements is a fixed-width array. I already have the contents I would like to initialize the array with in another fixed-width array of appropriate size.
Is there any way to do this with a designated initializer? A simple (failing example) of what I'm trying to accomplish is demonstrated below.
struct foo {
uint8_t array1[4];
uint8_t array2[4];
}
uint8_t array[4] = {
1, 2, 3, 4
};
struct foo const bar = {
.array1 = array, // incompatible pointer to integer conversion
.array2 = { *array } // only copies the first element
};
Short answer: you can't. C does not copy arrays (without the use of (standard library-)functions). The warnings come from the fact that you cannot assign an array as a whole, even when they are static or constant. When an array is used as an r-value in an assignment it decays to a pointer and thus cannot be assigned to another array (as a whole).
The easiest way to go would be to use memcpy, but obviously that must be inside a function.
If bar has global scope, or is declared static, then you won't be able use designated initializers to initialize from non-immediate values, regardless of whether or not the members in question are arrays.
However, if:
bar is declared on the stack of some function, and
Your fixed-size array really does only have 4 elements,
then you might be able to get away with something like this:
#include <stdio.h>
#include <stdint.h>
struct foo {
uint8_t array1[4];
uint8_t array2[4];
};
#define ARRAY_INIT(a) { a[0], a[1], a[2], a[3] }
int main (int argc, char **argv) {
uint8_t arr_init[4] = {
1, 2, 3, 4
};
struct foo const bar = {
.array1 = ARRAY_INIT(arr_init),
.array2 = ARRAY_INIT(arr_init),
};
printf("%d, %d\n", bar.array1[0], bar.array2[3]);
return (0);
}
The initializer array must appear before what is being initialized in the stack frame. Or it may come from a function parameter.
Of course if your array is much bigger than this, then using a macro like this will get very messy indeed.
While you may not be able to initialize the array by copying from another array, it may be helpful to use a preprocessor macro:
#define ARRAY_INIT {1, 2, 3, 4}
struct foo const bar = {
.array1 = ARRAY_INIT,
.array2 = ARRAY_INIT
};