0

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.

homersimpson
  • 4,124
  • 4
  • 29
  • 39
  • You cannot use a variable length array unless you are compiling under C99 or later. I suggest using #define NUMWORDS 10 at the top of your code under the library imports – LeatherFace Apr 04 '14 at 23:52
  • 2
    Is this code your whole file? You can't do something like `words[0].word = "Hello";` outside of a function. – user2357112 Apr 04 '14 at 23:53
  • Please indicate what line each warning/error refers to. – Scott Hunter Apr 04 '14 at 23:53
  • @user2357112 , sure you can, as long as the memory is allocated properly. That is just a global variable. – LeatherFace Apr 04 '14 at 23:56
  • 1
    @user56029283888 VLA can't use at file scope. when not file scope then use `-std=c99` option. – BLUEPIXY Apr 04 '14 at 23:58
  • @user56029283888: It's a statement, and you can't just run arbitrary statements outside a function. You can declare global variables, and you can initialize them in the declaration, but `words[0].word = "Hello";` isn't a declaration. – user2357112 Apr 05 '14 at 00:03
  • @ScottHunter, the VLA warning is referring to the line: `wordsCount words[numWords]` and the error is referring to the last two lines of my code, where the assignment statements are. – homersimpson Apr 05 '14 at 23:29

3 Answers3

3
#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.

LeatherFace
  • 478
  • 2
  • 11
1

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];
Gerben
  • 122
  • 4
1

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?

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278