2011-10-03 54 views
2

編輯調用看來,這僅僅是一個示例代碼是錯的情況。感謝您解決這個問題,所以。試圖圍繞讓我的頭時,免費使用C

看一下下面的代碼/引自http://staff.um.edu.mt/csta1/courses/lectures/csa2060/c8a.html

//f.c  
#include <stdio.h> 
#include <stdlib.h> 

char *foo(char *); 

main() { 
    char *a = NULL; 
    char *b = NULL; 

    a = foo("Hi there, Chris"); 
    free(a); 

    b = foo("Goodbye"); 
    free(b); 

    printf("From main: %s %s\n", a, b); 
} 

char *foo(char *p) { 
    char *q = (char *)malloc(strlen(p)+1); 
    strcpy(q, p); 
    printf("From foo: the string is %s\n", q);  
    return q; 
} 

如果免費(B)省略了,然後「再見」可以看出,被寫入的位置「嗨,克里斯」 。

我不明白你爲什麼使用在printf()語句中free'd變量之前調用free(事實上,在我的腦海,好像第一次釋放內存將使這一失敗)。

道歉,如果這是一個重複的,不過話說搜索/讀什麼我能找到我仍然在黑暗中。 代碼和報價都是從這裏:http://staff.um.edu.mt/csta1/courses/lectures/csa2060/c8a.html

編輯看來,這僅僅是一個示例代碼是錯的情況。感謝您解決這個問題,所以。

+0

你也可以使用'的strdup(P)',而不是'malloc'和'的strcpy '。只是說... .. :) – Constantinius

+0

@constantinius我敢肯定,有很多方法可以做什麼作者正在做的,我只是想明白他想要在這裏做的點 – heisenberg

+0

我明白,對不起,沒有認識到它不是你的代碼。 – Constantinius

回答

3

你叫free()當你將不需要再次使用的內存。

您的printf()是在您釋放兩個字符串之後出現的,因此您在嘗試打印字符串時調用「未定義行爲」(UB)。有一個溫和的機會,你在main()得到相同的地址都ab,在這種情況下,你只能有存儲空間,當然這兩個字符串之一。但這仍然是UB,任何事情都可能發生。

您只能在printf()main()之後撥打free()

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

char *foo(char *); 

int main(void) 
{ 
    char *a = NULL; 
    char *b = NULL; 

    a = foo("Hi there, Chris"); 
    b = foo("Goodbye"); 

    printf("From main: %s %s\n", a, b); 

    free(a); // Now it is safe to free the memory 
    free(b); 
    return 0; 
} 

char *foo(char *p) 
{ 
    char *q = (char *)malloc(strlen(p)+1); 
    strcpy(q, p); 
    printf("From foo: the string is %s\n", q);  
    return q; 
} 
+0

好吧,那就是我可能是我誤解了樣本中的內容,但我認爲他是在說這是正確的做法(在printf調用之前釋放) – heisenberg

+0

我去讀了足夠多的你引用的頁面看到是的,它聲稱'fc'是處理它的正確方法,這種說法完全是假的 - 在調用'free(free)之後使用指針'a'和'b'是100%不正確的)''記憶,如圖所示,課程材料僅在該示例中獲得F等級 –

+0

感謝Jonathan,非常感謝 – heisenberg

2

當你調用free(a),你指示運行釋放內存的指針變量a指向。當你到達printf時,a不再指向有效的內存。偶然地,b被分配與a曾經有過的相同的內存。 (然後b被釋放了,所以沒有指針是有效的。)

在兩個無效指針的打印字符串是未定義的行爲。偶然的情況下,內存中包含您在前面複製的字符串的內容。

1

釋放後使用變量是一個錯誤。在你的程序中,你在調用free()之後打印這些值,這是錯誤的。如果有效,這是偶然的。

人們普遍認爲是最佳做法,以調用malloc()和free()在相同的功能。在你的例子中,這意味着你調用malloc,將生成的緩衝區作爲參數傳遞給foo(),打印結果並免費調用。

+0

是的,也許我應該已經更清楚了,這是來自教程的示例代碼,不明白他爲什麼說o這樣做。 – heisenberg

+0

實際時,是的 - 但是如果一個函數需要分配一個大小爲調用者未知大小的內存塊,函數調用malloc()並調用者調用free()函數是合理的。非標準的'strdup()'這樣做。當然,調用者要求釋放()分配的內存需要記錄在案。 –

+0

沒有「在釋放後使用變量」這樣的事情,因爲你不能釋放變量。在變量上調用free(例如'free(&p)')會導致UB。當你調用'free(p)'時,*變量'p' *是**而不是**什麼被釋放。它指向的對象,它必須已被[malloc]分配,並且之前沒有被釋放過,就是釋放的對象。 –

0

這在許多層面上都是錯誤的。在foo中,您爲字符串動態分配空間並填充它 - 這很好。

問題是你現在每個字符串都有一個容器(好,內存塊),a和b因爲你在兩個上都調用了foo。你需要這個容器來保存你想要使用它的時間。

因此,直到完成使用後,您才能在a或b上撥打免費電話。你調用它太早(在你的printf()之前),所以你導致了未定義的行爲。對於你所知道的,在你的printf甚至打印它們的內容之前,計算機已經重用了a和b的內存空間。這可能會導致您陷入錯誤或類似的問題。

完成後,在printf後雙方都可以免費打電話。

此外,將指針a和b設置爲NULL,以便您知道它們是空的。在使用/取消引用它們之前,總是檢查你的指針是否有值(非空值),並且你可以節省很多麻煩。

+0

是的,也許我應該已經更清楚了,這是來自教程的示例代碼,我不明白他爲什麼要這樣做。 – heisenberg

1

你一定會得到一個輸出,如:

From foo: the string is Hi there, Chris 
From foo: the string is Goodbye 
From main: 

這根據你的代碼,你解放了你會在最後的printf語句使用變量非常有意義。

我修改您的代碼:

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

char *foo(char *); 

main() { 
    char *a = NULL; 
    char *b = NULL; 

    a = foo("Hi there, Chris"); 

    b = foo("Goodbye"); 

    printf("From main: %s %s\n", a, b); 
    free(a); 
    free(b); 
} 

char *foo(char *p) { 
    char *q = (char *)malloc(strlen(p)+1); 
    strcpy(q, p); 
    printf("From foo: the string is %s\n", q); 
    return q; 
} 

上述程序的輸出是:

From foo: the string is Hi there, Chris 
From foo: the string is Goodbye 
From main: Hi there, Chris Goodbye 
+0

好吧,我實際上沒有運行代碼,因爲我在我的C#日工作,但你在這裏寫的是我如何認爲它應該寫。謝謝。 – heisenberg

+0

你永遠無法釋放內存,然後嘗試使用它! – varunl