繁体   English   中英

在数组中的结构体中将C指针反引用为字符串?

[英]Deref a C pointer to a string within a struct within an array?

我有一个棘手的C语法问题。 我正在建立一个链接列表数组,其中列表中的每个节点都由一个结构表示。 每个结构都包含一个字符串,这在以后很重要:

// "linkedList.h"

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

我的代码建立了一个指向这些“ listnodes”的指针表,并将所有这些指针都设置为NULL,原因超出了本文的范围:

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;
}

到现在为止还挺好。 后来,我的程序将数据填充到表中,并在必要时添加到正确的链接列表中。 可以执行此操作的代码,但是为了使我的帖子尽可能简短,我将在此处提供一个高度简化的版本:

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;
}

所有这些都很好。 现在是我真正的问题...假设我想进入表格并取消引用其中一个字符串?

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;
}

编译器不喜欢我的语法:

$ gcc -Wall linkedList.c
linkedListc: In function ‘printTable’:
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);
                                                ^
$

因此,我知道这对于一个简单的问题来说是一个漫长的前提,但是有人可以在这里提供适当的语法帮助我吗? 我尝试了许多语法上的变体,但没有运气。

更令人困惑的是,当我稍稍修改代码以对其进行编译,然后在GDB中查看时,我可以看到**(table+i)是我的结构,但是**(table+i)->data无法访问。 这是我调试(修改的)程序时的GDB输出。 代表“新字符串A”的节点首先插入表中的索引0。

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)

我对此很困惑。 一旦C指针经过了不止一层的解引用,我就会开始眼花cross乱。 有人知道这里合适的语法是什么吗?

谢谢一百万,-Pete

PS-对超长职位表示歉意。 我发誓我努力将尺寸保持在可控范围内。

给出声明

listnode **table;

那么以下表达式具有指定的类型

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

因此,您将使用以下表达式之一来访问data成员,从最小到最繁琐:

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

分组括号是必要的- . ->成员选择运算符的优先级高于一元* ,因此*table[i].data将被解析为*(table[i].data) ,这不是您想要的。

C a->b运算符的计算结果为(*a).b 因此,您的代码行实际评估为***(table+i).data ,这显然是错误的。

这也可能有助于对括号进行分组,因此很明显该行的计算结果为(***(table+i)).data还是***((table+i).data) 根据收到的错误消息,可能是后者。

然后,您可以使用数组语法对其进行更多清理。

全部放在一起,您可以简化到table[i]->data

那么,为什么您的调试会话指示相反? 因为**(table + i)是实际的结构本身。 要使用-> ,您需要一个指向该结构的指针。

另外,一点提示。 您进行了malloc()调用。 通常,程序员出于多种原因会避免这种情况。 关于这方面有几篇文章,但是最好的文章之一可以在这里找到。

好的,所以->是最初称为主运算符 ,现在在C11中指定为后缀表达式 它比一元运算符更紧密地绑定。 ->就像. 因为它具有最高的优先级。

情况1:要使用间接指针,可以执行以下操作:

(*p)->field // or...
p[0]->field

情况2:在间接指针的疯狂边缘,您显然可以继续使用...

(**p)->field // or ...
p[0][0]->field

但是,一旦将parens放到那里,就可以像下面这样点缀到结果表达式中。 使用->将一些deref放在->运算符中,而某些则放在* 可能存在使用一个或另一个的论点。

(**p).field      // case 1
p[0][0].field    // still case 1
(***p).field     // case 2
p[0][0][0].field // still 2

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM