2017-10-10 65 views
-1

我目前正在嘗試學習如何鏈接列表作爲個人項目。我瞭解核心概念,並一直試圖將其實施到c。我的程序看起來應該可以工作,請記住我仍然是編程新手:D在函數中使用雙指針

我創建了一個名爲head的結構指針。 head將指向linked_list中的第一個節點,startPtr將包含head的地址。每次調用函數add時,都會創建一個新節點並在內存中分配一些空間,然後之前創建的節點將指向新節點。

我知道我的程序在哪裏崩潰,但我可以看到爲什麼?它編譯好。上線

(*prevNode)->link = newNode; 

我的代碼崩潰是我看到這個代碼的方式:我通過雙指針startPtr到函數添加 。然後我使用malloc創建了一個新節點。接下來我參考startPtr(它在函數中被稱爲prevNode),它應該包含head的內存地址....對吧?然後我使用「 - >」表達式來指向稱爲鏈接的頭內的結構指針。

程序只是在這一點結束,我不知道爲什麼。我查看了其他鏈表的c代碼,但其中大多數不使用雙指針,他們只是聲明全局結構和指針。我使用GCC作爲我的編譯器。

任何人都知道爲什麼會發生這種情況?

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


// STRUCTURES 

struct node 
{ 
    int data; 
    struct node *link; 
}*head; 

void add(int, struct node **); 


int main() 
{ 
    struct node *head; 
    struct node **startPtr; 
    startPtr = head; 
    struct node *nodePtr; 
    int userInput; 
    int inputData; 


    do{ 
    printf("\n\n1: enter new node\n"); 
    printf("2: Print Nodes\n"); 
    printf("\n\nEnter: "); 
    scanf("%d", &userInput); 
     if (userInput == 1) 
     { 
      printf("\n\nEnter data:"); 
      scanf("%d", &inputData); 
      add(inputData, startPtr); 
     } 

    }while(userInput == 1); 

    // printing linked list 
    nodePtr = head->link; 
    while(nodePtr->link != NULL) 
    { 
     printf("%d\n", nodePtr->data); 
     nodePtr = nodePtr->link; 
    } 
    printf("%d\n", nodePtr->data); 
    return 0; 

}// END main() 

void add(int num, struct node **prevNode) 
{ 
    // assigning memory for a new node 
    struct node *newNode = malloc(sizeof(struct node)); 
    (*prevNode)->link = newNode;   
    newNode->data = num;   
    newNode->link = NULL;   
    prevNode = &newNode; 
}// END add() 

另外我有一個其他問題,我無法找到並在網上回答。當我創建一個指向結構的指針時,例如struct node * ptr ;. structer指針默認存儲它自己的地址。通過它的自我我的意思是結構,所以如果我打印ptr會輸出structer ptr的地址嗎?

+0

除此之外,你的add()函數也被竊聽(它的分配prevNode不會改變調用者的變量)。 – jarmod

+0

對不起,我早上在亂搞,我必須刪除它。我編輯了我的代碼。我是編碼新手,所以我不確定你的意思。我以爲因爲我傳遞了一個指針,所有在該函數中做出的改變都會被寫入指針地址的內存位置。 –

+1

爲什麼重新打開?這是不是重複的「我試圖將數據存儲到單位化指針的地址」?我們不需要解釋爲什麼每天10次沒有意義。存在典型重複是有原因的。 – Lundin

回答

1

除了這個錯字

startPtr = head; 
      ^^^^ 

哪裏有要

startPtr = &head; 
      ^^^^^ 

有幾個問題的代碼。

第一個問題是標題最初沒有初始化。所以取消引用這個指針會導致未定義的行爲。

的第二個問題是,這個循環

do{ 
printf("\n\n1: enter new node\n"); 
printf("2: Print Nodes\n"); 
printf("\n\nEnter: "); 
scanf("%d", &userInput); 
    if (userInput == 1) 
    { 
     printf("\n\nEnter data:"); 
     scanf("%d", &inputData); 
     add(inputData, startPtr); 
    } 

}while(userInput == 1); 

是建立在邏輯上不正確。例如,如果用戶輸入的數字不等於1或2,那麼程序將在退出循環後嘗試輸出列表。

第三個是最初頭可以等於空。所以在功能

(*prevNode)->link = newNode; 

這一說法再次調用未定義的行爲,而且如果*prevNode不等於空,則所有早期的附加節點都將丟失,因爲其參考link被覆蓋。

功能可以從頭部未初始化看看下面的方式

int add(struct node **head, int data) 
{ 
    struct node *newNode = malloc(sizeof(struct node)); 
    int success = newNode != NULL; 

    if (success) 
    { 
     newNode->data = data; 
     newNode->link = *head; 
     *head = newNode; 
    } 

    return success; 
} 
+0

第一個問題是代碼首先不能編譯,因爲它不是有效的C.'startPtr = head;'這些是不兼容的指針類型。該行違反了簡單賦值的約束條件。 – Lundin

+0

@Lundin我認爲這只是一個錯字,因爲從它的帖子來看,這是一個分段錯誤。 –

1
struct node *head; 

從未初始化

startPtr = head; 

初始化爲未初始化的;除此之外,你的整個程序是不確定的。

+0

這就是爲什麼程序崩潰的原因'(* prevNode) - > link = newNode;'這就是爲什麼當數據被複制/掃描/讀取到未初始化的指針時,問題與[崩潰或「段錯誤」 ](https://stackoverflow.com/questions/37549594/crash-or-segmentation-fault-when-data-is-copied-scanned-read-to-an-uninitializ)。 – Lundin

2

很多在這裏解開......這些都是初始化,然後你別名指針,而不是指向一個地址,所以你真的沒有指針的指針,你有相同的指針2

struct node *head; 
struct node **startPtr; 
startPtr = head; 
struct node *nodePtr; 

也許是這樣的:

struct node *head = NULL; 
struct node **startPtr = &head; 
struct node *nodePtr = NULL; 

將是一個更好的開始...然後用C,所以你必須先檢查是否有一個空指針的可能性不能DEREF NULL指針。 ..注意這不會檢查未初始化的垃圾值,該局部變量可以是:

if(startPtr && *startPtr) 
{ 
// now you know you can deref startPtr twice, 
// once to a pointer to an object (which might be null) 
// then after then && you can deref to an actual object 
} 
+0

'startPtr = head;'甚至不是有效的C.這些不是兼容的指針類型。該行違反了簡單賦值的約束條件。 – Lundin