类型为 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 的情况下出现段错误)。
免责声明:我还没有测试过这个。
题外话:请花点时间防止内存溢出; scanf
和 strcpy
不安全。
我正在使用这个链表库,但是我在列出保存的客户端时遇到了问题,我只得到了最后一个插入的客户端。 注意到 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 的情况下出现段错误)。
免责声明:我还没有测试过这个。
题外话:请花点时间防止内存溢出; scanf
和 strcpy
不安全。