2015-02-12 138 views
1

我很難在類項目的一段代碼中找到段錯誤(這部分未敘述)。我正在爲OS類實現一個隊列,並且在add函數中遇到了分段錯誤。C程序分段錯誤

void AddQueue(QElem * head, QElem * item) { 
    printf("WHERE\n"); 
    if(head == NULL){ 
     printf("THE\n"); 
     head = item; 
     //item->next = item; 
     //item->prev = item; 
    } 
    else{ 
     printf("$^&*\n"); 
     (head->prev)->next = item; 
     printf("ARE\n"); 
     item->prev = (head->prev); 
     printf("YOU\n"); 
     item->next = head; 
     printf("FAILING\n"); 
     head->prev = item; 
    } 
    printf("!?!?!?\n"); 
} 

我有我從不同的類調用測試功能...

void TestAddQueue() 
{ 
    printf("********************************************\n"); 
    printf("Begin testing the add test function\n"); 
    printf("********************************************\n"); 

    QElem * queue; 
    InitQueue(queue); 


    for(int i = 0; i < 10; i++) 
    { 
     printf("Adding element %d\n", i+1); 
     QElem * newElem = NewItem(); 
     printf("Changing payload value\n"); 
     newElem->payload = i+100; 
     printf("Adding to the queue\n"); 
     AddQueue(queue, newElem); 
     printf("Item added, payload value = %d\n", queue->payload); 
     printf("The previous payload = %d\n", queue->prev->payload); 

    } 
    for(int i = 0; i < 10; i++) 
    { 
     printf("Rotating list", i+1); 
     RotateQ(queue); 
     printf("Printing element %d\n", i+1); 
     printQElem(queue); 
    } 
} 

這裏是的newitem功能...

QElem * NewItem() 
{ 
    // just return a new QElem struct pointer on the heap 
    QElem * newItem = calloc(1,sizeof(QElem)); 
    newItem->next = newItem; 
    newItem->prev = newItem; 
    newItem->payload = -1; 
    return newItem; 
} 

...這裏是運行程序的輸出...

******************************************** 
Begin testing the add test function 
******************************************** 
Adding element 1 
Changing payload value 
Adding to the queue 
WHERE 
THE 
!?!?!? 
Segmentation fault 

現在,傳遞給add函數的頭指針應該是NULL,因爲它發送給初始化函數,它只是將指針的值設置爲NULL,所以我不認爲這會導致我的問題。

我的猜測是,下面一行是一個導致了問題...

printf("Item added, payload value = %d\n", queue->payload); 

也許當我嘗試獲得有效載荷值,無論是我試圖訪問該結構已不存在或不知怎的,隊列指針被移動到一個無效的空間。任何反饋或在正確的方向推動將不勝感激。

注意:這是在Unix服務器環境(bash)中編譯的,此刻我無法訪問IDE來調試和查看變量。

+0

有你的例子中缺少很多代碼;例如NewItem()。也就是說,我說:看看AddItem中的「(head-> prev) - > next」行:你已經檢查過「head」是非NULL,但沒有檢查到「head-> prev」 NULL – haavee 2015-02-12 09:06:06

回答

2

在C參數中傳遞值的值爲,這意味着它們是複製了。而更改副本當然不會改變原來的。

所以在AddQueue函數,變量head副本,你可以改變,就像你想要的,你最初傳遞給函數的變量將不會發生任何變化。

爲了能夠更改參數,您需要通過引用,C沒有,但它可以通過使用指針來模擬。當然,這意味着要通過引用傳遞指針,必須將指針傳遞給指針。


因此,對於你的代碼它會像

void AddQueue(QElem ** head, QElem * item) { 
    if(*head == NULL){ 
     *head = item; 
    } 
    ... 
} 

... 

AddQueue(&queue, newElem); 

什麼上述變化做的是首先使AddQueue採取指針的指針QElem,從而模擬通副參考成語。要使用原始指針,請使用解除引用運算符*,該運算符爲您提供指針指向的值(在本例中爲原始指針)。然後,爲了將指針實際傳遞給指針,必須在指針變量上使用操作符&的地址。

+0

謝謝@Joachim謝謝你的信息和例子。我花了一些時間和重新考慮,但是我能夠讓我的代碼按預期工作。我也發現這個偉大的網站[鏈接](http://c.learncodethehardway.org/book/)。我將添加適合我的答案的重構代碼。再次感謝,歡呼! – Dave0 2015-02-13 21:00:25

0

head = itemAddQueue函數以外的內容沒有任何影響。如果您將空指針作爲head傳遞給AddQueue,那麼在完成AddQueue之後,該指針仍爲空。

0

感謝@Joachim,我能夠按預期運行我的隊列。請參閱下面的重構代碼。

首先add函數...

//////////////////////////////////////////////////////////////////////////////// 
// 
// Add Queue 
// 
//  Adds a queue item, pointed to by `item`, to the end of the queue pointed 
//  to by `head`. 
// 
//  Note: Tested 2-12-2015 using proj_1.c tests. PASSED -Dave 
// 
//////////////////////////////////////////////////////////////////////////////// 
int AddQueue(QElem ** head, QElem ** item) { 

    //If the queue is empty... 
    if(*head == NULL){ 
     //Point the head to the item. The new item's next/prev were initialized 
     //to point to itself already. 
     *head = *item; 
    } 
    //If there are already elements in the queue... 
    else{ 
     // insert the new element at the end of the list (just to the left 
     // of the head) setting the next and previous values of the 
     // appropriate nodes to the new values. 
     ((*head)->prev)->next = *item; 
     (*item)->prev = ((*head)->prev); 
     (*item)->next = *head; 
     (*head)->prev = *item; 
    } 
    return TRUE; 
} 

接下來的新項目功能...

//////////////////////////////////////////////////////////////////////////////// 
// 
// New Item 
// 
//  Returns a pointer to a new queue element created in heap memory. 
// 
//  Note: Calloc is a more precise way of allocating, but is basically the 
//  same as malloc, the 1 denotes how many of the item to reserve mem for. 
//  -Dave 
// 
//  Note: Tested 2-12-2015 using proj_1.c tests. PASSED -Dave 
// 
//////////////////////////////////////////////////////////////////////////////// 
QElem * NewItem() 
{ 
    // just return a new QElem struct pointer on the heap with values initialized 
    QElem * newItem = calloc(1,sizeof(QElem)); 
    newItem->next = newItem; 
    newItem->prev = newItem; 
    newItem->payload = -1; 
    return newItem; 
} 

現在來測試添加功能...

//////////////////////////////////////////////////////////////////////////////// 
// 
// A test function for the add function. It will create a queue of items 
// and attempt to iterate through them and print the value of the payload 
// 
//////////////////////////////////////////////////////////////////////////////// 
void TestAddQueue(QElem ** queue){ 
    printf("********************************************\n"); 
    printf("Begin testing the add test function\n"); 
    printf("********************************************\n"); 

    InitQueue(&(*queue)); 

    for(int i = 0; i < 10; i++) 
    { 
     printf("Adding element %d\n", i+1); 
     QElem * newElem = NewItem(); 
     printf("Changing payload value\n"); 
     newElem->payload = i+100; 
     printf("Adding to the queue\n"); 
     AddQueue(&(*queue), &newElem); 
     printf("Item added, payload value = %d\n", newElem->payload); 
     printf("The previous payload = %d\n", (*queue)->prev->prev->payload); 

    } 
}