2015-09-06 36 views
0

在某些函數(如* scanf變體)中,有一個參數爲結果佔用內存空間。您也可以在代碼返回地址的地方編寫代碼。有什麼優點,爲什麼以這種奇怪的方式設計功能?C設計:傳遞內存地址或返回

void process_settings(char* data) 
{ 
    .... // open file and put the contents in the data memory 
    return; 
} 

VS

char* process_settings() 
{ 
    char* data = malloc(some_size); 
    .... // open file and load it into data memory 
    return data; 
} 
+1

如果每次調用函數時都不想分配,該怎麼辦? – SLaks

+1

你爲什麼不呢?該函數是否應該被分割並對它自己的內存和malloc調用負責? – Zimm3r

+0

不適用於回傳給調用者的內存。 – SLaks

回答

3

好處是,您可以保留錯誤檢查,狀態指示等功能的返回值,並實際上使用輸出參數發回數據。事實上,使用這種模式,您可以發回任何數量的數據以及返回值,這可能非常有用。當然,通過多次調用該函數(例如,在循環中調用scanf來驗證用戶輸入),則不必每次都有malloc

有效使用此模式的最佳示例之一是函數strtol,該函數將字符串轉換爲long

該函數接受指向字符的指針作爲其參數之一。通常在本地聲明此charendptr並將其地址傳遞給該函數。該函數將返回轉換後的數字,但如果不能,則返回0表示失敗,而且會將傳入的字符指針設置爲遇到的導致失敗的非數字字符。

然後,您可以報告該特定字符上的轉換失敗。

這比使用全局錯誤指示器更好的設計;考慮多線程程序。如果您要調用可能在多個線程中失敗的函數,那麼使用全局錯誤指示符可能是不合理的。

你提到一個函數應該對它自己的內存負責。那麼,scanf不存在創建內存來存儲掃描值。它存在於從輸入緩衝區掃描一個值。該職能的職責非常明確,不包括分配空間。

返回malloc'd指針也不是不合理的。程序員應該謹慎,儘管如此,當他們完成使用時,它是返回的指針。

+0

但是,爲什麼你只是返回一個數組。例如atoi一個int [],int [0]是一個錯誤細節,而int [1]的值是?我想這是因爲我來自python,其中參數是進入函數的東西,返回是爲了所有事情。 – Zimm3r

+0

在C中,你不能返回一個數組,你需要返回一個指向一個數組的指針,這個數組也需要'malloc'。這是'免費'的另一件事情。 :)另外,在一個'int []'數組中,你只能存儲'int's。如果錯誤代碼是一個int,但是我正在填充字符串緩衝區?你不能將兩種不同的類型分解成一個數組。它可能不是直觀的,但這是一個非常有效的設計。 – Purag

+0

我想我的問題是直覺。而不是int []它可能是一個結構。雅它需要malloc,但似乎你得到那個或怪異的論證事情。回報至少讓參數的概念在 - >退出。我不知道我在尋找解決這個問題的設計資源。 – Zimm3r

3

使用一種方法代替其他的決定取決於你打算做什麼。

如果你想修改數組的函數內的保持原始數組中的修改,你應該用你的第一個例子。

如果您要創建自己的數據結構,則必須處理所有操作。如果你想創建一個新的結構,你應該在函數內部分配內存並返回指針。第二個例子。

如果您想從函數中「返回」兩個值,如向量和向量的長度,並且您不想爲此創建結構,那麼可以返回向量的指針並傳遞一個int指針作爲函數的參數。這樣你就可以在函數內修改int的值,並在外部使用它。

char* return_vector_and_length(int* length); 
0

比方說,例如,您想將流程設置存儲在內存中的特定位置。使用第一個版本,您可以將其寫爲process_settings(output_buffer + offset);。你如何做到這一點,你只有第二個版本?如果它是一個非常龐大的陣列,會出現什麼情況?或者,假設您正在編寫一個多線程應用程序,讓所有線程始終調用malloc()將會使他們爭奪堆並序列化程序,因此您想要預先分配所有緩衝區?

你的直覺是在某些情況下是正確的,但:現代操作系統能夠內存映射文件,它確實練得更有效地返回一個指向該文件的內容比標準庫歷史編寫方式,這是glib如何做到的。有時在堆上分配所有緩衝區有助於避免粉碎堆棧的緩衝區溢出。

重要的一點是,如果你有第一個版本,你可以通過調用malloc然後傳遞緩衝區作爲dest參數來得到第二個版本。但是,如果只有第二個,則不能在不復制整個數組的情況下實現第一個。