Hello,
My goal here is to be able to understand why the code below results in
the printing of "maintable is NULL.". I saw a way to do what I wanted
using typedef string ..., but doing that does not help me to
understand what is going wrong here. Wy doesn't the variable
maintable change?
Thanks
You have several problems. First of all, remember that in C all
function parameters are passed by value; the formal parameter is a
different object in memory from the actual parameter, so if the
function writes to the formal parameter, the actual parameter isn't
affected. If you want the function to be able to modify it's inputs,
you must pass a *pointer* to the thing you want to modify. For
example,
void foo (int x)
{
x = 5;
}
void bar(void)
{
int a = 3;
foo(a);
printf("a = %d\n", a);
}
The expression x in foo and the expression a in bar refer to
completely different objects; writing to x doesn't affect a, so the
output of bar is "a = 3". If we want foo to modify the contents of a,
we must pass a pointer to a, like so:
void foo (int *x)
{
*x = 5;
}
void bar(void)
{
int a;
foo(&a); // the expression &a evaluates to the *location* of
a.
printf("a = %d\n");
}
Now the expression *x in foo and the expression a in bar both refer to
the same object, so writing to *x affects a.
Note that I used the address-of operator & to get the address of a and
pass that to foo; I didn't just cast a to int *.
This same rule applies for any type parameter; if you want a function
to modify a pointer (that is, change where the pointer points to), you
must pass a pointer to that pointer:
void foo (int **x)
{
*x = &some_other_integer; // where some_other_integer has a
// lifetime outside of foo
}
void bar (void)
{
int *a = &some_integer;
foo(&a);
printf("*a = %d\n", *a);
}
Again, the expression *x in foo and the expression a in bar refer to
the same object, it's just that this time that object is a pointer to
an integer, rather than the integer itself. Writing to *x updates the
*pointer* value, not the integer value.
Your next problem is that your off by one level of indirection in your
types. The expression functable in get_table has type char *[2],
which will "decay" to char **, not char *. Thus, you want maintable
in main to have type char **, and the parameter table will need to
have type char ***.
Your final problem is that functable has auto extent; once the
get_table function exits, functable will no longer exist (the memory
that it occupied is released for something else to use, and the
pointer to it will no longer be valid). You can deal with this
several different ways. One is to declare functable as static; this
allocates the memory for it in such a way that it's not released after
the function exits:
static char *functable[] = {"Okay", "Help"};
Another option is to define the array at file scope, which has the
same effect as declaring it as static in the function, although the
functable identifier is visible to the entire program now:
char *functable[] = {"Okay", "Help"};
...
int main(void)
...
void get_table(char ***table)
{
*table = functable;
}
Or, you could declare the memory dynamically, which remains allocated
until you deallocate it explicitly:
void get_table(char ***table)
{
*table = malloc(sizeof **table * 2);
if (*table)
{
*table[0] = malloc(strlen("Okay") + 1);
if (*table[0])
strcpy(*table[0], "Okay");
*table[1] = malloc(strlen("Help") + 1);
if (*table[1])
strcpy(*table[1], "Help");
}
}
The downside of this method is that you'll have to free up that memory
at the end of the program:
free(maintable[0]);
free(maintable[1]);
free(maintable);