0

I'm trying to do something with an array (malloc-ed), namely arr of a custom struct. The array is passed by reference to a function. I get a segfault whenever I tried to index anything other than arr[0] in the function at runtime (e.g (*arr[1])->i = 3;). Why is this happening?

The full source code is:

#include <stdio.h>
#include <stdlib.h>
#define SIZE 100

typedef struct{
    int i;
    float f;
}foo;

void doSomething(foo ***arr);

int main()
{
  foo **arr = (foo**) malloc (SIZE * sizeof(foo*));
  int i;
  for(i = 0; i < SIZE; i++)
    arr[i] = (foo*)malloc(sizeof(foo));

  arr[1]->i = 1;
  printf("Before %d\n",arr[1]->i );
  doSomething(&arr);
  printf("After %d\n",arr[1]->i );
  return 0;
}

void doSomething(foo ***arr)
{
  (*arr[1])->i = 3;
}
user3813674
  • 2,553
  • 2
  • 15
  • 26
  • Standard warning: Do not cast the result of `malloc` in C. And: this is no 2D array. (And being a 3-star-programmer is no compliment). And see [here](http://port70.net/~nsz/c/c11/n1570.html#7.22.3.4) – too honest for this site Aug 29 '15 at 20:45
  • 2
    You get the warning because you didn't put `#include ` in the top – Hamza Abbad Aug 29 '15 at 20:50
  • @Olaf: How do you pass arr by reference to the function without using 3 stars? – user3813674 Aug 29 '15 at 20:53
  • 2
    Why do you thing two stars are not sufficient? (btw: C does not support passing by reference). You are actually passing a pointer to the pointer. What if you nest another function? Do you use four stars? – too honest for this site Aug 29 '15 at 20:54
  • @user3886450 Your function does not modify `arr`; it only modifies memory being pointed to (indirectly) by `arr`. So you may pass `arr` by value to the function. – M.M Aug 30 '15 at 01:49

2 Answers2

2

Your problem is the line

(*arr[1])->i = 3;

Because the subscripting operator's evaluation precedes the dereferencing's evaluation it is equivalent to the following:

(*(arr[1]))->i = 3;

This is obviously wrong. You need

(*arr)[1]->i = 3;

therefore.


Notes:

  • do not cast the result of malloc
  • add #include <stdlib.h> to resolve the warning
  • adding an extra level of indirection (foo*** pointing to foo**) is unnecessary; just copy by value
  • (in addition to the upper note) a good old 1D array should actually be sufficient in your case

  • call free after malloc

Community
  • 1
  • 1
cadaniluk
  • 15,027
  • 2
  • 39
  • 67
  • Adding to this: using `->` with a pointer to an element of an array is a bit confusing, this would be more clearly written as `(*arr)[1][0].i = 3;`, showing that you want to access row 1, column 0 of the array. – M.M Aug 30 '15 at 01:47
1

The warning you get is because you forgot to #include <stdlib.h>, so malloc is not declared, so the compiler assumes it should return int. This can lead to all kinds of fun problems. (And you should remove those casts.)


The other problem is in this line: (*arr[1])->i = 3;

Postfix operators (like []) bind tighter than prefix operators (like *), so *arr[1] parses as *(arr[1]).

You can write (*arr)[1]->i instead to fix this, but as it turns out, your function never actually modifies *arr, so there's no reason to pass arr (the other arr, the one in main)'s address to it. Just do this:

void doSomething(foo **arr)
{
  arr[1]->i = 3;
}

and call it as doSomething(arr).

melpomene
  • 84,125
  • 8
  • 85
  • 148