2

PythonからCに来ました。Pythonには、文字列を操作するための楽しく単純な白い手袋のアプローチがあります。Cで配列を使用すればするほど、特定の機能を備えていると便利だと思います。特定の操作を行う必要があるたびにこれを行うためのループを作成するのではなく、これを行うためのライブラリを作成することにしました。

それで、私が図書館を持っていて、呼び出しが次のようになっているとしましょう:

char* new_array = meatSlicer(old_array, element_start);

変更したい配列にポインターを渡し、ポインターが返されることを期待し、スライスする要素を示しています。

meatSlicer(はい、私は悪い名前の吸盤です)がスライサー内でローカルに作成された配列へのポインターを返す場合、そのポインターは悪いポインターになります。だから、meatSlicer()私はこれを持っています:

    ... manipulation before the below ...

    char *heap_the_Array;     /* put it on the heap to pass it back to caller */
    heap_the_Array = malloc((size + 1) * sizeof(char));

    int i;                
    for (i = 0; i <= (size + 1); i++){           /* make it so... again */

            heap_the_Array[i] = newArray[i];     /* newArray is the local */

    }

    return heap_the_Array;                       /* return pointer */

私の質問は、free()新しい配列を使用できるように、呼び出し元の関数に所有権を適切に戻しているかどうかです。ヒープ上の配列へのポインタを渡すだけで十分ですか?

4

7 に答える 7

5

はい、ローカル変数をmallocメモリの-ed領域にコピーするとうまくいきます。ループをの呼び出しに置き換えてmemcpy、コードサイズを減らすことができます。書く

memcpy(heap_the_Array, newArray, size+1);

それ以外の

int i;                
for (i = 0; i <= (size + 1); i++){           /* make it so... again */
        heap_the_Array[i] = newArray[i];     /* newArray is the local */
}
于 2013-01-17T21:17:42.183 に答える
3

はい、所有権を呼び出し元の関数に適切に譲渡しています。この所有権へのアプローチは、Cプログラマーによって頻繁に使用されることはありませんが、時々発生します(strdupそして、GNUishasprintfは広く知られている例です)。

ヒープに割り当てられた配列を最初から操作して、コピーする必要をなくすこともできます。

ちなみに、それ自体をコピーする時点では、コードにバグがあります。の本体for (i = 0; i <= (size + 1); i++)が呼び出されるsize+2回数です。別の答えが示唆するように、size引数を使用memcpyすると、実際に自分で使用するよりもエラーが発生しにくくなります。

そして最後sizeof(char)に、ANSI Cでは常に1です。これを掛けないでください、

于 2013-01-17T21:21:18.987 に答える
2

はい、meatSlicerはheap_the_Arrayで実行され、呼び出し元に属します。したがって、呼び出し元は、他の誰かに所有権を渡さない限り、その配列を削除できる(そして削除しなければならない)唯一の人です。この所有権のアイデアは、あなたが何らかの形で定義する必要があるものであり、トラブルを回避し、メモリリークモンスターによってスライスされることを回避するために、それと一致している必要があります。

于 2013-01-17T21:18:21.913 に答える
1

所有権がどのように譲渡されるかが明確に説明されています。しかし、私は「より伝統的な」アプローチを提案したいと思います。あなたのコードは私がPythonで喜んで行うことと非常によく似ていますが、CはPythonではありません(そしてPythonはCではありません!)。新しい言語を学ぶことの一部は「その言語で物事がどのように行われるか」を学ぶことです。Cを学んでいるばかりのプログラマーは、あちこちでmallocを呼び出すことに飛びつく傾向があります。そうしないようにしてください。

関数に配列を割り当てさせる代わりに、呼び出し元のコードに配列を渡します。この配列には、コピーしたいもののためのスペースがあります。次に、実際に取得した要素の数を返します。たとえば、次のようになります。

 TYPE new_array[some_size];
 int max_size = sizeof(new_array) / sizeof(new_array[0]);
 int actual_size;

 actual_size = meatSlicer(old_array, new_array, element_start, max_size);

mallocを使用してnew_arrayを作成する場合は、もちろん次のようにすることができます。

 TYPE new_array = malloc(some_size * sizeof(TYPE));
 int max_size = some_size;
 int actual_size;

 if (new_array == NULL) panic();    // Do something useful here. 

 actual_size = meatSlicer(old_array, new_array, element_start, max_size);

 ... 

 free(new_array);

オーバーヘッドが少なく、「後で解放することを忘れないでください」という必要性が少ないため、固定サイズの配列を使用する方がはるかに好きです。後者は、特にコードが少し複雑になり、いくつかの呼び出しがある場合に、コードで一般的な問題です。関連するレベル-そして、1つの関数に複数のアイテムを割り当てる場合、たとえば、後の割り当てが失敗した場合は、最初のアイテムをクリーンアップすることを忘れないでください。人生を複雑にします...

于 2013-01-17T22:02:35.407 に答える
0

ヒープに割り当てられたオブジェクトへのポインタを返すことはできますが、文字配列を終了するNULLを忘れることができるという意味ではありません:)。

それは機能します。末尾の「\0」をミックスに追加することを忘れないでください。また、終了したらfree()char配列に追加することを忘れないでください。

于 2013-01-17T21:18:27.363 に答える
0

はい、関数が戻ると、スタックに割り当てられた変数のみが自動的に「解放」され、ヒープに配列が正しく割り当てられ、その配列へのポインターが正しく返されます。

具体的には、ポインタ変数heap_the_Arrayがスタックに割り当てられ、その値のコピーが返されます。

于 2013-01-17T21:15:19.530 に答える
0

配列が文字列であると仮定すると、バグのあるコードを1行に置き換えることができます。

return strdup(newArray);
于 2013-01-17T21:34:01.777 に答える