类型为 Void 函数处理的指针

Pointer of type Void function handling

我正在使用这个链表库,但是我在列出保存的客户端时遇到了问题,我只得到了最后一个插入的客户端。 注意到 list_iterator_next() 函数 return 是一个空指针, 我的代码有什么问题?

#include <stdio.h>
#include <string.h>

#include "simclist.h"   /* use the SimCList library */


int main() {

    // initialize clients
    list_t clients;

    // structure to append
    typedef struct client{
        char ip[45];
        int port;
    } client;

    client client1;

    int i;
    char ip[45];
    int port;

    // initialize the list
    list_init(&clients);

    for( i  = 1 ; i <= 3; i++ ){
        printf("Insert your ip: ");
        scanf("%s", &ip);
        strcpy( client1.ip , ip );

        printf("Insert your port:");
        scanf("%d", &port);
        client1.port = port;

        list_append(&clients, &client1);
    }

    // size of list
    printf("The list now holds %u elements.\n", list_size(&clients));

    // starting iterator session
    list_iterator_start(&clients);
    // check if there is more values
    while (list_iterator_hasnext(&clients)) {
        // get the next value
        client show_client = *(client *)list_iterator_next(&clients); 
        printf("%s:%d\n", show_client.ip, show_client.port);
    }

    list_iterator_stop(&clients);

    list_destroy(&clients);

    return 0;
}

这不是一个完整的答案,但您可以使用这样的数组查看@JonathanLeffler 的评论。然后你会发现列表库是只是结构指针,还是整个数据结构内容。

注意 i 循环中的变化,在 scanf() 中省略了字符串标识符前的 &,并直接在结构字段上使用 scanf()。最后 - 注意字符串长度!

client client1[3];
for( i=0 ; i<3; i++ ){
    printf("Insert your ip: ");
    scanf("%44s", client1[i].ip);

    printf("Insert your port:");
    scanf("%d", &client1[i].port);

    if (list_append(&clients, &client1[i]) != 1) {
        printf ("List append failed\n");
        exit (1);
    }
}

编辑

回到这个问题上,答案很明显了。由于 int list_append(list_t *restrict l, const void *data) 唯一知道 struct client 的是指向它的 void* 指针,它不可能知道要复制的数据的大小,因此它创建的列表中的外部数据,仅包含给定的指针。所以@JonathanLeffler 是正确的:通过为每次插入传递相同的 struct 指针,列表的所有元素都具有相同的指针,因此只有最新数据。

正如 Jonathan Leffler 已经提出的那样,您需要为每个单独的客户端动态分配内存。 SimCList 不会为您做这些;它不能也不会对您的内存管理负责。

替换此行:

list_append(&clients, &client1);

作者:

list_append(&clients, duplicate_client(&client1));

duplicate_client 的简单实现是:

client *duplicate_client(client *c)
{
    return memcpy(malloc(sizeof(client)), c, sizeof(client));
}

但强烈建议进行一些异常处理(以防止在 malloc returns NULL 的情况下出现段错误)。

免责声明:我还没有测试过这个。

题外话:请花点时间防止内存溢出; scanfstrcpy 不安全。