我在链接列表末尾插入节点时遇到问题。我和其他人的逻辑看起来很好,但问题仍然存在,我对它可能发生的地方一无所知。我插入第一个节点,它打印正确。但是,当我尝试插入以下节点时,就好像另一个节点被删除并被新节点替换。这是我正在使用的函数:
struct client_info{
pthread_t client_ID;
int sockfd;
struct chat chats;
char user[NAMELEN];
struct client_info *next;
char current[NAMELEN];
};
struct header{
struct client_info *fnode, *lnode;
}client_head;
void client_insert(struct client_info *node){
if(client_head.fnode == NULL){
client_head.fnode = node;
client_head.lnode = node;
}
else{
client_head.lnode->next = node;
client_head.lnode = node;
}
}
void display_clients(){
struct client_info *tmp = client_head.fnode;
while(tmp!=NULL){
printf("Username: %s\nSocket: %d\n--------------------\n",tmp->user,tmp->sockfd);
tmp = tmp->next;
}
}
//inside main.
while(1){
size = sizeof(struct sockaddr_in);
if((clientfd = accept(sockfd, (struct sockaddr *)&client_addr,(socklen_t*)&size))>0){
printf("Client accepted\n");
struct client_info clinfo;
clinfo.sockfd = clientfd;
clinfo.next = NULL;
pthread_mutex_lock(&mutex);
client_insert(&clinfo);
pthread_mutex_unlock(&mutex);
pthread_create(&clinfo.client_ID, NULL, client_commands_handler, (void *)&clinfo);
}
else{
perror("accept");
}
}
return 0;
}
主要的接受功能,是因为我将它用于聊天程序。此代码中的fnode和lnode分别是指向列表的第一个和最后一个节点(头部和尾部)的指针。 所以例如我有一个名为jack的连接客户端,插座号为5,他是第一个也是唯一一个连接的客户端,它会正确地打印出jack和5.但是如果是一个sencond客户端,amy加入socket 3它只会打印出来艾米和3,没有第一个客户,依此类推。
答案 0 :(得分:1)
在while
循环中,您将clinfo
声明为struct client_info
的实例。然后,将该变量的地址传递给client_insert
,将该变量的地址放入列表中。
当您到达循环结束时,该变量超出范围。所以现在你有一个超出范围的变量的地址。随后使用该地址调用undefined behaivor。
至于为什么事情似乎被覆盖,这正是发生的事情。在每次循环迭代中,您有一个struct client_info
实例,它恰好发生(由于未定义的行为)与上一次循环相同的地址。因此,您每次都会将同一地址传递给client_insert
。
您需要动态分配struct client_info
的实例并将其添加到列表中。
struct client_info *clinfo = malloc(sizeof(*clinfo);
if (!clinfo) {
perror("malloc failed");
exit(1);
}
clinfo->sockfd = clientfd;
clinfo->next = NULL;
pthread_mutex_lock(&mutex);
client_insert(clinfo);
pthread_mutex_unlock(&mutex);
pthread_create(&clinfo->client_ID, NULL, client_commands_handler, clinfo);