OK, now that you specified what you are trying to do, let's simply start with your code. Let's use the godbolt compiler explorer. I'll only link to versions of your code so that I don't have to copy so much code into this answer.
If we run your original code (with 0
instead of your condition marker) through a recent gcc (12.2.) on godbolt we get a number of warnings and, of course, the error where the condition should be (version 0). Let's fix the first warnings because they are simple:
<source>:16:6: warning: return type of 'main' is not 'int' [-Wmain]
16 | void main(void)
| ^~~~
<source>: In function 'main':
<source>:25:5: warning: implicit declaration of function 'strcpy' [-Wimplicit-function-declaration]
25 | strcpy(table[X_selected][Y_selected]->name, "NAME");
| ^~~~~~
<source>:3:1: note: include '<string.h>' or provide a declaration of 'strcpy'
2 | #include <stdlib.h>
+++ |+#include <string.h>
3 |
<source>:25:5: warning: incompatible implicit declaration of built-in function 'strcpy' [-Wbuiltin-declaration-mismatch]
25 | strcpy(table[X_selected][Y_selected]->name, "NAME");
| ^~~~~~
<source>:25:5: note: include '<string.h>' or provide a declaration of 'strcpy'
- OK, main should return an int. Googling that points us to an SO answer pointing out that
int main(void)
is OK, and not having a return statement is OK, too. Got it.
strcpy
must be declared. gcc already suggests to include the header string.h
. Got it.
- The next warning is harder:
<source>: In function 'main':
<source>:30:17: warning: passing argument 1 of 'show_struct' from incompatible pointer type [-Wincompatible-pointer-types]
30 | show_struct(table, X_selected, Y_selected);
| ^~~~~
| |
| struct mystruct * (*)[7]
<source>:14:35: note: expected 'struct mystruct *' but argument is of type 'struct mystruct * (*)[7]'
14 | void show_struct(struct mystruct* table, int X_selected, int Y_selected);
| ~~~~~~~~~~~~~~~~~^~~~~
In particular, what is struct mystruct * (*)[7]
, and why is the compiler thinking we are passing that when in fact we pass a 2-dimensional array? Before I suggest a solution that is simpler and avoids complicated types, I'll give short explanation.
A 2-dimensional array in C is, in fact, an array of (1-dimensional) arrays. It's easy to understand a 1-dimensional array for a type T (T may be struct mystruct *
like in your program, but the argument is universal). T table[7];
defines an array of 7 Ts. Now I can define an array of 5 of those arrays; because square brackets are evaluated left-to-right, I have to write the new dimension to the left of the old one (think "I first index the 2-dimensional array, obtaining an element — which is a 1-dimensional array, which I index again to obtain the j-th T" — left to right): T table[5][7]
. 5 one-dimensional arrays with 7 Ts each.
The crucial point is to remember what happens when you pass an array to a function: It is "adjusted" to a pointer to its first element. The elements of a T table[5][7]
are arrays of 7 T, or T [7]
, a pointer to that is a T (*)[7]
. We must put the *
in parentheses because otherwise, per operator precedence, the index operation would come first, resulting in a pointer to T, which is something different: We don't have an array of seven pointers to T — we have a pointer to an array of seven T. The order of "pointer" and "array" in these two sentences reflects the order of evaluation, which is enforced by the parentheses in the second case. Now, in our case T is struct mystruct *
, so that the argument actually passed to the function is what gcc reports: struct mystruct * (*)[7]
. It is a pointer to an array of seven pointers to mystruct. That is not the same as a pointer to mystruct.
The easiest way to implement a function that prints one mystruct object would actually be to define the function to simply take a pointer to that mystruct object. The caller is responsible for providing the right pointer. This makes the function more general: Perhaps we want to print mystructs which are not in the table?
Pointers have a nice reserved value to show that they don't point to anything, which is NULL in C. We'll test whether the pointer is NULL to check whether it was initialized. Note that we cannot test e.g. `if(myStructPtr->id == 0) because if myStructPtr is not initialized the program will be faulty and likely crash. But we can and often must examine the actual pointer value.
void show_struct(struct mystruct* myStructPtr)
{
if (myStructPtr != NULL) {
printf("OK , initialized");
}
else {
printf("ERROR, uninitialized");
}
}
Passing such a pointer is relatively straightforward: You index the table properly! The obtained element is a pointer, after all:
show_struct(table[X_selected][Y_selected]);
Now we must make sure that the pointers stored in the table are actually null. We can do that with brace initialization. We don't actually need to initialize all elements, missing ones will be filled with zeroes by default:
struct mystruct* table[X][Y] = {{0}};
Now we have everything together for a working program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define X 2
#define Y 3
struct mystruct {
char name[10];
int id[1];
int status[1];
};
void show_struct(struct mystruct* myStructPtr)
{
if (myStructPtr != NULL) {
printf("OK , initialized\n");
printf("Status: %d\n", *myStructPtr->status);
}
else {
printf("ERROR, uninitialized\n");
}
}
int main(void)
{
struct mystruct* table[X][Y] = {{0}};
int X_selected = 1;
int Y_selected = 1;
table[X_selected][Y_selected] = (struct mystruct*)malloc(sizeof(struct mystruct));
strcpy(table[X_selected][Y_selected]->name, "NAME");
*table[X_selected][Y_selected]->id = 0;
*table[X_selected][Y_selected]->status = 1;
printf("Selected: ");
show_struct(table[X_selected][Y_selected]);
printf("\n");
for(int xInd = 0; xInd < X; xInd++)
{
for(int yInd = 0; yInd < Y; yInd++)
{
printf("%d, %d:\n", xInd, yInd);
show_struct(table[xInd][yInd]);
printf("****************************************\n");
}
}
}