2013-10-20 30 views
4

所以現在我試圖實現deltaclock,我嘗試的第一步是首先使用雙鏈表(我會稍後再做其他deltaclock的東西)。要從優先隊列中彈出的第一個元素是位於鏈表(或deltaClock結構)根部的元素。Segifying當試圖取消指針C

我在測試中將幾個元素推到隊列中,經過幾次彈出操作後,有一種情況會在從幾乎空的列表彈出時發生段錯誤。

當我在彈出方法中註釋掉我說「clock-> root-> previous = 0;」的行時,主方法中的程序在彈出元素時不會出現段錯誤。但是,由於前一個節點不再存在,因此需要刪除指向前一個節點的指針。

我怎樣才能讓新的根的前一個指針在執行彈出操作時變爲空?

#include <stdio.h> 
#include <stdlib.h> 

struct deltaNode{ 
    int tics;     // source 
    struct deltaNode* next; 
    struct deltaNode* previous; 
}; 

struct deltaClock{ 
    struct deltaNode* root; 
    struct deltaNode* tail; 
    int size; 
}; 

void initDeltaClock(struct deltaClock **clock){ 
    (*clock) = malloc(sizeof(struct deltaClock)); 
    (*clock)->size = 0; 
} 

void push(struct deltaClock* clock, int numberOfTics){ 
if(clock->root == 0){ 
    // root is empty, initialize it. 
    clock->root = malloc(sizeof(struct deltaNode)); 
    clock->root->tics = numberOfTics; 
    clock->tail = clock->root; 
} 
else { 
    struct deltaNode* newNode = malloc(sizeof(struct deltaNode)); 
    newNode->tics = numberOfTics; 
    struct deltaNode* temp = clock->root; 

    if(newNode->tics < temp->tics){ 
     clock->root->previous = newNode; 
     newNode->next = clock->root; 
     clock->root = newNode; 
    } else { 
     while(newNode->tics > temp->tics){ 
      if(temp->next == 0){ 
       break; 
      } 
      temp = temp->next; 
     } 

     if(temp->next == 0 && newNode->tics > temp->tics){ 
      clock->tail->next = newNode; 
      newNode->previous = clock->tail; 
      clock->tail = newNode; 
     } 
     else{ 
      temp->previous->next = newNode; 
      newNode->previous = temp->previous; 
      newNode->next = temp; 
      temp->previous = newNode; 
     } 

    } 

} 
clock->size++; 
} 

int pop(struct deltaClock* clock){ 
    struct deltaNode* temp = clock->root; 
     if(temp == 0){ 
     return -1; 
    } 
    int result = temp->tics; 
    clock->root = clock->root->next; 
    clock->root->previous = 0; 
    free(temp); 
    clock->size--; 
    return result; 
} 

void printClock(struct deltaClock* clock){ 
    struct deltaNode* iterator; 
    iterator = clock->root; 
    while(iterator != 0){ 
      printf("\n%d",iterator->tics); 
      iterator = iterator->next; 
    } 
} 


int main(int argc, char* argv[]){ 
    printf("\nHello world."); 
    struct deltaClock* clock; 
    initDeltaClock(&clock); 
    push(clock, 3); 
    push(clock, 2); 
    push(clock, 7); 
    push(clock, 33); 
    push(clock, 221); 
    push(clock, 5); 
    printClock(clock); 
    printf("\npopping %d",pop(clock)); 
    printf("\npopping %d",pop(clock)); 
    printf("\npopping %d",pop(clock)); 
    printf("\npopping %d",pop(clock)); 
    printf("\npopping %d",pop(clock)); 
    printf("\npopping %d",pop(clock)); 
    printf("\npopping %d",pop(clock)); 
    printf("\npopping %d",pop(clock)); 
    printf("\npopping %d",pop(clock)); 
    printf("\npopping %d",pop(clock)); 
    printf("\npopping %d",pop(clock)); 
    printf("\npopping %d",pop(clock)); 
    push(clock, 25); 
    printf("\npopping %d",pop(clock)); 
    printf("\n"); 
} 
+4

+1包括SSCCE([簡短,自足,正確的例子](http://sscce.org/)) - 謝謝。它對我來說再現了一個問題,在'爆裂7'後崩潰。 –

+2

在'pop'中,當你爲'clock-> root-> next'賦值之後,你不檢查'clock-> root'是不是'NULL'。另外,對於指針,它可以使用'NULL'而不是'0'。 – Kninnug

+0

在C++中,通常使用0;我在C中大部分時間都使用0,但是如果某些代碼使用NULL,我會繼續使用NULL(一致性比拼寫空指針更重要)。 –

回答

2

對於它的價值,這個代碼運行合理的三立:

#include <stdio.h> 
#include <stdlib.h> 

struct deltaNode 
{ 
    int tics;     // source 
    struct deltaNode *next; 
    struct deltaNode *previous; 
}; 

struct deltaClock 
{ 
    struct deltaNode *root; 
    struct deltaNode *tail; 
    int size; 
}; 

void initDeltaClock(struct deltaClock * *clock); 

void initDeltaClock(struct deltaClock * *clock) 
{ 
    (*clock) = malloc(sizeof(struct deltaClock)); 
    (*clock)->size = 0; 
} 

void push(struct deltaClock *clock, int numberOfTics); 

void push(struct deltaClock *clock, int numberOfTics) 
{ 
    if (clock->root == 0) 
    { 
     // root is empty, initialize it. 
     clock->root = malloc(sizeof(struct deltaNode)); 
     clock->root->tics = numberOfTics; 
     clock->tail = clock->root; 
    } 
    else 
    { 
     struct deltaNode *newNode = malloc(sizeof(struct deltaNode)); 
     newNode->tics = numberOfTics; 
     struct deltaNode *temp = clock->root; 

     if (newNode->tics < temp->tics) 
     { 
      clock->root->previous = newNode; 
      newNode->next = clock->root; 
      clock->root = newNode; 
     } 
     else 
     { 
      while (newNode->tics > temp->tics) 
      { 
       if (temp->next == 0) 
        break; 
       temp = temp->next; 
      } 

      if (temp->next == 0 && newNode->tics > temp->tics) 
      { 
       clock->tail->next = newNode; 
       newNode->previous = clock->tail; 
       clock->tail = newNode; 
      } 
      else 
      { 
       temp->previous->next = newNode; 
       newNode->previous = temp->previous; 
       newNode->next = temp; 
       temp->previous = newNode; 
      } 
     } 
    } 
    clock->size++; 
} 

int pop(struct deltaClock *clock); 

int pop(struct deltaClock *clock) 
{ 
    struct deltaNode *temp = clock->root; 
    if (temp == 0) 
     return -1; 
    int result = temp->tics; 
    clock->root = clock->root->next; 
    if (clock->root != 0) 
     clock->root->previous = 0; 
    free(temp); 
    clock->size--; 
    return result; 
} 

void printClock(struct deltaClock *clock); 

void printClock(struct deltaClock *clock) 
{ 
    struct deltaNode *iterator; 
    iterator = clock->root; 
    while (iterator != 0) 
    { 
     printf(" %d", iterator->tics); 
     iterator = iterator->next; 
    } 
    putchar('\n'); 
} 

int main(void) 
{ 
    printf("Hello world.\n"); 
    struct deltaClock *clock; 
    initDeltaClock(&clock); 
    push(clock, 3); 
    push(clock, 2); 
    push(clock, 7); 
    push(clock, 33); 
    push(clock, 221); 
    push(clock, 5); 
    printClock(clock); 
    printf("popping %d\n", pop(clock)); 
    printf("popping %d\n", pop(clock)); 
    printf("popping %d\n", pop(clock)); 
    printf("popping %d\n", pop(clock)); 
    printf("popping %d\n", pop(clock)); 
    printf("popping %d\n", pop(clock)); 
    printf("popping %d\n", pop(clock)); 
    printf("popping %d\n", pop(clock)); 
    printf("popping %d\n", pop(clock)); 
    printf("popping %d\n", pop(clock)); 
    printf("popping %d\n", pop(clock)); 
    printf("popping %d\n", pop(clock)); 
    push(clock, 25); 
    printf("popping %d\n", pop(clock)); 
    printf("\n"); 
} 

它產生:

Hello world. 
2 3 5 7 33 221 
popping 2 
popping 3 
popping 5 
popping 7 
popping 33 
popping 221 
popping -1 
popping -1 
popping -1 
popping -1 
popping -1 
popping -1 
popping 25 

主要的變化不是設置clock->root->previous = 0;除非clock->root不爲空。

輔助更改將新行添加到打印語句的末尾,並從頭開始刪除它們。列表水平打印,每行多個數字,而不是每行一個數字。

所示的代碼編譯乾淨地使用:

gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \ 
    -Wold-style-definition pl.c -o pl 

需要的函數聲明與這些選項乾淨編譯;他們總體上是個好主意。另一種方法是使函數全部爲靜態,這對單文件程序也適用。爲了使代碼乾淨地編譯,唯一的改變是添加函數原型,並用main(void)代替main(int argc, char **argv) - 做得很好,那是非常好的。

+0

感謝Jonathan的幫助! – idungotnosn

2

除了給出的其他建議,在處理指針時,總是將它們初始化爲NULL或其最終值是一個不錯的主意,不要讓它們懸空。

例如,在initDeltaClock,(*clock)->root(*clock)->tail未被初始化。這意味着,在第一push電話,甚至if (clock->root == 0)檢查將是無效的,因爲clock->root尚未初始化爲0

這裏有一個建議改進:

void initDeltaClock(struct deltaClock **clock){ 
    (*clock) = calloc(sizeof(struct deltaClock)); /* <-- zero out entire contents after alloc */ 
} 

這同樣適用於結構這是malloc'push',你可以使用calloc而不是malloc來確保返回的塊清零,或者你應該明確地設置結構的指針爲零。

此外,如果這不僅僅是一個玩具項目,總是檢查分配函數的返回值以檢查內存不足錯誤。