23

を呼び出さずに関数から文字列を返すことは可能mallocですか? 私は以下のような機能を持っています:

char* getString(){
      char tempStr[20]

      // open file, read char by char and assign to tempStr
      // ....

      char* str = (char*)malloc(sizeof(char)*20);
      strcpy(str, tempStr); // assume this copy the null terminating char as well
      return str;
}

次に、 を呼び出すときにgetString()、戻り値を に代入し、char*完了したら解放します。次のようにします。

void randomFunction(){
      char* line = NULL;
      int i = 0;
      while (i < 1000) {
           line = getString();
           // do stuff with line
           free (line);  
           line = NULL;
      }
}

ただし、なしでこれを行う方法があるかどうか疑問に思っていmallocますか? そして、これは C 関数から文字列を返す適切な方法ですか? なしで戻る方法について調査を試みましたがmalloc、明確な答えが見つかりませんでした。私はCが初めてで、まだ学んでいます。

4

8 に答える 8

14

関数から一時的に返すことはできません。malloc を使用しない限り、関数で定義された文字配列は一時的なものになります。別の解決策は、文字配列をパラメーターとして関数に渡し、それを出力パラメーターとして使用することです。

于 2013-03-16T20:02:56.273 に答える
13

関数から文字列を返す一般的な方法は3つあります。(実際にはありませんが、文字列へのポインタを返す一般的な方法は3つあり、呼び出し元はこれを使用して文字列にアクセスできます。)

  1. 関数内を使用して文字列にスペースを割り当てmalloc()ます。free()これは最も柔軟な方法ですが、割り当てられた配列を呼び出し側が担当するようになります。また、パフォーマンスのオーバーヘッドが発生する可能性もあります。

  2. 文字列にスペースを割り当て、そのスペースへのポインタを渡すように呼び出し元に要求します。これにより、発信者に不便が生じます。特に、呼び出し元は文字列の大きさを決定する必要があります。

  3. static関数内で定義された配列(の最初の要素)へのポインターを返します。関数が戻った後も配列は存在し続けますが、コピーは1つだけです。つまり、連続した呼び出しは、前の呼び出しによって返された結果を覆い隠します。また、コードを作成するときに配列を選択して、一定のサイズにする必要があることも意味します。

于 2013-03-16T20:07:00.167 に答える
8

場合によります。

返された文字列が静的な内部バッファーへのポインターであることを判断して文書化できます。次に、ルーチンは再入可能ではありません (スレッドセーフでもありません)。たとえば、ctimeまたはそれgetpwentを行います。

より良い方法は、結果の文字列とサイズを引数として渡し、その文字列を埋めて、場合によってはそれを返すことです。getcwd(またはsnprintfポインタstrftimeではなくサイズを返す)はそのように機能します。

ただし、通常は、返された文字列がヒープに割り当てられていることを決定して文書化し、それに対する責任は呼び出し元にfreeあります。strdupその場合はorを使用することをお勧めしますasprintf

また、プログラム全体でBoehm の保守的なガベージ コレクタを使用することもできます(たとえば、文字列やポインタを含むヒープ値にはGC_STRDUPorを使用します)。GC_MALLOC_ATOMICGC_MALLOC

mallocその標準または遅すぎると感じた場合strdup(ただし、最初にそれを測定してください)、独自のプール アロケーターなどを使用できます。

別のスキームを使用することもできます (ただし、それらを文書化することが重要です)。たとえば、インターンされた文字列、または正規のインターンされた文字列 (「クォーク」または「シンボル」と呼ばれることもあります) を返すことができます。その後、文字列の等価性の代わりにポインターの等価性を使用できます。参照カウンター方式を使用することもできます。たとえば、Glib (GTK からのものですが、GUI プログラムの外でも使用可能です!) が提供するものを見てください: GString-sGQuark-s文字列ユーティリティ

ただし、結果がヒープに割り当てられているかどうかを判断し、そのヒープに割り当てられた結果を解放する責任を誰が負うか (および解放する方法) を明確に定義することが重要です。

メモリ リークを追跡するためにvalgrindを使用することもできます。コンパイラに渡すことを忘れないで-Wall -gください!gcc

PS。Boehm の GC の使用を検討します。そして、パフォーマンス上の理由でmalloc(またはstrdup, ....) を拒否すべきではないと思います(他のより高速な実装を選択するか、独自のメモリ プールを使用することができます)。ただし、メモリ リークが問題になる可能性があります。asprintfmalloc

于 2013-03-16T20:03:25.960 に答える
2

関数の外にメモリ割り当てを移動する通常の方法は、ポインタを渡すことです。実際には、バッファの範囲を超えないようにする必要があります。

char* getString(char* tempStr){
          // open file, read char by char and assign to tempStr
          // ....

          return tempStr;
    }


void randomFunction(){
        char line[20];
        int i = 0;
        while (i < 1000) {
             getString(line);
             // do stuff with line

        }
  }
于 2013-03-16T20:06:03.537 に答える
2

文字列は(明らかに)常に20文字なので、次のように簡単に実行できます。

void getString( char *outputString ) {
    // do stuff to outputString instead of mallocing, or use local memory and copy it at the end
}

char line[20];
for( ... ) {
    getString( line );
    // do things with line
}

これにより、多くの小さなmallocが回避されるため、より高速になります。

于 2013-03-16T20:06:29.703 に答える
2

C でこれを行う一般的な方法は、文字列を引数として関数に渡すことです。

char *getString(char *str, int size){
      // open file, read char by char and assign to tempStr
      // ....

      strncpy(str, tempStr, size); // assume this copies the null terminator
      return str;
}

または、文字列を静的に宣言するか、ファイルまたはグローバル スコープで宣言し、その中にコピーすることもできます。ただし、ヒープに割り当てられたバッファーへのポインターをこのシンボルに格納する場合は、再度割り当てる前に解放してください。

于 2013-03-16T20:08:24.747 に答える
0

関数内で文字列を静的として宣言し、それを返すだけです。

于 2013-03-17T03:11:05.703 に答える