2017-09-19 34 views
-2

//它目前還不是一個非常成熟的LINK-Stack,我會更新它。 我試圖釋放linklist-style堆棧中的每個節點時遇到此錯誤:銷燬(免費)鏈表式堆棧中的所有東西?

根據解決方案1,這是一個可編譯但不可執行的腳本。也許我的問題發生時,我想分配一個地址(* S),但(* S)已釋放ALREADY?

關於破壞函數,我想釋放之前分配給(S)的RAM中的每個節點,使RAM可重用。

那麼爲什麼第一個功能不可用?我不知道在C中刪除一個變量,我的意思是刪除它的地址。也許通常的變量不能通過FREE()釋放? PPS:當我使用free()時,我認爲它只是釋放RAM,但保留可能指向NULL或somwhere的變量的名稱或標識符,這是危險的,但在Solution1中,似乎我必須這樣做。

//IDE:Dev C++ 5.11 
#include<stdio.h> 
#include <stdlib.h> 
typedef int ElemType; 

typedef struct Stack 
{ 
    struct Stack *next; 
    ElemType data; 
} Stack,*LinkStack; 

int InitStack(LinkStack *S) { 
    *S = (LinkStack)malloc(sizeof(struct Stack)); 
    if(!*S) return -1; 
    (*S)->next=NULL; 
    (*S)->data =0; 
    printf("Maybe successfully initialized.\n"); 
    return 0; 
} 

int Push(LinkStack *S, ElemType e) 
{ 
    LinkStack pt = (LinkStack)malloc(sizeof(struct Stack)); 
    LinkStack newpt = (LinkStack)malloc(sizeof(struct Stack)); 
    newpt->data = e; 
    pt = (*S)->next; 
    int number = 0; 

    if (!pt) 
    { 
     printf("#a one time \n"); 
     (*S)->next = newpt; 
     (*S)->data++; 
     return 1; 
    } 
    else 
    { 
     while (number < (*S)->data) 
     { 
      pt = pt->next; 
      number++; 
     } 
     pt->next = newpt; 
     newpt->next = NULL; 
     (*S)->data++; 
     return 0; 
    } 
} 

int StackTraverse(LinkStack S) 
{ 
    LinkStack pt = (LinkStack)malloc(sizeof(struct Stack)); 
    pt = (S)->next; 
    while (pt) 
    { 
     printf("%d__", pt->data); 
     pt = pt->next; 
    } 
    return 0; 
} 

Solution1: //unavailable 
void DestroyStack(LinkStack *S) 
{ 
    while (*S) 
    { 
     LinkList pt = (*S)->next; 
     free(*S); 
     (*S) = pt; 
    } 
    printf("Node destroyed!\n"); 
} 

int main() 
{ 
    LinkStack Sb; 
    InitStack(&Sb); 
    ElemType *e = (ElemType *)malloc(sizeof(ElemType)); 
    while (scanf("%d", e)) 
    { 
     Push(&Sb, *e); 
     printf("you have entered : %d.\n", *e); 
    } 
    free(e); 
    printf("%d\n", Sb->next->next->data); 
    StackTraverse(Sb); 
    DestroyStack(&Sb); 
    if (!Sb) 
    { 
     printf("succeed\n"); 
    } 
    return 0; 
} 

於是我想出了另一種功能!使用遞歸,但是當我插入3個節點的linklist-style堆棧,似乎「LinkStack破壞」打印6次。當我插入4個節點時,它會打印7次。

solution2: //available ,but not work well 
void DestroyStack(LinkStack *S) { 
    while(*S){ 
     LinkStack pt=(*S); 
     (*S)=(*S)->next; 
     printf("#a\n"); 
     DestroyStack(S); 
    } 
    printf("LinkStack Destroyed!"); 
} 

謝謝你的幫忙!

+0

OOPS !!!!我把solution1和solution2放在一個錯誤的地方,一個是可用的,另一個不可用。 – justinRen

+0

請[編輯]你的問題,告訴我們你做了什麼樣的調試。我希望你已經在Valgrind或類似的檢查器中運行你的[mcve],並且已經使用例如GDB的調試器進行了調查。確保你也啓用了一整套編譯器警告。這些工具告訴你什麼,他們缺少什麼信息?並閱讀Eric Lippert的[如何調試小程序](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/)。 –

+0

@ TobySpeight,對不起,我隨便上傳了一個問題。我會按照你的建議,並提出更好的問題.... 0.0謝謝你的建議。 – justinRen

回答

0

您的整個代碼是有問題的,也許是因爲您不明白mallocfree真的在做什麼。

  • malloc分配一定大小的塊並給出該存儲器的句柄。該句柄是一個指針。這意味着在創建對象時只能調用malloc。在你的代碼中,你應該叫它的唯一地方是Push,因爲你創建了一個新節點。
  • 您不需要爲僅穿過堆棧的指針分配內存。尤其是,這樣的事情:

    LinkStack pt = malloc(sizeof(struct Stack)); 
    pt = (S)->next; 
    

    是錯誤的:你分配內存,並立即將其分配給pt失去句柄。拋出malloc並只保留第二行。

  • free給出先前分配回系統的內存。每個malloc需要對應的free。如果不這樣做,則稱爲內存泄漏。
  • 一旦您在指針上調用free,就可能無法再訪問它後面的數據。系統功能free不會將指針設置爲NULL,所以這是您必須注意的事項。
  • 空堆棧是沒有節點的堆棧。因此分配虛擬節點是毫無意義的。您的堆棧由指向其頭節點的指針定義。你可以只初始化該節點NULL

    Stack *Sb = NULL; 
    

    同樣,你可以檢查是否還有堆棧上的項目有:

    if (Sb) ... 
    
  • 這更多的是一種風格的問題:它被認爲是不好練習到typedef帶走指針性質。你可以使用typedef這個結構體,而不是LinkStack,只需要使用Stack *,這樣一看就知道你正在處理一個指針。

  • main,您執行以下操作:

    printf("%d\n", Sb->next->next->data); 
    

    這是危險的,因爲你不知道用戶是否已進入至少三個項目做。在解引用之前,您必須檢查指針NULL

讓我們把這個付諸實踐:推動手段來創造一個新的節點,並在頭部插入,使新的頭是新的節點:

typedef int ElemType; 

typedef struct Stack Stack; 

struct Stack { 
    Stack *next; 
    ElemType data; 
}; 

void Push(Stack **S, ElemType e) 
{ 
    Stack *newpt= malloc(sizeof(*newpt)); 

    newpt->data = e; 
    newpt->next = (*S); 
    *S = newpt; 
} 

你的代碼實現的破壞堆棧,但更多的時候,堆棧會耗盡py彈出的東西。因此,讓我們imlement說:

ElemType Pop(Stack **S) 
{ 
    ElemType res; 
    Stack *rem = *S; 

    if (*S == NULL) { 
     fprintf(stderr, "Stack underflow\n"); 
     exit(1); 
    } 

    res = (*S)->data; 
    *S = (*S)->next; 
    free(rem); 

    return res; 
} 

注意我們必須保持數據和舊指針的副本,因爲free荷蘭國際集團的數據碟剎它無法訪問。

現在我們可以重寫破壞函數:我們彈出堆棧中的物品,直到它耗盡。

void DestroyStack(Stack **S) 
{ 
    while (*S) Pop(S); 
} 

最後,穿越功能,不分配任何東西:

void StackTraverse(const Stack *S) 
{ 
    while (S) { 
     printf("%d ", S->data); 
     S = S->next; 
    } 

    puts(""); 
} 

此功能僅檢查堆棧;它並沒有完成它,所以它足以通過恆定的頭腦。最後,主功能:

int main(){ 
    Stack *Sb = NULL;   
    ElemType e; 

    while (scanf("%d", &e) == 1){ 
     Push(&Sb, e); 
    } 

    StackTraverse(Sb); 
    DestroyStack(&Sb); 

    return 0; 
} 

元素類型僅僅是一個int,所以它是一個位矯枉過正的爲它動態分配內存。使用自動變量更容易。

該程序結束後,所有分配的塊都被釋放。

+0

首先非常感謝你這麼詳細回答,我知道我的代碼對於某人來說看起來如此混亂,但是感謝您耐心地閱讀我的腳本並回復這麼長的爭論。因此,這裏是我的問題,是否可以通過指針釋放分配給堆棧的內存,我的意思是,你似乎沒有將momery分配給rem,但你使用free()! – justinRen

+0

你的答案就是我的意思!刪除內存。而且我還學到了很多關於釋放由malloc()分配給變量的內存的獨特方法!謝謝 ! – justinRen

-1

您不會在解決方案1中調用free(pt),它將進入所有節點的循環,並且不釋放任何東西。

A free()在C中釋放指針指向的內存,指針仍然存在於內存中,因此一般程序員編寫一個封裝函數,釋放內存並將指針指向NULL。

+0

感謝您的諮詢!但事實上,我確實將內存分配給了InitStack()中的堆棧,這意味着我可以使用free。 – justinRen

0

您的解決方案1是錯誤的。

void DestroyStack(LinkStack *S){ 
    if(S){ 
     LinkStack pt = S; 
     S = S->next; 
     free(pt); 
     printf("#a\n"); 
     DestroyStack(S); 
     printf("LinkStack Destroyed!"); 
    } 
} 

請注意,你傳遞指針*S,所以不要混用->和引用操作(一元*)。還請記住free,無論你用malloc分配了什麼。

對於解決方案2,正確的代碼應該是這樣的:

void DestroyStack(LinkStack *S){ 
    while(S){ 
     LinkStack pt = S->next; 
     free(S); 
     S = pt; 
    } 
    printf("Node destroyed!\n"); 
} 

記住,S->next相當於(*S).next,不要混合起來。也不要混合指針((*S)=pt是絕對錯誤的)。 S是一個指針,而*S是一個用戶定義的結構。您不能指定結構的指針。

+0

,呃.........首先,感謝您回答我的問題,實際上我錯誤地解決了方案1和方案2,使用Recovered解決方案(原來的解決方案1)實際上是正確的。並且原始解決方案2是錯誤的。但是S實際上是一個**堆棧,所以我認爲可能將** Stack pt分配給** Stack S.So對不起,因爲我在編輯問題時遇到了錯誤。 @iBug – justinRen

+0

@justinRen直接打中文吧,拼音看起來好累 – iBug

+0

就是我在輸入的時候把Solution1和Solution2搞反了,使用迭代的那個函數其實是可以運行的 – justinRen

0

in soluting1,無論真假在哪裏,你的代碼打印「destory」,因此你插入的時間不等於你destory.it的邏輯錯誤,你也需要免費的時間,你差不多完成了。 我不擅長英語,希望你能理解我

+0

是的....我明白了,當我發佈這個問題時我犯了一個錯誤。我錯誤地解決了方案1和解決方案2,我很抱歉。謝謝! – justinRen