I am new to C and have never done anything with a non-OOP language.
I have an array of structs. It is global to the class and I parse a json with the results ending up in above mentioned array. I create an object (?) based on the struct that offers one property for every entry. After adding the items, the array turned out to have the same value on all of the positions.
I did remember C being tricky when it comes to values and pointers/references so I have made a little test to see whether the array actually only took the reference:
typedef struct {
char* name;
} ww_item ;
char nameW[40];
// iterating through json {
// strcpy(nameW, data);
ww_item w = { nameW };
ww_items [ position ] = w;
strcpy(nameW, "d"); //replaces the "Hello" with "d" in all previous ww_items
Obviously it does, which explains why my array ends up being a repetition of the last element that has been added to it instead of listing all the different strings I have added to it.
I am unable to find any short information on this and unfortunately my deadline is too close to read through a whole C book now. I'm pretty sure that my assumptions so far are true but now I do not know what to search for/ to look for in order to solve this problem.
I'm okay with an ugly solution or workaround but at the moment I am just stuck with this.
Thank you for your help.
Change the name member from a pointer to an array.
typedef struct {
char name[40];
} ww_item ;
and then use strcpy()
strcpy(ww_items[position].name, w);
There's no need for the w variable.
Related
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!
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
};
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
struct orange_t {
short size;
Month expirationMonth;
char** foodCompanies;
int maxNumberOfFoodCompanies;
int sellingPrice;
};
memcpy(orange->foodCompanies,foodCompany,sizeof(strlen(foodCompany)));
printf("%s %s",orange->foodCompanies[0],foodCompany);
My problem. that I really don't know to access rightfully to the first word in orange in foodComapnies, the second and so on ...
What is the right syntax and the right way to do it?
I want to write a few foodComapny into orange->foodCompanies, each foodComapny in another place in the array of strings.
memcpy(orange->foodCompanies,foodCompany,sizeof(strlen(foodCompany)));
is wrong. sizeof(strlen...) tells you how big a number is - not useful.
I assume that foodCompanies is an array of names and you want to add foodCompany to that array. You dont show how that array was set up (v important). I will assume that its not set up
orange->foodCompanies = malloc(sizeof(char*))// array holds one entry
orange->foodCompanies[0] = strdup(foodCompany);
to add another entry you will need to realloc or make the original malloc bigger
So I am trying to build and use a struct array in C, and I am encountering a few errors of which I cannot resolve. The code that I have is:
int numWords = 10;
typedef struct
{
char* word;
int count;
} wordsCount;
wordsCount words[numWords];
words[0].word = "Hello";
words[0].count = 1;
First of all, when using the gcc compiler in Unix, I receive an warning, when compiling with the -Wall -pedantic -ansi flags, which reads warning: ISO C90 forbids variable length array 'words' [-Wvla]. And for the last two lines of my code snippet, I receive the error: error: expected identifier or '(' before '[' token.
Could anybody tell me why I am getting these errors? I've Googled many different typedef and struct examples, and mine mirrors that of those examples.
EDIT:
Thank you all for the suggestions. I decided to edit my post instead of responding to each individual comment to provide some clarification of my question. So, I now understand that you can't use variable length arrays in C. I can't officially accept any of the provided answers because my problem still exists, so a clearer explanation of what I am trying to do is warranted.
I am creating a program which counts the occurrences of each word in a text file and prints it out in ASCII order. For example, if the text file contains the following text: "Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo" is a grammatically correct sentence., the output of the program shall be:
Buffalo - 3
a - 1
buffalo - 5
correct - 1
sentence - 1.
The words themselves are already stored into an array. So I want to create an array of structs that contain both the word and the count. I've revised my program to account for dynamically allocated memory. My updated code is:
typedef struct
{
char* word;
int count;
} wordsCount;
wordsCount** words = malloc(sizeof(*words) * numWords);
words[0]->word = "Hello";
words[0]->count = 2;
printf("%s - %d\n", words[0]->word, words[0]->count);
*Note that numWords is an integer that changes according to how large the text file is.
It compiles fine; however, I receive a seg fault at the first assignment statement words[0]->word = "Hello";.
Am I wrong to assume that I can create a pointer to a pointer to structs? I thought the `->' operator does the deference of the struct pointer, and then point to the member "word." I do not understand why I am seg faulting. Any help would be appreciated. If making this edit warrants a new thread, please let me know so I can move it. Thanks.
EDIT 2
I figured out the problem - I was pointer-happy and used way too many pointers to do what I want. I changed wordsCount** words = malloc(sizeof(*words) * numWords); to wordsCount* words = malloc(sizeof(*words) * numWords);. And then I realized I was doing necessary dereferencing when I did words[0]->word = "Hello";, so I changed it to words[0].word = "Hello";, and it works perfectly. Thanks for the help, guys. I'm not sure how to close a thread, or if I should post an answer to my own question? But this thread is now closed.
#define NUM_WORDS 10
typedef struct
{
char* word;
int count;
} wordsCount;
wordsCount words[NUM_WORDS];
This will sufficiently allocate the memory you will need in order to start assigning values.
The compiler needs to know how big the 'words' array should be, so when it comes across your array initialization, it expects to find a size between the brackets. But it finds the 'numWords' variable instead and it can't use that. The preprocessor will not replace 'numWords' with '10'. It will do so when you change this
int numWords = 10;
to this
#define numWords 10
That should work. The preprocessor will then replace every instance of the word 'numWords' in your code with '10', so that the array initialization will read:
wordsCount words[10];
There are two main problems.
The first, ably identified by the other answers, is that you can't use a VLA at global scope. Since numWords is an int variable, it is not a constant and array dimensions at file scope must be constants.
I'd recommend:
enum { numWords = 10 };
See also static const vs #define in C.
The second problem is that you are writing assignments at global scope, and that is not allowed either. You can provide an initializer, though:
enum { numWords = 10 };
typedef struct
{
char* word;
int count;
} wordsCount;
static wordsCount words[numWords] =
{
{ "Hello", 1 },
};
You wouldn't want to let code outside this file access your variables, would you?
Firstly, I am really sorry if this has already been asked and resolved - I have spent ages searching and trying to adapt code samples to give me what I need... but sadly to no avail. Essentially I am just trying to copy the contents of one struct to another (which is documented here elsewhere but I cannot get it to work).
A scanner populates the following struct when it reads a barcode:
struct barcode
{
char *text;
int length;
int id;
int min;
int max;
};
This is instantiated as:
static struct barcode code = {0};
I instantiate another one of the same type:
struct barcode *barcodeHolder;
This is intended to store a copy of the scanned barcode. This is because other codes will then be scanned that indicated other steps such as barcodes to indicate numbers or stages (eg. end, start, etc). Once I want to write the struct contents to disk I use the "copy" of the struct as that is what I want.
However, the char *text property always equals 'c' and not the value of the barcode.
I copy them as follows:
barcodeHolder = malloc(sizeof(code));
barcodeHolder->text = malloc(strlen(code->text) + 1);
strcpy(barcodeHolder->text, code->text);
barcodeHolder->id = code->id;
barcodeHolder->length = code->length;
barcodeHolder->max = code->max;
barcodeHolder->min = code->min;
This is what I have got from other posts on a similar topic.
However, I am clearly doing something stupidly wrong and would welcome any help anyone might be able to offer so that my copy of the struct text element does actually get the right value copied.
Thank you!
Your code is not a pointer
You need this:
barcodeHolder = malloc(sizeof(code));
barcodeHolder->text = malloc(strlen(code.text) + 1);
strcpy(barcodeHolder->text, code.text);
barcodeHolder->id = code.id;
barcodeHolder->length = code.length;
barcodeHolder->max = code.max;
barcodeHolder->min = code.min;
I don't believe that your code is really:
static struct barcode code = {0};
[..]
strcpy(barcodeHolder->text, code->text);
Because the last statement would yield a compile error - because code is not a pointer you have to use code.text there (instead of code->text).
Assuming that you are actually using something like
struct barcode *code = ...;
You are allocating with your above code sizeof pointer of struct code bytes which is not enough for your structure.
Thus, copy it like this:
barcodeHolder = malloc(sizeof(struct barcode));
// alternative: ... = malloc(sizeof(*code));
*barcodeHolder = *code;
barcodeHolder->text = malloc(strlen(code->text) + 1);
strcpy(barcodeHolder->text, code->text);
Or, more simply:
barcodeHolder = malloc(sizeof(code));
*barcodeHolder = code;
barcodeHolder->text = strdup(code.text);
Probably unrelated, but if code in your example is a pointer to a struct, then your sizeof is wrong. It should be sizeof(*code) or sizeof(struct barcode). – Sean Bright 21 hours ago
#SeanBright In no way would I ever call myself a C programmer - ever! - so you saved completely here! Thank you. No, "code" is not a pointer in programme which confused me too... and was probably why I couldn't get anywhere. I just needed to get it work to prove we can do it for a demo. Should it progress I will come back (hopefully!) and revisit the code to better understand why it is working when it maybe shouldn't be. Thank you again!!!
My post tries to kill 2 birds with 1 stone. Sorry in advance for the ignorance.
I'm trying to create an array of strings that I can index[0] or use ptr++ to advance the array. I'm not sure if I should create an array of char pointers, or a pointer to a char array. The variables will be stored in a struct. Forgive the ignorance, I'm just having a hard time with the order of precedence of when and where to use (). I understand a basic struct, it was when I started using a pointer to a string when I started to loose syntax structure. If I can understand the syntax for this, I could apply it further to dimensional structures of arrays.
Assuming I had the assignment of the variables correct, I think I rather use ptr++ in regards to something like printf("%s", ptr++). If I understand correctly, ptr++ would move the pointer to the next string, or some for of ptr++ could. This correct? Seems like that would be faster for many, many things.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Umbrella {
char *name[10];
} Umbrella;
int main ()
{
struct Umbrella * ptr;
// Not understanding this way...
ptr->name[0] = "Some name";
// or this way. Well name++ as long as it wasn't the first string.
ptr->name++ = "Some name";
return 0;
}
Boot note: I have read "C Primer Plus" by Prata. He does well in explaining things, it is just when you start bending things to your will when you start to fall short on applying the syntax. In example, it never covered using pointers to structures to access multidimensional arrays, and it didn't cover pointer arithmetic in a manner of syntax where you would actual use it. Can anyone recommend another book that might at least braze by such approaches?
P.S. This is my second post, and I forgot to say I really like this sites text input design. Had to say it :-).
Well, there's char *name[10] which is really just something like :
char *name0;
char *name1;
char *name2;
// .. etc
Accessing it as ptr->name[0] will just pick the ptr->name0 as a char*.
ptr->name++ = "asdf"; is a pretty bad idea here. What it basically does is :
*(ptr->name) = "asdf";
ptr->name += 1;
Of course, you can't increase name by one here (it's an array, not a pointer) so the compiler won't allow it.
The ++ operator can be useful when iterating past objects. Example :
ptr->name[9] = nullptr; // Make sure the last element is a NULL pointer.
// Take the first element
char **it = ptr->name;
char *current;
// Loop until we reach the NULL
while ((current = *(it++)) != nullptr) {
printf("%s\n", current);
}
The above is a (pretty ugly) way of iterating through an array.
Inserting things in a pre-allocated array:
char **it = ptr->name; // Start at the first element
*(it++) = "Hi!";
*(it++) = "This is the second message.";
*(it++) = "Hello world!";
*(it++) = nullptr; // End the array
Of course, all of this iteration stuff is from a dark past: nowadays we have C++ which takes care of most of these things for us, via std::vector, etc.