首次遍历后的链表列错误

时间:2012-03-02 09:39:42

标签: c linked-list

我正在使用链接列表示例from junghans并尝试使其工作 一些服务器代码。在char数组中,我可以插入一个主机(来自inet_ntoa) 并更新它的年龄。所以我可以向守护进程发送一个数据包,但随后它崩溃了。 我尝试设置next_pointer=start_pointer;,因为根据我的阅读,它会是 圆形清单。但是,收到第二个数据包后,strcpy崩溃..

问题:

  1. 如果next_pointer = start_pointer不能解决问题,我该如何指向开头?
  2. 在覆盖char数组的成员之前,我是否需要释放?
  3. 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 second\n", 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
    

1 个答案:

答案 0 :(得分:0)

您的代码存在的问题是您从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是结构中的数组。您将它与结构(列表节点)一起分配,它将通过节点释放。
  • names是指向常量字符串的指针数组。它们没有被分配,而是将成为应用程序编译代码的数据部分的一部分,因此无法释放。

最后但并非最不重要:了解strcpy。如果你只复制那里的IP,那么20个字符总是足够的,但是你第一次尝试复制更大的东西,你就会有缓冲区溢出并且可以覆盖其他一些数据。您应该使用strncpy,其中n = 19,然后是next_pointer->name[19] = 0以确保空终止。

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

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