當將char *作爲參數傳遞給函數時,被調用的函數是否應該對該字符串進行自由處理?否則,數據會「丟失」,程序會泄漏數據。或者,編譯器以特殊的方式處理char *,以避免每個人都必須一直空閒,並自動刪除它,使其超出範圍?我將「字符串」傳遞給該函數,因此不會將實例傳遞給已存在的char *。或者應該使用char []來代替?只是覺得非常愚蠢的是爲參數輸入設置一個固定的限制。char *作爲函數的參數C
回答
請牢記這一簡單原則:「始終釋放內存在您分配的相同級別」。換句話說,函數不應該嘗試釋放它本身沒有分配的內存。一個簡短的例子來闡明這一點:
#include "graphics.h"
// The graphics API will get a Canvas object for us. This may be newly allocated
// or one from a pool of pre-allocated objects.
Canvas* canvas = graphics_get_canvas();
// If draw_image() frees canvas, that violates the above principle.
// The behavior of the program will be unspecified. So, just draw the image
// and return.
draw_image (canvas);
// This is also a violation.
// free (canvas) ;
// The right thing to do is to give back the Canvas object to the graphics API
// so that it is freed at the same 'level' where it was allocated.
graphics_return_canvas (canvas);
注意,該函數的名稱不是graphics_free_canvas()
之類的東西,因爲API可以選擇釋放它或將其返回到池重用。關鍵是,假定我們沒有創建資源的所有權,這是一個非常糟糕的編程實踐,除非我們另有具體說明。
這是如何與malloc()和strcmp()的喜歡?他們打算在不同的層面上被釋放。事實上,free()本身不會釋放內存:-) – paxdiablo 2010-07-20 06:38:42
@paxdiablo,strcmp()?你是說strdup()?如果是這樣,我不明白他們是如何在不同的層面上獲得釋放的。 strcmp()當然不會分配任何東西。 – 2010-07-20 06:41:41
@HH,我不認爲他真的是這個意思。答案中概述的原則(清理你自己的混亂)是健全的。避免我以前的一位同事使用的構造函數,他的函數返回一個char *給(文本)答案,在這種情況下,您必須釋放它,或者返回錯誤消息,在這種情況下,您不得釋放它。 – 2010-07-20 06:55:35
這聽起來像你問這個用法:
void foo(char* str);
foo("test string");
這是一個特殊情況; "test string"
是存儲在可執行文件中的字符串表中的常量字符串,不需要釋放。 foo
實際上應該採取const char*
來說明,並允許字符串文字存儲在非恆定char*
S IN C++
爲了擴大這一點,字符串文字「測試字符串」以* static extent *的char(C++中的const char)的12元素數組的形式存在,這意味着它的內存在程序啓動時分配並保存到程序退出。當您將字符串文字作爲函數參數傳遞時,編譯器**不會**創建字符串的新實例;相反,它傳遞一個指向現有實例的指針。 – 2010-07-20 18:36:10
已被棄用,軟鍵功能是否應該做一個free
與否取決於誰擁有的字符串。此代碼是完全有效的,不會導致任何內存泄漏:
int main()
{
char* s = malloc(.....);
f(s);
free(s);
}
的free
可以內部功能f
,如果它需要字符串的所有權進行爲好。但是請注意,由於您假定傳遞給函數f
的字符串始終使用malloc
或相關函數在堆上進行分配,因此這很危險。如果用戶將指針傳遞給堆棧中分配的字符串,則程序將表現出不可預測的行爲。
一般情況下,編譯器不會對字符串的內存管理進行任何特殊處理。從編譯器的角度來看,它只是一堆字符。
不只是一個堆棧分配的字符串。如果你傳遞'f()'字符串,並且'f()'試圖釋放它,你也會遇到麻煩。 – ptomato 2010-07-20 08:58:47
有時API需要一個分配的緩衝區,並且它的功能所有者可以調用該API釋放它。
myFunc()
{
char *error = malloc(<max size of error string>);
foo(error);
//Free the pointer here
free(error);
}
像GLIB一些API API的預期指針的聲明的變量
myFunc()
{
GError *error;
glib_api(&error);
if (error)
{
printf("Error %s", error-> message);
// can use glib API to free if error is NON NULL but message is allocated by GLIB API
g_error_free(error);
}
}
所以,即使你還沒有分配的內存,你需要做的釋放,而使用標準庫的變量地址。
分配的一塊內存(如果未釋放)會導致多進程環境中的內存較小,從而降低系統的性能。
看來你已經習慣了OOP風格。我不喜歡OOP,對我來說,如果我在分配後獲得一個對象的副本,會很奇怪。在這種情況下,字符串在內存中的某處,其地址以char *形式發送,而不是整個字符串。 另外,請注意,您可以釋放()只有malloc()返回的指針,並且只有一次。
用普通的char *
,我會建議總是編寫一個策略的代碼,調用者「擁有」字符串,並負責釋放它,如果它是由malloc
獲得的。另一方面,當然可以設想C中的「僞值傳遞」字符串對象,作爲結構實現,其中策略規定在傳遞字符串時必須放棄字符串的所有權(或者先複製並傳遞重複)作爲論據。如果這個實現使用引用計數的存儲來傳遞對象只是對存儲的引用,那麼「重複」操作僅僅是一個引用計數增量加上簡單的包裝器結構分配(或即使通過值結構)。
指向char作爲函數變量的指針是指向相同變量的地址,除非它已被替換爲常量字符串。你的問題不能用簡單的是/否指導來解釋;它取決於上下文。在下面的代碼中,分別在堆和堆棧上分配的結構通過引用傳遞以及字符串char *,並將數據插入到結構中。請注意malloc在使用時的不同,但函數的工作原理完全相同。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// struct with all data within
typedef struct d
{
int number;
char name[50];
}data;
// struct with dynamic char *
typedef struct d2
{
int number;
char *name;
}dynamic_data;
// generic function placing data into struct
void InsertData (data * out, int a, char * b)
{
out->number = a;
strcpy(out->name, b);
}
// generic function placing data into second struct
void InsertData2 (dynamic_data * out, int a, char * b)
{
out->number = a;
strcpy(out->name, b);
}
int main (void)
{
char * text = "some string\0";
int n = 20;
// allocated struct
data stuff;
dynamic_data stuff2;
dynamic_data * stuff3;
// need to allocate pointer within struct only
stuff2.name = (char *) malloc(50 * sizeof(char));
// heap allocated struct
stuff3 = (dynamic_data *) malloc(50 * sizeof(dynamic_data));
// heap allocated sub element char *
stuff3->name = (char *) malloc(50 * sizeof(char));
// this is the data
printf ("Pre insertion data\n");
printf ("s=[%s]\n", text);
printf ("n=%d\n", n);
// this is the function insertting
InsertData (&stuff, n, text);
printf ("Post insertion data\n");
printf ("stuff.name=[%s]\n", stuff.name);
printf ("stuff.number=%d\n", stuff.number);
// this is the function inserting
InsertData2 (&stuff2, n, text);
printf ("Post insertion data\n");
printf ("stuff.name=[%s]\n", stuff2.name);
printf ("stuff.number=%d\n", stuff2.number);
//
// This is the segfault version - if nothing was allocated for pointers into
// this function scope, it would crash
// this is the function insertting under a heap allocated
InsertData2 (stuff3, n, text);
printf ("Post insertion data - dynamic version\n");
printf ("stuff3->name=[%s]\n", stuff3->name);
printf ("stuff3->number=%d\n", stuff3->number);
// free in reverse order
free(stuff3->name);
free(stuff3);
free(stuff2.name);
return 0;
}
- 1. const char *&作爲函數參數C++
- 2. C函數參數char * vs char []
- 3. c,在函數中傳遞char數組作爲參數?
- 4. 用char **參數的C++函數
- 5. char str []和char * str作爲函數參數有什麼區別?
- 6. 在C++中將函數參數作爲函數參數傳遞
- 7. 爲什麼我不能使用char作爲函數的參數?
- 8. 函數指針作爲參數在C
- 9. 傳遞char *作爲參數
- 10. 如何將char數組作爲參數傳遞給C中的函數?
- 11. C指針作爲函數的參數
- 12. C++指針的函數作爲參數
- 13. 作爲函數參數的類C++
- 14. 傳遞C數組爲char *函數參數
- 15. 如何爲在C++中使用'char *'的函數提供'const char *'參數?
- 16. 無法傳遞的char []作爲參數傳遞給函數
- 17. 在C++中傳遞fstream參數作爲函數參數11
- 18. 函數作爲參數
- 19. C++函數指針作爲參數
- 20. C#枚舉作爲函數參數?
- 21. 傳遞char數組作爲參數
- 22. C++,傳遞的n個參數的函數作爲參數
- 23. C++:作爲另一個函數的參數的成員函數
- 24. 作爲參數的函數
- 25. 作爲參數的PHP函數參數
- 26. C函數參數
- 27. 函數作爲函數中的參數
- 28. 作爲函數參數的Python函數?
- 29. PHP函數作爲函數的參數
- 30. 字符串作爲函數中的參數c
邁克爾的良好答案告訴你考慮將字符串存儲在所謂的「靜態存儲器」中 - 這是存儲器在程序映像加載時由操作系統初始化的存儲器。 Naveen的例子和free/malloc自己使用「免費商店」,有時稱爲「堆」。還有「自動存儲」通常作爲「堆棧」來實現。其他存儲可能性是操作系統映射的ABI內存區域,內存映射文件等。一個例子可能是操作系統調用返回當前目錄字符串 - 這個「char *」可能指向OS的每線程數據結構。 – 2010-07-20 06:39:32
您通常不應該爲參數輸入設置固定限制。相反,讓調用者給你一個指針,讓*他們*告訴你*字符串是多長。 – bta 2010-07-20 16:47:22