2012-03-02 22 views
0

我正在使用鏈接列表示例from junghans並嘗試使其與某些服務器代碼一起工作 。在字符數組中,我可以插入一個主機(來自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 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 
+0

哦,縮進使得它看起來更容易。 :)你確定count是否在數組邊界內? – 2012-03-02 11:31:19

+0

什麼是計數?它在哪裏初始化? – wildplasser 2012-03-02 11:42:20

+0

int count = 0; ... – Anton 2012-03-02 11:48:39

回答

0

與您的代碼的問題是,你錯過了這個部分,從初始化循環鏈接的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是結構中的一個數組。您將它與結構(列表節點)一起分配,並且它將與節點一起釋放。
  • 名稱是指向常量字符串的指針數組。它們沒有被分配,而是成爲應用程序編譯代碼的數據部分的一部分,因此不能被釋放。

最後但並非最不重要的:瞭望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. */ 
}