2014-09-24 69 views
1

我建立一個簡單的垃圾收集器C,與收集malloced指針,並釋放他們都在最後一個空指針鏈表。段錯誤在C垃圾收集

#include "linked_list.h" 

#define MAKE_GC(NAME) \ 
MAKE_LIST(NAME); \ 
static void _throw_away_##NAME() { \ 
    ITERATOR(NAME) = &NAME; \ 
    do { \ 
     free(ITERATOR(NAME)->elem); \ 
    } while ((ITERATOR(NAME) = ITERATOR(NAME)->next) != NULL); \ 
    DESTROY_LIST(NAME); \ 
} 

#define GC_ALLOC(TYPE, TARGET, LEN, GC_NAME) \ 
do { \ 
    TARGET = (TYPE *)malloc(LEN * sizeof(TYPE)); \ 
    PUSH(TYPE *, TARGET, GC_NAME); \ 
} while (0) 

#define GC_FREE(NAME) _throw_away_##NAME() 

以上是垃圾收集器,和下面是linked_list.h

struct linked_list { 
    void *elem; 
    struct linked_list *next; 
}; 

#define ITERATOR(LIST_NAME) _iter_##LIST_NAME 

#define MAKE_LIST(NAME) \ 
struct linked_list NAME = { NULL, NULL }; \ 
struct linked_list *ITERATOR(NAME) = &NAME 

#define PUSH(TYPE, X, LIST) \ 
do { \ 
    ITERATOR(LIST) = ITERATOR(LIST)->next = (struct linked_list *)malloc(sizeof(struct linked_list)); \ 
    *(TYPE *)ITERATOR(LIST)->elem = X; \ 
    ITERATOR(LIST)->next = NULL; \ 
} while (0) 

#define DESTROY_LIST(LIST) \ 
do { \ 
    struct linked_list *l; \ 
    ITERATOR(LIST) = &LIST; \ 
    do { \ 
     l = ITERATOR(LIST)->next; \ 
     free(ITERATOR(LIST)); \ 
    } while ((ITERATOR(LIST) = l) != NULL); \ 
} while (0) 

當我測試此代碼與下面,

#include <stdio.h> 
#include "garbage_collector.h" 

MAKE_GC(char_gc); 

int main() { 
    char *str; 
    int i; 

    GC_ALLOC(char, str, 11, char_gc); 
    for (i = 0; i < 10; i++) { 
     putchar(str[i] = i + '0'); 
    } 
    str[i] = '\0'; 
    putchar('\n'); 
    puts(str); 

    GC_FREE(char_gc); 
    return 0; 
} 

它運行如預期,儘管調試器(gdb和Visual Studio調試器)不斷拋出GC_ALLOC中的段錯誤。這是一段非常短的代碼,我非常惱火,我仍然不知道它出錯的地方。

我想知道在哪裏我的計劃被打破,其他地方實施前解決它。預先感謝您的幫助。

+0

您在哪裏包含'stdlib.h'?你爲什麼要投射'malloc'的返回值? – 2014-09-24 01:49:15

+0

stdlib.h應該包含在兩個頭文件中,並且不會造成問題。我投了malloc,因爲我經常使用C++編譯器進行編譯,特別是Visual Studio。 – xiver77 2014-09-24 02:00:39

回答

2

在你PUSH宏,我不認爲這行是正確的:

*(TYPE *)ITERATOR(LIST)->elem = X; \ 

我想你想是這樣的:

ITERATOR(LIST)->elem = (void *)X; \ 

在代碼中,我得到了賽格故障在這裏:

GC_ALLOC(char, str, 11, char_gc); 

而且這樣的事實:GC_ALLOC做一個的到期,將str作爲X傳遞。一旦str已由上一行正確分配,您希望將指針指定爲elem,但代碼嘗試解除引用elem,然後將指針指定給解除引用的項目。解除引用elem在這一點上是非法的,並且seg故障,因爲它沒有被分配(並且不應該在那一點上)。

之後,你在你的代碼最終GC_FREE有問題,因爲它最終嘗試釋放未分配的指針。當GC_FREE嘗試DESTROY_LIST(gc_Char),它開始與列表中的第一項。但這個項目沒有通過malloc分配(看看MAKE_LIST),所以不能使用free被free'd。所以當我們想要DESTROY_LIST時,我們必須跳過列表中的第一項。以下代碼已修復這些項目,並且似乎對您的測試用例正常工作:

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

struct linked_list { 
    void *elem; 
    struct linked_list *next; 
}; 

#define ITERATOR(LIST_NAME) _iter_##LIST_NAME 

#define MAKE_LIST(NAME) \ 
struct linked_list NAME = { NULL, NULL }; \ 
struct linked_list *ITERATOR(NAME) = &NAME 

#define PUSH(TYPE, X, LIST) \ 
do { \ 
    ITERATOR(LIST) = ITERATOR(LIST)->next = (struct linked_list *)malloc(sizeof(struct linked_list)); \ 
    ITERATOR(LIST)->elem = (void *)X; \ 
    ITERATOR(LIST)->next = NULL; \ 
} while (0) 

#define DESTROY_LIST(LIST) \ 
do { \ 
    struct linked_list *l; \ 
    ITERATOR(LIST) = &LIST; \ 
    l = ITERATOR(LIST)->next; \ 
    while ((ITERATOR(LIST) = l) != NULL) { \ 
     l = ITERATOR(LIST)->next; \ 
     free(ITERATOR(LIST)); \ 
    } \ 
} while (0) 

#define MAKE_GC(TYPE, NAME) \ 
MAKE_LIST(NAME); \ 
static void _throw_away_##NAME() { \ 
    ITERATOR(NAME) = &NAME; \ 
    do { \ 
     free(ITERATOR(NAME)->elem); \ 
    } while ((ITERATOR(NAME) = ITERATOR(NAME)->next) != NULL); \ 
    DESTROY_LIST(NAME); \ 
} 

#define GC_ALLOC(TYPE, TARGET, LEN, GC_NAME) \ 
do { \ 
    TARGET = (TYPE *)malloc(LEN * sizeof(TYPE)); \ 
    PUSH(TYPE *, TARGET, GC_NAME); \ 
} while (0) 

#define GC_FREE(NAME) _throw_away_##NAME() 

MAKE_GC(char, char_gc); 

int main() { 
    char *str; 
    int i; 
    GC_ALLOC(char, str, 11, char_gc); 
    for (i = 0; i < 10; i++) { 
     putchar(str[i] = i + '0'); 
    } 
    str[i] = '\0'; 
    putchar('\n'); 
    puts(str); 
    GC_FREE(char_gc); 
    return 0; 
} 
+0

我還是不明白爲什麼'*(TYPE *)ITERATOR(LIST) - > elem = X;'是一個不正確的行。如果'TYPE'不是一個指針,而是一個'int'或者'char'或者其他東西,它就可以毫無問題地工作。另外'DESTROY_LIST'工作正確的,因爲'MAKE_LIST'總是初始化爲'NULL' – xiver77 2014-09-24 03:44:57

+0

沒關係的第一要素!我的確認識到了這個問題。謝謝。 – xiver77 2014-09-24 04:01:47