1

重複の可能性:
関数から「ローカル」char* を返すことと、関数から「ローカル」int* を返すことの違い

以下は単純なコードです。3 つの異なる関数[localStrPtr、localIntPtr、localCharPtr]で、それぞれの関数のローカル変数[string、integer、char]へのポインターが返されます。

コード:

#include <stdio.h>

char*  localStrPtr (char*);
int*   localIntPtr (int, int);
char*  localCharPtr (char);

main()
{
    int *pInt;
    char *pChar;

    printf( "localStrPtr = %s\n", localStrPtr("abcd") );

    pInt = (int*) localIntPtr(3, 5);
    printf( "localIntPtr = %d\n", *pInt );

    pChar = (char*) localCharPtr('y');
    printf( "localCharPtr = %c\n", *pChar );
}

char* localStrPtr(char* argu)
{
    char str[20];
    // char* str = (char*) malloc (20);

    strcpy (str, argu);
    return str;
}

int* localIntPtr (int argu1, int argu2)
{
    int local;
    local = argu1 + argu2;
    return (&local);
}

char* localCharPtr (char argu)
{
    char local;
    local = argu;
    return (&local);
}

コンパイルログ:

stringManip.c: In function `localStrPtr':
stringManip.c:27: warning: function returns address of local variable
stringManip.c: In function `localIntPtr':
stringManip.c:34: warning: function returns address of local variable
stringManip.c: In function `localCharPtr':
stringManip.c:41: warning: function returns address of local variable

実行ログ:

localStrPtr =
localIntPtr = 8
localCharPtr = y

ログ ファイルでわかるように、localStrPtr は「ゴミ」を返しますが、localIntPtr と localCharPtr は「期待される」値を返します。

しかし、関数localStrPtrchar str[20]で、 -to->に変更するとchar* str = (char*) malloc (20)、 localStrPtr は文字列 "abcd" を正しく返します。上記の変更が行われた後の実行ログは次のとおりです。

新しい実行ログ:

localStrPtr = abcd
localIntPtr = 8
localCharPtr = y

質問:

[1] 関数 localIntPtr および localCharPtr では、返されたローカル変数アドレスの内容は WORKED ですが、関数 localStrPtr では、正しい値はmalloc で「のみ」返されますが、ローカル char str[20] では返されません。ローカル変数 char および int で動作するのに、なぜ str[20] で動作しないのですか?

[2] COMPILE LOG に、以下の 3 つの関数すべての行が表示されるのはなぜですか?

  • stringManip.c:27: 警告: 関数はローカル変数のアドレスを返します
  • stringManip.c:34: 警告: 関数はローカル変数のアドレスを返します
  • stringManip.c:41: 警告: 関数はローカル変数のアドレスを返します
4

5 に答える 5

8

関数からローカル変数を返すことはできません。ローカル変数はスタック上に存在し、関数が完了すると、そのスタック領域が解放され、次の関数呼び出しで使用できるようになります。

malloc を使用すると、ヒープにメモリが割り当てられます。このメモリは関数が終了しても解放されないため、それを返すことができ、そのメモリは呼び出し元の関数のスペースにまだ割り当てられています (これが malloc がメモリ リークを引き起こす可能性がある理由でもありますが、ローカル配列はそうではありません)。

戻り値は常に値で渡されるため、これは見かけほど明確ではありません。ローカルの int を返すと、その int の値が返され、正常に動作します。ローカル配列を返す場合、その配列へのポインターの値を返しますが、そのポインターがメモリの有用な部分を指していない場合は問題ありません。

于 2013-01-09T00:20:36.500 に答える
3

関数で変数を宣言すると、その関数に対してローカルになるため、その関数が終了すると、すべてのローカル変数が解放されます。自動的に解放されるメモリ空間へのポインターを返しているため、間違いを犯して警告を受けています。malloc を使用すると、プロセスの仮想メモリ (ヒープ) からスペースを要求し、そのメモリに対する責任を負います。要求すると、それを解放する必要があります (必要な場合は解放する必要があります)。

C メモリの割り当てを、後の初期化/割り当ての手段としてのみ考えるのは間違いであり、それ以上のものです。

したがって、2番目の質問については、上記の私の回答でほぼ説明されていますが、基本的にはコンパイラが言っていることです。ローカル関数にのみ属するもののアドレスを返しています。おそらくガベージへのポインターを返しています。

[編集] もう 1 つ: 戻り値と「非参照渡された引数」は変数のコピーであり、「THE」変数ではありません。たとえば、次の場合に機能する理由を理解するために、これは重要です。

int localIntPtr(){
 int hi;
 ...
 return hi;
}

お役に立てれば。

于 2013-01-09T00:30:48.507 に答える
1

コンパイラ ログの警告には理由があります。ローカル変数へのポインターを返すべきではありません。これらの変数によって使用されるメモリは、いつでも再利用できます。これが、 の出力にゴミが表示される理由ですlocalStrPtr()。他の 2 つの関数の出力が正しいことは幸運です。これは保証されていません。

usingmalloc()が期待どおりに機能する理由は、対応する への呼び出しでコンピュータに明示的にそうするように指示するまで解放されないメモリを割り当てるためですfree()。ローカル変数の場合、コンピュータはいつでもメモリを再利用できます。

于 2013-01-09T00:31:24.763 に答える
1

コンパイラが言及しているように、スタック上のアドレスを返しています。リターンを行った後、スタック内の値は、後で来る他の関数呼び出しによって上書きされる場合と上書きされない場合があります。int または char を取得するという事実は単なるチャンスです。再び戻る直前に別のものを発行するprintf( "localIntPtr = %d\n", *pInt );と、pInt が既に上書きされていることがわかります。

于 2013-01-09T00:35:47.440 に答える
0

これまでの回答は、ローカル変数へのポインターを返すことが決して受け入れられない理由をよく説明していますが、malloc() を使用する代わりの方法があります。最も一般的なのは、入力する必要があるデータへのポインターを渡すことです。たとえば、空の char 配列を、文字列で入力する関数に渡すことができます。または、整数へのポインターを、ポインターに値を入力する関数に渡すことができます。

関数にメモリを割り当てるのは、関数が何らかのデータへのポインターを返すことができるようにするためだけに行うのは、通常は適切な選択ではありません。その関数の呼び出し元にデータを解放するように強制します[そうしないと、リークが発生しますが、これは悪いことです]。呼び出し元が呼び出し元の関数でローカル変数を割り当てたり使用したりできるようにする関数を用意することをお勧めします。

明らかに、場合によっては、これは、関数の下位層から何かを埋める「最上位」関数に関数呼び出しの複数の層を同じ変数に渡す必要があり、その後、さまざまなレベルで処理されることを意味します。 、およびおそらく malloc されたメモリ位置にも格納されます。これは完全に良い習慣であり、奨励されるべきです。

Malloc は、データの量が不明な場合にのみ使用する必要があります。そのため、呼び出し元は割り当てるメモリの量を知ることができません。または、データを実際にしばらく保存する必要があり、ローカル変数が " "。ただし、割り当てられたメモリを解放することを常に忘れないでください。

于 2013-01-09T00:45:57.250 に答える