char* を引数として関数に渡す場合、呼び出された関数はその文字列を解放する必要がありますか? そうしないと、データが正しく「失われ」、プログラムがデータをリークする可能性があります。または、コンパイラによって特別な方法で char* が処理され、誰もが常に解放する必要がなくなり、範囲外になると自動的に削除されますか? 関数に「文字列」を渡すので、既存の char* のインスタンスではありません。または、代わりに char[] を使用する必要がありますか? 引数の入力に一定の制限を設定するのはとてもばかげているように感じます。
7 に答える
この単純な原則を念頭に置いてください。「割り当てたのと同じレベルで常にメモリを解放する」。つまり、関数は、それ自体が割り当てていないメモリを解放しようとすべきではありません。これを明確にするための短い例:
#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 は関数を解放するか、プールに返すことで再利用することを選択する可能性があるため、関数には名前などは付けられていないことに注意してください。重要なのは、特に指示がない限り、作成していないリソースの所有権を想定することは、非常に悪いプログラミング プラクティスであるということです。
関数が a を実行するかどうかは、文字列の所有free
者によって異なります。このコードは完全に有効であり、メモリ リークは発生しません。
int main()
{
char* s = malloc(.....);
f(s);
free(s);
}
文字列の所有権を取得する場合は、free
関数内でも実行できます。f
ただし、関数に渡される文字列は常に関数または関連する関数f
を使用してヒープに割り当てられると想定しているため、危険であることに注意してください。malloc
ユーザーがスタックに割り当てられた文字列へのポインターを渡すと、プログラムは予期しない動作をします。
一般的に、コンパイラは文字列のメモリ管理に対して特別な処理を行いません。コンパイラの観点からは、これは単なる文字の集まりです。
この使用法について尋ねているようです:
void foo(char* str);
foo("test string");
これは特殊なケースです。"test string"
実行可能ファイル内の文字列テーブルに格納されている定数文字列であり、解放する必要はありません。foo
実際にはconst char*
それを説明するために を使用する必要があり、文字列リテラルを非定数 s に格納できるようにすることchar*
は、C++ では非推奨です。
OOP スタイルに慣れているようです。私は OOP が好きではありません。私にとって、代入後にオブジェクトのコピーを取得するのは奇妙です。この場合、文字列はメモリ内のどこかにあり、そのアドレスは文字列全体ではなく char* として送信されます。また、free() できるのは、malloc() によって返されたポインターのみであり、1 回だけであることにも注意してください。
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);
}
}
したがって、変数にメモリを割り当てていなくても、標準ライブラリを使用しているときに解放を行う必要があります。
割り当てられたメモリを解放しないと、マルチプロセス環境でメモリが少なくなり、システムのパフォーマンスが低下します。
plainchar *
では、呼び出し元が文字列を「所有」し、malloc
. 一方、構造体として実装された C の「値による疑似受け渡し」文字列オブジェクトを確かに思い描くことができます。この場合、ポリシーでは、文字列を渡すときに文字列の所有権を放棄する (または最初に複製して複製を渡す) 必要があります。引数として。これは、渡されたオブジェクトが単なるストレージへの参照である文字列に参照カウント ストレージを使用する実装で、「複製」操作が単に参照カウントのインクリメントと自明なラッパー構造体の割り当て (または値渡し構造体でさえ)。