2010-11-22 10 views
3

の文字列を読み取り、保存することです:のfgetc():私は割り当てのために行うために必要なもの、未知の長さ

  • (fopen()でを使用して)ファイルを開く
  • は、(学生の名前を読んで名前のstruct

の一部に私が持っている問題は、私は名前に任意の長い文字列を読み取る必要があるということである、と私はそれを保存する方法を知らないということはfgetc())

  • ストアを使用して文字列をメモリ無駄にすることなく(または割り当てられていないメモリに書き込む) y)。

    EDIT

    私の最初のアイデアは、1バイト(文字)メモリ・ブロックを割り当てることだった、そして、より多くのバイトが必要な場合)(のreallocを呼び出しますが、これは非常に効率的ないないようです。一杯になったら、配列を二倍にして、最後に文字を正確なサイズの新しいメモリブロックにコピーすることもできます。

  • +3

    サイズを倍増するreallocの提案を編集しても問題はありません。あなたはおそらく十分な大きさの配列から始めることができます(学生名であることがわかっていれば)、ほとんどの場合reallocを避けてください。 Supercalifragilisticsuperalidosciousさんは、あなたの学校に行きません。 –

    +0

    @ポール - あなたは確かに彼は彼に? – DMan

    +1

    文字を正確に正しいサイズの新しいメモリにコピーする必要はありません。最後に 'realloc()'をもう一度使って、割り当てられたブロックを正しいサイズにトリムすることができます。 – caf

    答えて

    5

    すべての名前に十分な長さの100または1000バイトを無駄にする心配はありません。 私はたぶんあなたが読んでいるバッファをスタックに置くだけでしょう。

    バッファの末尾に書き込むことを心配します。すなわちバッファオーバーラン。それを防ぐためのプログラム!

    構造体に名前を格納するときは、必要な正確な長さの名前を格納するためにバッファをmallocできます(ヌルターミネータに余分なバイトを追加することを忘れないでください)。

    しかし、本当に任意の長さの名前を格納しなければならない場合は、reallocを使用して実行できます。 すなわち、サイズが50バイトのmallocでバッファを割り当てます。

    さらにスペースが必要な場合は、reallocを使用してスペースを増やしてください。 50バイトのブロックで長さを増やし、それをどれだけ大きくして、いつ成長させる必要があるかを知ることができます。ある時点では、無期限に成長することができないため、バッファーの長さを決める必要があります。

    +0

    あなたは本当にバッファオーバーランについて心配する必要があります。あなたが最速で汚れテストアプリケーションを扱っているのでなければ、または文字列があなたのバッファより大きくなることは絶対に確かであるかもしれません –

    2

    文字列を文字列で読み取って終わりを見つけてから最初に巻き戻し、正しいサイズのバッファを割り当ててから再読み込みすることができますが、小さな組込みシステムでなければおそらく愚かです。 1つは、fgetcやfreadなどの関数がO/Sにバッファを作成することです。

    十分な大きさの一時バッファを割り当て、そのバッファに長さ制限付きの読み取り(安全のために)を使用し、それをコピーする正確なサイズのバッファを割り当てることができます。使用可能なスタック領域を超えていると思わない限り、一時バッファをmalloc経由ではなくスタックに割り当てることをお勧めします。

    小さなシステム用にシングルスレッドコードを書いている場合は、起動時または静的にスクラッチバッファを割り当てて、多目的に再利用することができます。

    ほとんどのシステムの実装の複雑さを考えれば、実際の動作を実際に研究しない限り、メモリ最適化コードを書くことは可能です。変数の初期化は、別の驚くほど無駄なものになる可能性があります。

    2

    私の提案は十分なサイズのバッファを割り当てるために、次のようになります。

    char name_buffer [ 80 ]; 
    

    一般的に、ほとんどの名前(少なくとも一般的な英語名)が80文字未満のサイズになります。あなたがそれよりも多くのスペースを必要とするかもしれないと感じたら、是非、もっと多くを配分してください。

    あなたはすでにあなたのバッファに読み込まれているどのように多くの文字を知っているカウンター変数を保持:

    int chars_read = 0; /* most compilers will init to 0 for you, but always good to be explicit */ 
    

    この時点で、あなたはファイルマーカーの終わりを打つか、80を読んでどちらかまでfgetc()と文字で文字を読んであなたはヌルターミネーターのためのスペースが必要なので79文字です。読み込んだ各文字をバッファに格納し、カウンタ変数をインクリメントします。

    while ((chars_read < 80) && (!feof(stdin))) { 
        name_buffer [ chars_read ] = fgetc (stdin); 
        chars_read++; 
    } 
    if (chars_read < 80) 
        name_buffer [ chars_read ] = '\0'; /* terminating null character */ 
    

    私はあなたがstdinから読んでいることを、ここで想定しています。より完全な例では、エラーをチェックし、ストリームから読み込んだ文字が人の名前(数字など)に有効であることを確認します。スペースを割り当てたよりも多くのデータを読み込もうとすると、コンソールにエラーメッセージが表示されます。

    私は、できるだけ小さなバッファを維持し、必要なものだけを割り当てたいと考えていますが、プログラムの学習方法の一部は、コード/データサイズ、効率、コードの可読性のトレードオフを理解することです。 mallocreallocでも可能ですが、コードが必要以上に複雑になり、NULLポインタ、配列インデックスの範囲外エラーなどが発生する可能性があります。ほとんどの場合、十分なものを割り当てる必要がありますあなたのデータ要件に加えて少量の呼吸室が必要です。データがバッファのサイズを超えている場合が多い場合は、それに合わせてバッファを調整します。つまり、デバッグとテストの場合です。

    関連する問題