tags:

views:

541

answers:

6

I can't get the code below to compile (see errors). Advice on correction would be appreciated.

#include <stdio.h>

typedef struct {
  char    *fldName;
  unsigned fldLen;
} Field;

typedef struct {
  char    *fldPrompt;
  unsigned startRow;
  unsigned startCol;
} Prompt;

typedef struct {
  Field   *fields[];
  Prompt  *prompts[];
  unsigned numFlds;  <<< invalid field declaration after empty field 
} Form;                    <<< in '(incomplete) struct (no name)'.

Field  firstName = { "fName", 12 };
Field  surName   = { "sName", 25 };
Field  gender    = { "gder", 1 };

Prompt fn        = { "First Name : ", 4, 10 };
Prompt sn        = { "Surname    : ", 6, 10 };
Prompt gn        = { "Gender     : ", 8, 10 };

int main (void)
{
  Form aForm = { { &firstName, &surName, &gender },
                 { &fn, &sn, &gn}, 
                 3 };  <<<  Multiple initializers for the same element
  return 0;             <<<  Too many initializers
}
+3  A: 

You have declared arrays in the struct definition without specifying the bounds. This is not possible:

typedef struct {
    Field   *fields[];
    Prompt  *prompts[];
    unsigned numFlds; 
} Form;

You should either specify a number in the brackets or change it to a pointer type instead: Field **fields;. Always note that size of a structure is static and is known at compile time, thus, it can't have variable sized array inside itself. However, it can point to a variable sized array (as pointers have a constant size).

Mehrdad Afshari
Mehrdad: thank you.
+8  A: 

All your errors stem from the fact that you incorrectly declare arrays inside your struct. You have to specify the size of the array; you cannot just use empty brackets. I.e. this would work:

typedef struct {
    Field *fields[3];
    Prompt *prompts[3];
    unsigned numFlds;
} Form;

If you need to allow for varying number of elements, you'll have to use something else. For example, you can have both fields be pointers:

Field **fields;
Prompt **prompts;

But then you'll have to dynamically allocate and free memory for them, and you definitely won't be able to use aggregate initializer to initialize the struct.

Pavel Minaev
Pavel: I want there to be varying elements so I will investigate your ** advice.
A: 

The following code [ just modified and introduced the size of the array ] and it compiled fine.

include

typedef struct { char *fldName; unsigned fldLen; } Field;

typedef struct { char *fldPrompt; unsigned startRow; unsigned startCol; } Prompt;

typedef struct { Field *fields[3]; Prompt *prompts[3]; unsigned numFlds; // invalid field declaration after empty field } Form; // in '(incomplete) struct (no name)'.

Field firstName = { "fName", 12 }; Field surName = { "sName", 25 }; Field gender = { "gder", 1 };

Prompt fn = { "First Name : ", 4, 10 }; Prompt sn = { "Surname : ", 6, 10 }; Prompt gn = { "Gender : ", 8, 10 };

int main (void) { Form aForm = { { &firstName, &surName, &gender }, { &fn, &sn, &gn}, 3 }; // Multiple initializers for the same element return 0; // Too many initializers }

Also, if you want more than 3 in Line 15, then you need to declare it double pointer and allocate memory and use it. But ensure to deallocate/free it, when not going to use it. Otherwise, it will result in memory leak.

Roopesh Majeti
Roopesh: thanks. I'll be careful with the memory allocation/deallocation!
A: 

The problem is that you can't initialize a zero lenght array.

if you chague the For declaration to:

typedef struct {
    Field   *fields[100];    
    Prompt  *prompts[100];    
    unsigned numFlds;  // <<< invalid field declaration after empty field
} Form;                    // <<< in '(incomplete) struct (no name)'.

It will work.

Aragorn
Aragorn: thanks.
+2  A: 

A structure normally can't hold a member with incomplete type (eg arrays without dimensions) because the compiler can't know that member's size, ie the offset of following members within the structure would be indeterminate. An exception to this rule is the last member, which may have incomplete array type (a so-called flexible array member).

The solution: use fixed-sized arrays or pointers.

Christoph
Christoph: As I want varying numbers of elements I]ll have to use pointers. Thanks.
+1 for mentioning FAMs
Johannes Schaub - litb
A: 

It looks like a linked list structure might be most appropriate to your needs.

By the way - are the Prompts and Fields always mapped one-to-one? If so, you could just store them in the same structure.

caf
Caf: in effect yes. I was rethinking this along the lines you suggested i.e. one structure.