0

C の学習を始めましたが、何が間違っているのかわかりません。pid+".data" を返す関数の簡単なコードを次に示します。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

char * getfilename(){
    char name[60];
    sprintf(name,"%i.data",getpid());
    return name;
}

void main(){
    char* name = getfilename();
    printf("%s",name);
}

出力: ��#�a.

だから私は何か間違ったことをしていると思います。

4

6 に答える 6

4
char * getfilename(){
    char name[60];
    sprintf(name,"%i.data",getpid());
    return name;
}

が戻ったname後は、オブジェクトにアクセスできません。getfilename自動オブジェクトの存続期間はname最後getfilename}. 関数が戻った後にアクセスすると、未定義の動作になります。

一時的な修正nameとして asstaticを指定すると動作します。しかし、あなたがすべきことは、getfilename関数がファイル名が書き込まれるポインタ引数を受け入れるようにすることです。

編集:

の使用をお勧めしないのはなぜstrdupですか?

  • strdupは標準 C 関数ではありません。strdupPOSIXの世界に住んでいます。移植性の理由から、可能な限り、標準 C 関数を使用することを好みます。
  • strdup隠しmalloc呼び出しを実行し、実行することを忘れる必要はありませんfree. これは、標準 C ライブラリのすべての関数が呼び出さないmalloc(または、実際には呼び出しないようmallocに見える) のとは対照的です。strdup悪い API 設計です。
  • strdup文字列のコピーを実行しています。余分なコピーを実行する必要があるのはなぜですか? 文字列を取得できる場所に書き込むだけです。
于 2012-11-12T13:07:52.323 に答える
3

1 つの解決策は、 strdupを使用することです。つまり、次のように変更します。

return name;

に:

return strdup(name);

これにより、動的メモリ割り当て (つまりmalloc ) を使用して一時 (ローカル) 文字列のコピーが作成されます。

もちろん、この文字列を使い終わったら、後でこの文字列を解放する必要があります。

あなたは必要になるでしょう:

#include <string.h> // strdup()
#include <stdlib.h> // free()
于 2012-11-12T13:11:48.023 に答える
1

char name[60]関数が呼び出されたときに割り当てられ、関数が戻るときに解放されるローカル変数です。それを返そうとすると、実際にはそのアドレスが返されます (すべての配列はほとんどがポインター演算の構文糖衣です)。これで、呼び出し元は解放されたメモリ ブロックへのポインタを持っているため、ガベージが含まれている可能性があります。

于 2012-11-12T13:10:58.143 に答える
1

name関数から配列を返すことはできませんgetfilename。これは (通常の) ローカル変数であり、関数が返されるときにクリーンアップされるためです。そのためmain、戻って戻り値を出力しようとすると、そこにあるポインターnameは、他の目的で再利用されたメモリーのブロックを参照します。

この問題にはいくつかの解決策があります。

  1. nameで作るgetfilename static。これにより、呼び出しが終了しても安全に返されることが保証されますが、すべての呼び出しが同じバッファーgetfilenameを使用するという欠点があります。getfilename
  2. で配列を動的に割り当てますmalloc(そして、使い終わったら、で配列をクリーンアップすることを忘れないでくださいfree
  3. 値を格納するバッファをパラメータとして渡します。
于 2012-11-12T13:15:36.397 に答える
1
char name[60] 

はスタック上に存在しますが、後で内部にある限りgetfilename()解放されるため、それへの参照 ( によっても返されるgetfilename()) は無効になります。

于 2012-11-12T13:10:10.887 に答える
0

他の回答で述べたように、関数のスタック内のどこかを指すポインターを返すことはできません。

割り当てられた配列をgetfilename()関数に渡すだけです。プログラムは次のように書き換えることができます。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void getfilename(char * name)
{

    sprintf(name,"%i.data",getpid());
}

int main(void)
{
    char name[60];
    getfilename(name);
    printf("%s\n",name);
    return 0;
}

これはうまくいくはずです。

于 2012-11-12T14:20:31.303 に答える