13

I have a structure as below:

struct Query {  
    int     pages[];
    int     currentpage;
};

I was wondering if it was possible to set the size of this array after creating the structure.

Query new = malloc(sizeof(struct Query));

After this, I will perform some calculations which will then tell me the size that pages[] needs to be. If pages[] needed to be of size 4, how can I set it as such?

4
  • 3
    int pages[]; --> int *pages; and then malloc-ate it. Remember that pages have to be freeed before the whole structure free. Commented May 12, 2016 at 6:32
  • in other languages, you can create a constructor for a struct. not sure with c. but i think that is the path to take. Commented May 12, 2016 at 6:32
  • 1
    Let pages be an int pointer instead. That way you can allocate memory for it in the heap with malloc after you've created the struct. Commented May 12, 2016 at 6:34
  • 4
    This struct is illegal. Flexible array member must be the last element. Then you can adjust the size . Commented May 12, 2016 at 9:01

5 Answers 5

14

In C99 you can use Flexible array members:

struct Query {  
    int currentpage;
    int pages[]; /* Must be the last member */
};

struct Query *new = malloc(sizeof(struct Query) + sizeof(int) * 4);
Sign up to request clarification or add additional context in comments.

3 Comments

OP said that wants to allocate the struct and after some calcs allocate the array. You should add a realloc example. BTW flexible arrays must be used by "expert" people, my personal opinion.
@LPs, I think you are right, but reallocing with a different size (than the first malloc) seems dangerous to me, isn't it? For this concrete case, I think OP means allocate the struct without knowing the size of array at runtime (there is only an int and an array in the struct and the int currentPage can be stored in a temporary variable before malloc and then reassigned to the struct), but I could be wrong. Excuse my poor english.
I agree. This specific case can work as you described. I don't think that realloc can be more dangerous than using malloc. I mean: you have to know what you are doing using Flexible arrays. +1
7

Change the type of pages member to pointer.

struct Query {  
    int *pages;
    int currentpage;
};

struct Query *test = malloc(sizeof(struct Query));

if (test != NULL)
{
   //your calculations

   test->pages = malloc(result_of_your_calcs);
   if (test->pages != NULL)
   {
      // YOUR STUFF
   }
   else
   {
      // ERROR
   }
}
else
{
   // ERROR
}

When you'll free your struct, you have to do that on the contrary.

free(test->pages);
free(test);

1 Comment

I think you meant if (test->pages == NULL) { /* ERROR */ }, not error if test->pages != NULL
5

You can use a Flexible array member (details in @AlterMann's answer) (C99+), or a Zero length array (GNU C).

Quoting from https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html,

Zero-length arrays are allowed in GNU C. They are very useful as the last element of a structure that is really a header for a variable-length object:

struct line {
   int length;
   char contents[0];
};

struct line *thisline = (struct line *)
   malloc (sizeof (struct line) + this_length);
thisline->length = this_length;

For standard C90, the linked site mentions

In ISO C90, you would have to give contents a length of 1, which means either you waste space or complicate the argument to malloc.

This means that for the code to work in standard C90/C89, char contents[0]; should be char contents[1];.

3 Comments

GCC supports flexible array member so there is not really any reason to use the zero-sized array. And you don't need to cast maloc
Yes. But flexible array member is standard only in C99+ (Yes, I know C89 is ancient, but it is worth mentioning). And as for the cast, I just copied the code from the linked site as such (I know that the cast is not required)
@M.M: Zero-sized arrays had some advantages over flexible array members in some implementations that allowed them. For example, if a programmer was mindful of alignment, given struct SIZED_ARRAY {int size; int dat[0];} it would be possible to create an initialized instance via struct { SIZED_ARRAY arr; int dat[4];} my_array = {{4}, {1,2,3,4}};`. While some C99 compilers offer useful extensions, I don't think C99 itself offers any practical equivalent.
2

Declare it as pointer and use malloc afterwards

struct Query {  
    int * pages;
    int   currentpage;
};

. . .

struct Query obj;
obj.pages = malloc(n * sizeof(int));   // n is the length you want

Comments

2

The best solution would be to use pointers to int instead of array.

You will need to change :

int pages[];

to :

int *pages;

and then dynamically allocate it like this :

Query *new = malloc(sizeof(struct Query));
if (new == NULL)
    printf ("Error\n");
else
{
    new->pages = malloc(4*sizeof(int));
    if (new->pages == NULL)
       printf ("Error\n");
}

Otherwise if you want to keep your format, you will use C99 mode. Declare pages as the last member of your struct, like this :

struct Query {  
    int currentpage;
    int pages[];
};

and then do :

Query *new = malloc(sizeof(struct Query) + 4*sizeof(int));

3 Comments

Shouldn't it be Query * new = ... ?
@Shreevardhan yes, I missed the asterisk! Thanks, I edited my post :)
new->pages = malloc(4*sizeof(int)); will cause a segmentation fault if the previous malloc for new fails.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.