関数呼び出し内の Malloc は戻り時に解放されるように見えますか?
質問
最も基本的なケースまでは理解できたと思います。
int main(int argc, char ** argv) {
int * arr;
foo(arr);
printf("car[3]=%d\n",arr[3]);
free (arr);
return 1;
}
void foo(int * arr) {
arr = (int*) malloc( sizeof(int)*25 );
arr[3] = 69;
}
出力は次のとおりです。
> ./a.out
car[3]=-1869558540
a.out(4100) malloc: *** error for object 0x8fe01037: Non-aligned pointer
being freed
*** set a breakpoint in malloc_error_break to debug
>
私の理解が間違っている箇所を誰かが明らかにしていただければ、大変感謝いたします。
解決
ポインタは参照ではなく値で渡されるため、foo 内で arr を使って何をしても、foo 関数の外側では違いが生じません。m_pGladiator が書いたように、1 つの方法は、このようにポインターへの参照を宣言することです (ちなみに、C++ でのみ可能です)。C は参照について知りません):
int main(int argc, char ** argv) {
int * arr;
foo(arr);
printf("car[3]=%d\n",arr[3]);
free (arr);
return 1;
}
void foo(int * &arr ) {
arr = (int*) malloc( sizeof(int)*25 );
arr[3] = 69;
}
別の (より良い個人的な) 方法は、ポインタを引数として渡すのではなく、ポインタを返すことです。
int main(int argc, char ** argv) {
int * arr;
arr = foo();
printf("car[3]=%d\n",arr[3]);
free (arr);
return 1;
}
int * foo(void ) {
int * arr;
arr = (int*) malloc( sizeof(int)*25 );
arr[3] = 69;
return arr;
}
また、ポインタをポインタに渡すこともできます。これが参照渡しの C の方法です。構文は少し複雑ですが、まあ、C はそういうものです...
int main(int argc, char ** argv) {
int * arr;
foo(&arr);
printf("car[3]=%d\n",arr[3]);
free (arr);
return 1;
}
void foo(int ** arr ) {
(*arr) = (int*) malloc( sizeof(int)*25 );
(*arr)[3] = 69;
}
他のヒント
foo に arr を割り当てましたが、そのポインター値は呼び出しスタックに格納されます。これを実行したい場合は、次のように実行します。
void foo( int ** arr) {
*arr = (int *)malloc( sizeof(int) * 25 );
(*arr)[3] = 69;
}
そして main では、単純に foo へのポインタを渡します (foo(&arr) のように)。
foo は int ポインタのローカル コピーを受け取り、それにメモリを割り当て、スコープ外に出るとそのメモリをリークします。
これを修正する 1 つの方法は、foo にポインターを返すようにすることです。
int * foo() {
return (int*) malloc( sizeof(int)*25 );
}
int main() {
int* arr = foo();
}
もう 1 つは、foo にポインターをポインターに渡すことです。
void foo(int ** arr) {
*arr = malloc(...);
}
int main() {
foo(&arr);
}
C++ では、ポインターへの参照を受け入れるように foo を変更する方が簡単です。C++ で必要な唯一の変更は、foo を次のように変更することです。
void foo(int * & arr)
ポインタを値で渡しているため、main 内の arr ポインタは割り当てられたメモリを指していません。これは次の 2 つのことを意味します。メモリ リークが発生しており (いいえ、関数 foo が完了してもメモリは解放されません)、main 内の arr ポインタにアクセスすると、メモリの任意の範囲にアクセスすることになるため、3 が出力されません。 out であるため、free() は機能しません。main 内の arr[3] にアクセスするときにセグメンテーション違反が発生しなかったのは幸運でした。
引数 (arr) が参照 (&) によって渡されない場合、その値を変更することはできません。一般に、ポインタを返す必要があるため、メソッドは次のようになります。
arr=foo();
引数を再割り当てしようとするのは悪い判断です。(&) ソリューションはお勧めしません。