第一次遍历后的c链表segfault



我正在使用junghans的链表示例,并尝试使其发挥作用带有一些服务器代码。在char数组中,我可以插入一个主机(从inet_ntoa)并更新它的年龄。所以我可以向守护进程发送一个数据包,但随后它崩溃了。我尝试设置next_pointer=start_pointer;,因为从我读到的内容来看循环列表。然而,在接收到第二个数据包后,strcpy崩溃。。

问题:

  1. 如果next_pointer=start_pointer不起作用,我该如何指向开头
  2. 在覆盖char数组的一个成员之前,我需要释放吗
struct x {
    char name[20];
    int age;
    struct x *next_rec;
};
struct x *start_pointer;
struct x *next_pointer;    // starting hosts, will be overwritten 
char *names[] = {
    "127.0.0.1",
    "evil666",
     "192.168.56.101",
     ""
};
int ages[] = {0,20,30,0};
// some other code
while (1) {
    sleep(1);
    us=time(NULL);
    printf("%ld, Sleep a secondn", us);
    buf[0] = 0x0;
    current_host = 0x0;
    memset (buf,0,sizeof buf);
    if(recvfrom(s, buf, BUFLEN, 0, (struct sockaddr*)&si_other, &slen)==-1)
        diep("recvfrom()");
    current_host = inet_ntoa(si_other.sin_addr);
    if(!current_host)
        diep("inet_ntoa()");
    /* linked list initialization */
    /* Initalise 'start_pointer' by reserving
     * memory and pointing to it
     */
    start_pointer=(struct x *) malloc (sizeof (struct x));
    if(!start_pointer)
        diep("start pointer on holiday");
    /* Initalise 'next_pointer' to point
     * to the same location.
     */
    next_pointer=start_pointer;
    /* Put some data into the reserved
     * memory.
     */
    strcpy(next_pointer->name,current_host);
    next_pointer->age = ages[count];
    /* Loop until all data has been read    */
    while ( ages[++count] != 0 )
    {
        /* Reserve more memory and point to it  */
        next_pointer->next_rec=(struct x *) malloc (sizeof (struct x));
        if(!next_pointer)
            diep("next pointer on holiday");
        strcpy(next_pointer->name, names[count]);
        next_pointer->age = ages[count];
    }
    next_pointer->next_rec=NULL;
    next_pointer=start_pointer;
    /* insert new record, update age  */
    while (next_pointer != NULL)
    {
        printf("%s   ", next_pointer->name);
        if(strstr(next_pointer->name,current_host)) {
            printf("%d n", next_pointer->age+1);
        }
        if(!strstr(next_pointer->name,current_host)) {
            printf("%d n", next_pointer->age);
        }
        next_pointer=next_pointer->next_rec;
    }
    next_pointer=start_pointer; // XXX

您的代码的问题是您在init循环中从链接的C文件中错过了这一部分:next_pointer=next_pointer->next_rec。结果,在第一次迭代中,您分配了新的列表节点,但随后修改了第一个节点的内容。然后在随后的迭代中,您可以分配更多的节点,但仍然只修改第一个节点。

然后在循环之后立即终止列表,但由于在此期间没有更新next_pointer,所以列表现在只有一个节点。(你在那里泄露了一些内存,用下一次分配和NULL覆盖了地址,所以现在你无法释放它。)

关于您更具体的问题:

问题1:next_pointer只是一个遍历列表的辅助变量。如果您想要一个循环列表,您应该将某个next_rec指针设置为start_pointer。你可以这样做:

for (next_pointer = start_pointer;
     next_pointer->next_rec != NULL; /* This is not the last node. */
     next_pointer = next_pointer->next_rec /* Move to the next node. */)
  ;
/* At this moment next_pointer points to the last node of the list. */
next_pointer->next_rec = start_pointer; /* And a cycle is there. */

然而,您实际上可以在初始化循环时执行此操作。当您退出init循环时,next_pointer确实指向最后一个节点。因此,与其用next_pointer->next_rec=NULL来终止列表,不如用next_pointer->next_rec = start_pointer来进行循环。

UPDATE也就是说,如果您确实想要一个循环列表。因为实际上next_pointer=start_pointer会使next_pointer指向开头。所以我假设您希望列表的末尾指向开头(正如您提到的循环列表)。

问题2:如果你没有显式(使用malloc)或隐式(例如使用strdup)分配字符串,你就不需要释放它

  • next_pointer->name是结构中的一个数组。您将它与结构(列表节点)一起分配,它将与节点一起释放
  • name是指向常量字符串的指针数组。它们没有被分配,而是将成为应用程序编译代码的数据部分的一部分,因此无法释放

最后但同样重要的是:注意strcpy。如果你只在那里复制IP,20个字符就足够了,但当你第一次尝试复制更大的东西时,缓冲区溢出,可能会覆盖其他一些数据。您应该使用strncpy,n=19,后面跟next_pointer->name[19] = 0,以确保null终止。

并且您不需要在那里运行strstr()两次。它要么返回NULL指针,要么不返回,所以您可以运行

if (strstr( /* .. the arguments .. */ )) {
  /* ... */
} else {
  /* what if the call did return NULL. */
}

相关内容

  • 没有找到相关文章

最新更新