0

Answers to this question describe how to allocate memory and return it to the calling function. An example was given:

void someFunction (int **data) {
  *data = malloc (sizeof (int));
}

void useData (int *data) {
  printf ("%p", data);
}

int main () {
  int *data = NULL;

  someFunction (&data);

  useData (data);

  return 0;
}

I would also like to assign values before returning to the calling function. However, when I try (for example):

void someFunction (int **data) {
  *data = malloc (2 * sizeof (int));
  *data[0] = 1;
  *data[1] = 1;
}

void useData (int *data) {
  printf ("%p", data);
}

int main () {
  int *data = NULL;

  someFunction (&data);

  useData (data);

  return 0;
}

I receive a segmentation fault. Any help is appreciated.

DJames
  • 571
  • 3
  • 17

2 Answers2

3

Your problem lies with the statement:

*data[0] = 1;

Because of the way precedence works (a), this is actually equivalent to:

*(data[0]) = 1;

rather than, as you expected:

(*data)[0] = 1;

The former variant actually tries to dereference a not-yet-assigned (arbitrary) value, which is what's causing your crash. You should use the latter form to be more explicit.

In any case, it's always a good idea to check any calls that can fail so as to not cause problems later on based on incorrect assumptions. You may also want to consider what will happen if you call the function twice (or more) - it will currently result in a memory leak since the old memory is never freed.

With those points in mind, I would be modifying your function slightly as follows:

void someFunction (int **data) {
    // Release old memory if any (freeing NULL is fine).

    free (*data);

    // Allocate new memory and initialise only if it worked.

    *data = malloc (2 * sizeof (int));
    if (*data != NULL) {
        (*data)[0] = 1;
        (*data)[1] = 1;
    }
}

(a) Precedence is dictated by the order of appearance of expression types in the standard. For example, C11 6.5 Expressions states:

The syntax specifies the precedence of operators in the evaluation of an expression, which is the same as the order of the major subclauses of this subclause, highest precedence first.

And, since array subscripting appears in 6.5.2.1 compared to indirection in 6.5.3.2, the former will happen first.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
2

Sometimes, it is helpful to simplify pointer logic.

For example, in the code shown below, allocation and initialization of memory is done using a more familiar int * (rather than an int **). Then, after allocation and initialization, the allocated memory is returned to the caller via the int **.

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

#define SUCCESS 0

int SomeFunction(int **OUT_data)
   {
   int rCode = SUCCESS;
   int *data = NULL;

   errno=SUCCESS;
   data = malloc(2 * sizeof(int));
   if(!data)
      return(errno);

   data[0] = 10;
   data[1] = 20;

   *OUT_data = data;

   return(rCode);
   }

void UseData(int *data)
   {
   printf("Data[%p]: %d, %d\n", data, data[0], data[1]);
   }

int main()
   {
   int rCode = SUCCESS;
   int *data = NULL;

   rCode=SomeFunction(&data);
   if(rCode)
     {
     fprintf(stderr, "SomeFunction() reports: %d %s\n", rCode, strerror(rCode));
     return(rCode);
     }

   UseData(data);

   return(rCode);
   }
Mahonri Moriancumer
  • 5,993
  • 2
  • 18
  • 28