views:

77

answers:

3

Hey all,

Quick C question here. We've been playing with double, triple, even quadruple pointers recently. We though we had a grasp on things until we ran into this problem...

char ***data;
data_generator(&data);
char **temp = data[0];          
printf("printing temp[%d]: %s\n",0, temp[0]);
printf("printing temp[%d]: %s\n",1, temp[1]);
dosomething(temp);

int dosomething(char **array) { 

    printf("printing array[%d]: %s\n",0, array[0]);
    printf("printing array[%d]: %s\n",1, array[1]);
    ......
}

int data_generator(char ****char_data) {
    char *command1[2];
    char *command2[2];

    command1[0] = "right";
    command1[1] = "left";

    command2[0] = "up";
    command2[1] = "down";

    char **commandArray[2];

    commandArray[0] = command1;
    commandArray[1] = command2;

    number_of_commands = 2;

    if(number_of_commands > 1){
    *char_data = commandArray;
    }

    return number_of_commands - 1;
}

And this prints out...

printing temp[0]: right
printing temp[1]: left
Segmentation fault

Looks like I have some misconceptions about what happens to a pointer while passed through a function. Any thoughts?

+3  A: 
*char_data = commandArray;

You are putting the address of a stack (automatic) array in an outside memory location. This is a recipe for disaster (undefined behavior), since commandArray's lifetime ends as soon as data_generator returns. The same is true for the elements of commandArray, which are themselves pointers to stack array elements.

Matthew Flaschen
Thanks for the reply. To make sure I'm clear here, since all of the elements in commandArray are declared in the scope of data_generator, the system can deallocate those objects as soon as data_generator returns. Is that correct? I'm use to objective-c where "retain" is the solution here. What's the C equivalent?
Staros
It can (and does, though you may not get bitten right away) deallocate all the automatic variables. This includes the arrays `command1`, `command2`, and `commandArray`. The general solutions are using memory provided by the caller, or `malloc`.
Matthew Flaschen
A: 

Change:

char *command1[2];
char *command2[2];

to:

static char *command1[2];
static char *command2[2];

That will keep command1[] and command2[] in retained memory.

That, or malloc() them, as the other poster recommends, though proper use of malloc'c memory requires more considerations than I will discuss here.

pj_
You should mention that for many realistic examples (when more than constants are involved), this will make it non-reentrant.
Matthew Flaschen
A: 
int data_generator(char ****char_data)
{
  char *command1[2];
  char *command2[2];

  command1[0] = "right";
  command1[1] = "left";

  command2[0] = "up";
  command2[1] = "down";

  char **commandArray[2];

That ain't C - tha's C++. You have definitions after code without additional curley braces.

Blank Xavier
This is valid C99, which has been out for over a *decade*.
Matthew Flaschen
I never learned it. I've yet to find a company using it, or a compiler which fully implements it.
Blank Xavier