2014-11-20 72 views
2

我按順序運行一堆malloc,並檢查每次以確保它成功。事情是這樣的:C清理錯誤/終止

typedef struct { 
    int *aray; 
    char *string; 
} mystruct; 

mystruct *mystruct_init(int length) 
{ 
    mystruct *foo = malloc(sizeof(int *)); 
    if (!foo) exit(1); 

    foo->array = malloc(length * sizeof(int)); 
    if (!foo->array) exit(1); 

    foo->string = malloc(length * sizeof(char)); 
    if (!foo->string) exit(1); 

    return foo; 
} 

因此,當一個malloc失敗,程序退出而不釋放了以前的。什麼是一些技巧,以確保如果失敗的情況下,程序安全地退出所有分配的內存釋放?

+4

你*真的確定*要支持平臺(讀:裸機,或者至少沒有MMU /虛擬內存和普通堆)在程序退出時,系統不會自動釋放這些內存? – Deduplicator 2014-11-20 22:52:05

+4

刪除是正確的,任何真正的操作系統將釋放分配給您的程序在退出時的所有內存,無論如何。但是,我讚賞你的努力,以便不依賴於這個問題 - 程序經常成爲其他程序的模塊,然後它很重要。 – 2014-11-20 22:55:08

+0

@LeeDanielCrocker:任何自行調用退出/中止的模塊(除非有明確的文件證明這樣做是出於真正的理由,或者當它檢測到不可能的條件時)已經超出了希望。 – Deduplicator 2014-11-20 23:01:07

回答

2

如果你正在設計一個作爲操作系統一部分運行的驅動程序,你需要更仔細地處理這個問題。在這種情況下,經常使用goto。例如

mystruct *mystruct_init(int length) 
{ 
    mystruct *foo = malloc(sizeof(int *)); 
    if (!foo) goto FOO_FAIL; 

    foo->array = malloc(length * sizeof(int)); 
    if (!foo->array) goto ARRAY_FAIL; 

    foo->string = malloc(length * sizeof(char)); 
    if (!foo->string) goto STRING_FAIL; 

    return foo; 

    STRING_FAIL: 
     free(foo->array); 
    ARRAY_FAIL: 
     free(foo); 
    FOO_FAIL: 
     REPORT_ERROR; // user defined behavior 
    return NULL; 
} 

所以,如果說,foo->string沒有分配成功,foo->arrayfoo將相應釋放。如果foo->array失敗,則只有foo將被釋放。當其中任何一個失敗時,函數返回NULL,這允許調用者檢查返回值並決定下一步。

2

這裏是我最喜歡的招數之一:調用exit(...)之後的進程終止後

do { 
    a = malloc(...); 
    if (!a) break; 

    b = malloc(...); 
    if (!b) { 
     free(a); 
     break; 
    } 
} while (0); 

if (!a) { 
    ... 
    return; 
} 

... 

free(b); 
free(a); 
3

大多數現代操作系統將釋放正確的內存。這些操作系統包括:

  • 所有的Unix變種,包括Linux和Mac OS X
  • 所有的Windows版本
  • 所有DOS變種
0

你也可以這樣做,我認爲這是最乾淨的方式,我經常使用它,但是從函數返回,而不是退出程序,因爲系統會釋放內存在出口處。

順便說一下,由於您沒有爲foo分配足夠的空間,所以程序原樣會導致分段錯誤。

typedef struct { 
    int *aray; 
    char *string; 
} mystruct; 

mystruct *mystruct_init(int length) 
{ 
    mystruct *foo = malloc(sizeof(mystruct)); // you need to allocate space for string too 
    if (!foo) 
     return NULL; 
    memset(foo, 0, sizeof(mystruct)); // initialize all members to NULL 

    foo->array = malloc(length * sizeof(int)); 
    if (!foo->array) 
     goto abort; 

    foo->string = malloc(length * sizeof(char)); 
    if (!foo->string) 
     goto abort; 

    return foo; 
abort: 
    if (foo->array) 
     free(foo->array); 
    if (foo->string) 
     free(foo->string); 
    return NULL; 
} 

現在在調用功能,你可以做到這一點乾淨像

mystruct *foo; 

foo = mystruct_init(length /* assuming this is declared and set. */); 
if (!foo) 
    exit(1); 
+0

也'sizeof(char)'總是等於'1'。 – 2014-11-21 10:47:09