2011-10-05 42 views
14

比方說,我有這個struct在ANSI C:ANSI C在創建結構時是否必須使用malloc()?

typedef struct _point 
{ 
    float x; 
    float y; 
} Point; 

而這個函數來創建這個struct

Point createpoint(float x, float y) 
{ 
    Point p; 
    p.x = x; 
    p.y = y; 
    return p; 
} 

這讓我創建這個功能即struct

int main() 
{ 
    Point pointOne = createpoint(5, 6); 
    Point pointTwo = createpoint(10, 4); 
    float distance = calculatedistancefunc(pointOne, pointTwo); 

    /* ...other stuff */ 

    return 0; 
} 

有人告訴我這段代碼無效,因爲struct沒有n在返回之前在createpoint(float x, float y)函數中獲得malloc'd,並且struct將被刪除。 但是,當我使用我的struct這樣,它似乎並沒有被刪除。

所以我的問題是: 我必須要malloc這個struct,爲什麼?/爲什麼不?

回答

13

無論你在做什麼都是完全正確的。聲明 - 在功能

return p; 

返回複製局部變量p。但是如果你想要在該函數中創建相同的對象,那麼你需要malloc它。但是,您以後需要free

Point createpoint(float x, float y) 
{ 
    Point p; 
    p.x = x; 
    p.y = y; 
    return p; 
} // p is no longer valid from this point. So, what you are returning is a copy of it. 

但是 - 在功能

Point* createpoint(float x, float y) 
{ 
    Point *p = malloc(sizeof(Point)); 
    p->x = x; 
    p->y = y; 
    return p; 
}// Now you return the object that p is pointing to. 
+0

這是恕我直言的那種病態建議。如果你想做內存管理的權利,你不應該返回一個指向你的函數分配的dinamically分配結構的指針。您應該在第三個參數中請求預先分配的指針,並將其填充到您的方法中。 – mg30rg

+0

@ mg30rg當你可以在函數中完成並返回它時,爲什麼要傳遞一個預先分配的結構指針? – Houssni

+3

@YassineHoussni - 由於您比編寫代碼更可能會讀取您的代碼,所以在編寫舒適性時代碼可讀性更重要。如果將內存分配和釋放保留在同一個塊中,則內存泄漏將變得更加困難,因爲資源僅保留在需要的確切時間段,並且每次的清理(即:'malloc()'/'getmem() '/'new')與解除分配('free()'/'freemem()'/'delete')配對。你可以很容易地發現沒有delete的'new',但是你會發現'createpoint()'沒有'delete'嗎?維護程序員會這樣做嗎? – mg30rg

7

您可以在堆棧上返回struct,您的代碼有效。如果你想返回一個指向局部變量的指針,會發生問題,但這不是你正在做的,你正在返回一個副本,沒關係。

+2

但是你應該關心內存使用情況,如果你使用更大的結構遵循相同的過程,因爲每個字段在返回時都被複制。在那個具體情況下,這不應該是一個問題。 –

+1

@Kernald - 存在內存使用問題,性能問題,堆棧深度問題,但與OP的直接問題無關。它**是一個有效的C代碼。 – littleadv

+0

感謝大家的明確答案, 但我似乎無法理解爲什麼'通過引用'比'傳遞值'更有效率的內存。我的意思是,這兩種方式在結構中存儲相同數量的數據? –

3
Point createpoint(float x, float y) 
{ 
    Point p; 
    p.x = x; 
    p.y = y; 
    return p; 
}/

所有的局部變量都將被刪除after函數返回。

1>通過引用傳遞 所以,如果你正在返回指向此局部變量函數,然後返回後該變量被刪除,以便指針是無效的。

2>按值傳遞 但在這裏你是返回這個局部變量的副本,所以它的安全,因爲那個局部變量是戈納死當函數返回,但返回值的副本將被存儲在接收器變量函數調用函數返回之前。

+0

感謝您的明確解釋,但我現在有一個新的問題。 什麼時候你應該喜歡通過參考傳遞,什麼時候你應該通過價值傳遞? –

+0

當你要malloc在本地函數中的東西,然後通過refference&當你返回的東西局部變量傳遞它的值..更多你可以谷歌它.. !!! –

+0

你也可以提出另一個問題...! –

5

C99允許更好地在棧上創建結構。
鑑於以下結構

typedef struct 
{ 
    float x; 
    float y; 
} Point; 

您可以用下面的語句有點構造風格方式的C++初始化:

Point p = (Point){0.4, 0.5}; 

,因此你既可以縮短你的createpoint或完全廢了:

int main() 
{ 
    Point pointOne = (Point){5, 6}; 
    Point pointTwo = (Point){10, 4}; 
    float distance = calculatedistancefunc(pointOne, pointTwo); 
    //...other stuff 
    return 0; 
} 
0

對返回結構的方法的調用將表現得好像調用者創建了struc的臨時變量在任何其他範圍內都不可見的地方,併爲被調用的函數提供一個指向它的指針。然後被調用函數將把數據放在請求的地方,並且在返回之後調用者將能夠從其新變量中讀取數據。給定一個函數和調用代碼:

StructType BuildStruct(void) 
{ 
    StructType it; 
    it.this=4; 
    it.that=23; 
    return it; 
} 

StructType myStruct; 
myStruct = BuildStruct(); 

很可能至少有一個複製操作,如果不是兩個;聲明return it;可能需要從本地變量it複製到臨時結構,並且可能需要將myStruct的分配從臨時位置複製到myStruct。實際上並不需要兩次複製操作;有些需要一個(可以由調用者或被調用的方法執行),有些不需要,但是複製的必要性取決於調用者和被調用方法的細節。

一種替代設計將是:

void BuildStruct(StructType *it) 
{ 
    it->this=4; 
    it->that=23; 
} 

StructType myStruct; 
BuildStruct(&myStruct); 

這可能會產生碼等效於一個可以希望使用結構型返回變量的最佳代碼,因爲該結構數據將被直接放置到其最終沒有任何結構複製是必要的。

相關問題