Pete - 1 month ago 7
C Question

# Deref a C pointer to a string within a struct within an array?

I have a thorny C syntax question. I'm building an array of linked lists, where each node in a list is represented by a struct. Each struct holds a string, which is important later:

``````// "linkedList.h"

typedef struct llnode listnode;
struct llnode {
char* data;     // string
// ...and other data
};
``````

My code builds a table of pointers to these "listnodes" and sets all those pointers to NULL, for reasons beyond the scope of this post:

``````void initTable(listnode** table){
// Initialize all pointers in the table to NULL
for (int i = 0; i < TABLESIZE; i++)
table[i] = NULL;
}

int main(){
// Create table of linked lists
listnode** table = (listnode**) malloc(TABLESIZE * sizeof(listnode*));
initTable(table);

return 1;
}
``````

So far, so good. Later, my program stuffs data into the table, adding on to the right linked list if/when necessary. The code to do that works, but I'll offer up a HIGHLY simplified version here for the sake of keeping my post as brief as possible:

``````void insert(listnode** table, int index, char* newData){
if(*(table+index)==NULL){
// Create the new Node
listnode *newNode = NULL;
newNode = (listnode*)malloc(sizeof(listnode));  // allocate for the struct
newNode->data = (char*)malloc(sizeof(char)*15); // allocate for the string within the struct
strcpy(newNode->data, newData);                 // copy newData into newNode->data

// Insert node into table (Super simple version)
*(table+index) = newNode;
}
}

int main(){
listnode** table = (listnode**) malloc(TABLESIZE * sizeof(listnode*));
initTable(table);

insert(table, 0, "New String A");
insert(table, 5, "New String B");
insert(table, 7, "New String C");

return 1;
}
``````

All this works great. Now for my real question... Suppose I want to reach into the table and dereference one of those strings?

``````void printTable(listnode** table){
for(int i=0; i<TABLESIZE; i++){
if(*(table+i)==NULL)
printf("table[%d]  ==  NULL\n", i);
else
printf("table[%d]  ==  %s\n", i, **(table+i)->data);  // << PROBLEM IS HERE!
}
}

int main(){
// create & initialize the table, as above
// insert data into the table, as above
printTable(table);

return 1;
}
``````

The compiler doesn't like my syntax:

``````\$ gcc -Wall linkedList.c
linkedList.c:31:48: error: request for member ‘data’ in something not a structure or union
printf("table[%d]  ==  %s\n", i, **(table+i)->data);
^
\$
``````

So I know this is kinda a long-winding premise for a simple question, but can someone help me with the proper syntax here? I've tried a number of syntactical variations, with no luck.

More puzzling, when I modify the code a little to compile it, then look at this in GDB, I can see that
`**(table+i)`
is my struct, yet
`**(table+i)->data`
is not accessible. Here's the GDB output when I debug the (modified) program; the node representing "New String A" is inserted first at index 0 in the table. :

``````31           printf("table[%d]  ==  %d\n", i, **(table+i));
(gdb) p *(table+i)
\$1 = (listnode *) 0x6000397b0
(gdb) p **(table+i)
\$2 = {data = 0x6000397d0 "New String A"}
(gdb) p **(table+i)->data
Cannot access memory at address 0x4e
(gdb)
``````

I'm really confused about this. Once a C pointer goes through more than one layer of dereferencing, I start getting cross-eyed. Anyone know what the proper syntax here might be?

Thanks a million,
-Pete

PS - Apologies for the superlong post. I swear I struggled to keep it a manageable size...

Given the declaration

``````listnode **table;
``````

then the following expressions have the specified type

``````   Expression             Type
----------             ----
table             listnode **
table + i             listnode **
*table             listnode *
*(table + i)             listnode *
table[i]             listnode *
**(table + i)             listnode
*table[i]             listnode
``````

So you would use one of the following expressions to access the `data` member, from least to most eye-stabby:

``````table[i]->data      // use this, please
(*table[i]).data
(*(table + i))->data
(**(table + i)).data
``````

The grouping parens are necessary - the `.` and `->` member selection operators have higher precedence than unary `*`, so `*table[i].data` would be parsed as `*(table[i].data)`, which is not what you want.