C - 无法从void指针访问struct元素值

时间:2014-03-08 23:07:31

标签: c struct void-pointers doubly-linked-list

一些背景知识:

  • 我是一位长期读者,但却是第一次发表的海报。我在Java方面经验不多,但在C语言方面却很少。
  • 我创建了一个双向链表,其中每个节点中的数据实际上是一个“播放器”结构。
  • 我已成功填充列表中每个节点的结构。
  • 我已经对列表本身进行了大量测试,并且表现得如预期的那样。
  • 我希望链表中的每个节点都有一个void指针,因为我打算将这些代码用于最终相互交互的几种不同类型的列表。
  • 我的方法是初始存储从数组中的文件读取的值,然后将这些数据读入每个节点的数据元素。这似乎很成功。

我的问题:当我尝试访问“播放器”结构中各个元素的值时,我得到了废话。我几乎可以肯定这是一个指针问题,因为到目前为止,这是我对C的最大弱点。 相关代码:

我正在展示结构,以防万一我不清楚。注意Node中的void指针,它最终指向一个Player结构:

struct Node;
typedef struct Node {
    void *data;
    struct Node *prev;
    struct Node *next;
} Node;

typedef struct Player {
    char *name;
    char *pos;
    double *num;
} Player ;

我包含了我编写的代码,我将数组中的数据添加到列表中并打印结果。我还显示了结果控制台输出。

// char *vals[linesInFile][3] has already been declared.
// List playerList has already been created and initialized; it currently has 0 nodes.
// int i represents the number of nodes in the list.
// getNode and addNode do just what you'd expect them to do.  Both functions have been thoroughly tested.`

Player *player = calloc(1, sizeof(Player));
int n;
for(n = 0; n < i; n++) {
    if(vals[n][0] != NULL) {
        addNode(playerList, n, NULL);
        getNode(playerList, n)->data = &player;
        ((Player *)getNode(playerList, n)->data)->name = vals[n][0];
        ((Player *)getNode(playerList, n)->data)->pos = vals[n][1];
        ((Player *)getNode(playerList, n)->data)->num = vals[n][2];
        printf("%d: %s\n", n, ((Player *)getNode(playerList, n)->data)->name);
        printf("%d: %s\n", n, ((Player *)getNode(playerList, n)->data)->pos);
        printf("%d: %s\n", n, ((Player *)getNode(playerList, n)->data)->num);
        printf("\n");
    }
}
  

0:Mike Trout
  0:CF
  0:4276

     

1:布莱斯哈珀   1:LF
  1:4599

     

2:Jose Fernandez
  2:SP
  2:5023

到目前为止一切正常。最后,我包含了我编写的代码片段,试图从main函数中找到播放器结构的值。

// The getSize method has been tested and correctly returns the size of a list.
int i;
for(i = 0; i < getSize(playerList); i++) {
    printf("%d: %s\n", i, ((Player *)getNode(playerList, i)->data)->name);
    // The output from this is garbage.
    char *playerName = ((Player *)getNode(playerList, i)->data)->name;
    printf("%d: %s\n", i, playerName);
    // The output from this is garbage.
}

我不肯定最后一个块之前的所有代码都是正确的,但至少它似乎产生了所需的输出。希望这只是最后一段代码的一个简单的指针问题。无论如何,我们将非常感谢任何帮助。

2 个答案:

答案 0 :(得分:2)

这条线似乎错了:

getNode(playerList, n)->data = &player;

player已经是指向Player的指针,因此,这一行实际上是将新节点的data字段设置为指向的指针到{ {1}},其余的代码使用它,好像它是指向Player的指针 - 类型不匹配,这就是你的问题。

相反,该行应为:

Player

也就是说,您不需要应用运算符的地址。其余的代码看起来还不错。

代码似乎没问题,因为您的打印声明具有误导性。您只分配一个节点,并不断反复更改其值。问题是,每次更改该节点上的字段时,都会打印它,因此输出看起来正确,但程序一次只能存储一个节点和一条信息。您可以存储,打印,覆盖,打印,覆盖,打印....

要解决此问题,您需要在每次迭代时显式分配一个新节点:

getNode(playerList, n)->data = player;

然后,填充列表后,打印出来:

Player *player;
int n;
for(n = 0; n < i; n++) {
    if(vals[n][0] != NULL) {
        player = calloc(1, sizeof(Player));
        addNode(playerList, n, NULL);
        getNode(playerList, n)->data = player;
        ((Player *)getNode(playerList, n)->data)->name = vals[n][0];
        ((Player *)getNode(playerList, n)->data)->pos = vals[n][1];
        ((Player *)getNode(playerList, n)->data)->num = vals[n][2];
    }
}

此外,如果您不想复制数组中的指针但复制其内容,则可以使用for(n = 0; n < i; n++) { if(vals[n][0] != NULL) { printf("%d: %s\n", n, ((Player *)getNode(playerList, n)->data)->name); printf("%d: %s\n", n, ((Player *)getNode(playerList, n)->data)->pos); printf("%d: %s\n", n, ((Player *)getNode(playerList, n)->data)->num); printf("\n"); } }

strdup()

但是,请记住,在释放节点本身之前,您现在必须 /* ... */ ((Player *)getNode(playerList, n)->data)->name = strdup(vals[n][0]); ((Player *)getNode(playerList, n)->data)->pos = strdup(vals[n][1]); free()name中的每一个。{1}}。此外,由于pos是指向double的指针,因此您无法在其上使用num。相反,您必须手动分配内存并复制其内容:

strdup

答案 1 :(得分:2)

以及&amp; FilipeGonçalves指出的问题,你还有其他一些问题。

您只需分配一个Player结构,然后将其用于列表中的每个项目。这意味着他们都指向相同的数据,你最终会打印最后一个玩家的详细信息。您应该将calloc移动到for n循环内。

您也只是复制vals中name,pos和num值的指针。这可能没问题,但它确实意味着vals需要在播放器列表的生命周期内保持在范围内(或不被释放)。