0

I have a struct

 typedef struct
 {
  int size; //size of array
  int array*
 } 

How do I allocate memory for the int array using the size variable and malloc?

mazhar islam
  • 5,561
  • 3
  • 20
  • 41

3 Answers3

2

The answer to your question will depend on whether you are declaring a struct or a pointer to struct. In the event you declare a struct (e.g. mystruct s), then you only need to allocate memory for s.size elements in s.array. e.g.:

typedef struct mystruct {
    int size;
    int *array;
} mystruct;
...

mystruct s;

s.size = 5;

/* allocating array based on size */
s.array = malloc (s.size * sizeof *s.array);
if (!s.array) {
    fprintf (stderr, "error: virtual memory exhausted.\n");
    return 1;
}

note: you must validate your allocation succeeded and malloc actually returned a valid address each time you call malloc. (you can create a function that does this to cut down on the typing). You then only need free s.array when you are done.

However, if you declare a pointer to struct (e.g. mystruct *msp = NULL;) you now have to allocate memory for both msp and msp->array. Example:

mystruct *msp = NULL;

msp = malloc (sizeof *msp);
if (!msp) {
    fprintf (stderr, "error: virtual memory exhausted.\n");
    return 1;
}

msp->size = 5;

/* allocating array based on size */
msp->array = malloc (msp->size * sizeof *msp->array);
if (!msp->array) {
    fprintf (stderr, "error: virtual memory exhausted.\n");
    return 1;
}

You must free both when you are done.

The following is a quick example showing the allocation, use and freeing of memory for array in both circumstances:

#include <stdio.h>
#include <stdlib.h>

typedef struct mystruct {
    int size;
    int *array;
} mystruct;

int main (void) {

    size_t i = 0;
    size_t nelements = 0;
    int rd = 0;

    /*
     * declaring a struct mystruct
     */
    mystruct s;

    s.size = 5;

    /* allocating array based on size */
    s.array = malloc (s.size * sizeof *s.array);
    if (!s.array) {
        fprintf (stderr, "error: virtual memory exhausted.\n");
        return 1;
    }

    /* fill array */
    for (rd = 0; rd < s.size; rd++)
        if (scanf ("%d", &s.array[nelements]) == 1)
            nelements++;

    for (i = 0; i < nelements; i++)
        printf (" s.array[%zu] = %d\n", i, s.array[i]);

    /* free allocated memory */
    free (s.array);

    putchar ('\n');

    /*
     * declaring a pointer to mystruct
     */
    mystruct *msp = NULL;

    /* allocate memory for msp (mystruct pointer) */
    msp = malloc (sizeof *msp);
    if (!msp) {
        fprintf (stderr, "error: virtual memory exhausted.\n");
        return 1;
    }

    msp->size = 5;

    /* allocating array based on size */
    msp->array = malloc (msp->size * sizeof *msp->array);
    if (!msp->array) {
        fprintf (stderr, "error: virtual memory exhausted.\n");
        return 1;
    }

    /* fill array */
    rd = 0;
    nelements = 0;
    for (rd = 0; rd < msp->size; rd++)
        if (scanf ("%d", &msp->array[nelements]) == 1)
            nelements++;

    for (i = 0; i < nelements; i++)
        printf (" msp->array[%zu] = %d\n", i, msp->array[i]);

    /* free allocated memory */
    free (msp->array);
    free (msp);

    return 0;
}

Example Use/Output

$ printf "2\n4\n6\n8\n10\n12\n14\n16\n18\n20\n" | ./bin/struct_alloc_int
 s.array[0] = 2
 s.array[1] = 4
 s.array[2] = 6
 s.array[3] = 8
 s.array[4] = 10

 msp->array[0] = 12
 msp->array[1] = 14
 msp->array[2] = 16
 msp->array[3] = 18
 msp->array[4] = 20

Memory Error Check

In any code you write that dynamically allocates memory, it is imperative that your use a memory error checking program. For Linux valgrind is the normal choice. There are so many subtle ways to misuse a block of memory that can cause real problems, there is no excuse not to do it. There are similar memory checkers for every platform. They are simple to use. Just run your program through it.

$ printf "2\n4\n6\n8\n10\n12\n14\n16\n18\n20\n" | valgrind ./bin/struct_alloc_int
==20515== Memcheck, a memory error detector
==20515== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==20515== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==20515== Command: ./bin/struct_alloc_int
==20515==
 s.array[0] = 2
 <snip>
 msp->array[4] = 20
==20515==
==20515== HEAP SUMMARY:
==20515==     in use at exit: 0 bytes in 0 blocks
==20515==   total heap usage: 3 allocs, 3 frees, 56 bytes allocated
==20515==
==20515== All heap blocks were freed -- no leaks are possible
==20515==
==20515== For counts of detected and suppressed errors, rerun with: -v
==20515== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • Minor: `if ((int)i == msp->size)` is curious. See no advantage over `if (i == msp->size)`. If we are stuck with a signed `size`, then code should error or not read any with a non-positive `size` - that implies re-working the loop. – chux - Reinstate Monica Oct 14 '15 at 12:20
  • Yes, I agree. It is a Hobson's choice in this case. I don't want a `for` loop because I want increment control based on the successful `scanf`. Here the bounds on `i` were safe for the cast. e.g. `i=0; ... i++; if (int)i == msp->size) ...` But still I don't like it either. The only, less than elegant fix to preserve the increment based on successful `scanf` is to add and initialize an `int` counter as well. e.g. `i=0; int rd=0;... i++,rd++; if (rd == msp->size) ...`, or just replace `i` with an `int` counter altogether. (I want to keep `nelements` as `size_t`) Your thoughts? – David C. Rankin Oct 14 '15 at 13:44
  • Suggest `for ("same_type_as_msp->size" i = 0; i < msp->size; i++)` and exit loop should `scanf("%d", &msp->array[i]) != 1`. If the `scanf()` result is 0, likely offending `char` in `stdin` that needs special handing. Agree if `size` is any type other than `size_t`, for truly portable code, consult [M. Hobson](https://en.wikipedia.org/wiki/Hobson%27s_choice) and use `fgets()`. BTW nice full answer - you have my +1 – chux - Reinstate Monica Oct 14 '15 at 14:34
1
int *ptr;
ptr = malloc(sizeof *ptr * size);
//can now reference ptr[0], ptr[1], ... ptr[size-1].

What the above code does: When you allocate memory for an int array, you allocate 4 bytes of memory (sizeof(int)) for each element you need. So when you malloc, you malloc the size of the element multiplied by the number of elements you need.

Jack Ryan
  • 1,287
  • 12
  • 26
1

You can create a function for initializing the struct, you can create one like this:

typedef struct {
    int size; //size of array
    int *array;
} mystruct;

mystruct * create_mystruct(int size) {
    mystruct * st = (mystruct*) malloc(sizeof(mystruct));
    st->size = size;
    st->array = (int *) malloc(sizeof(int) * size);
    return st;
}

Here is a working idone as an example.

Hawkings
  • 533
  • 3
  • 16
  • You are welcome :). Also remember that you have to free() all the resources you reserve with malloc() – Hawkings Oct 14 '15 at 04:38
  • `st->array = (int *) malloc(sizeof(int) * size);` casting `maloc()` results not needed. Using `sizeof *pointer` safer --> `st->array = malloc(sizeof *(st->array) * size);` Testing for `NULL` return missing. – chux - Reinstate Monica Oct 14 '15 at 12:07