Reputation: 95
I think my english is just to bad to understand the other articles about this. But anyway:
I just thought i could write a program (in C), that can store a set of cards. Not complicated, just store values and names of cards and print them out. I'm a beginner in C, and because i'm in the section "Strings in Structures" in my Book, i wanted to try out structures on my own. This is my Code so far:
#include <stdio.h>
struct card
{
int value;
char name[];
};
int main(void)
{
const struct card heart[13] = { {2,"two"}, {3,"three"}, {4,"four"}, {5,"five"}, {6,"six"}, {7,"seven"}, {8,"eight"}, {9,"nine"}, {10,"ten"}, {11,"jack"}, {12,"queen"}, {13,"king"}, {14,"ace"} };
int i;
for (i = 0; i < 13; ++i)
{
printf("The card heart-%s has the value of %i", heart[i].name, heart[i].value);
}
return 0;
}
I just wanted to test if it works, so i just wrote the heart-cards in the code. If i want to compile this file, my compiler (gcc/mingw) hits me with 26 errors. It says: "(near initialization of heart[0])" "non static initialization of a flexible array member" I don't really understand this. In the book, everything works as expected. I tried to rebuild the code in the book and changing the names, but it doesn't work. I think it's a problem with the strings, because if i use integers only, everything works. In already read in another post, that every string should be allocated manually, and there was a code example, but i don't know what all the lines should mean, and i want understand what my code does, so i don't copy + paste.
Could you explain me why this doesn't work? PS: I am writing currently in windows, so please don't use bash commands to explain or something like that. I am also german and my english is not the "yellow of the egg", try to explain without using complex 'sentence builds' (i hope you know what i mean :D) and unusual words.
Thanks for all help!
Upvotes: 0
Views: 1210
Reputation: 4297
The prior answers suggest allocating a fixed length for your names. This has limitations and even dangers. It is always a good idea to avoid it all together.
e.g. You want to alter the name during the game, e.g. "Ace (Trump Card)" but that might be both too long even worse overwrite memory. (Many of the known vulnarabilities in code are caused by buffer overruns)
You are also building in a limitation; What if your game needs translating into another language?
By using pointers, you don't need to resort to either variable length structures or fixed string lengths.
You also add the ability to add API access functions that set data, allowing checks before it's written, preventing buffer overruns.
Instead of using character array (aka strings) you should use pointers in your structures. If you follow the link at the bottom I take this further and use pointers to the structures themselves.
As the pointer storage size never changes your names can be of any length and even altered later, perhaps as the game progresses.
Your card could look something like
typedef struct card
{
int value;
char * name;
}
Now the initial assignment can be done like this
card_t card_ace = {14, "Ace"};
And the values are not fixed (unless that is what you want, then you make them const).
card_ace.value = 200;
card_ace.name = "Trump card";
or an array of cards like this
card_t suit_hearts[] = {{2,"two"}, {3,"three"}, {4,"four"}, {5,"five"}, {6,"six"}, {7,"seven"}, {8,"eight"}, {9,"nine"}, {10,"ten"}, {11,"jack"}, {12,"queen"}, {13,"king"}, {14,"ace"}}
Even better make the whole thing using pointers
typedef card_t * cards_t;
cards_t mysuit = &(card_t){2,"two"}, &(card_t){3,"three"}, ...
Perhaps consider makeing the suit a structure.
typedef struct
{
char * name;
card_t ** cards;
} suit_t;
typedef card_t * cards_t[];
suit_t mysuit = {
.name = "Hearts",
.cards = (cards_t){&(card_t){2,"two"}, &(card_t){3,"three"},....}
}
* For a fully working example of the latter, demonstrating using arrays of pointers to sidestep the limitations of variable length members of fixed arrays, see this gist on github
Upvotes: 0
Reputation: 5265
You need to create some space for the name of each card. Easiest way to do this would be to change your struct card
definition to something like:
struct card
{
int value;
char name[16]; // doesn't have to be 16, but make sure it's large enough to hold each card name plus a '\0' terminator
};
Upvotes: 3