0

このような配列int a[5]では、a[0]からa[4]までの5つの値を格納できます。これではない..?

char mobile[10]変数がclassあり、この変数に正確に10文字の長さの文字列を格納していました。しかし、ファイルから読み取っているとき、次の変数(クラス内のこの変数の直後に宣言されている)の数文字が変数に追加されていますmobile。何が悪いのかを調査するのに何時間もかかりました。

変数の順番などを変えて、できる限りのことをしてみました。

最後に、サイズmobileを11(char mobile[11])に設定し、それをバイナリファイルに保存します。その後、すべてがうまくいきます。

ここで、私の研究を実証できるデモプログラムを作成しました。

#include <iostream.h>
#include <conio.h>
#include <string.h>
#include <fstream.h>
#include <stdio.h>

class Test
{
    public:
    char mobile[10], address[30];
};

void main()
{
    clrscr();
    Test t;
    // uncoment below to write to file
    /*strcpy(t.mobile, "1234567890");
    strcpy(t.address, "Mumbai");

    fstream f("_test.bin", ios::binary | ios::out | ios::app);
    f.write((char*)&t, sizeof(t));*/

    // uncomment below to read from file
    /*fstream f("_test.bin", ios::binary | ios::in);
    f.read((char*)&t, sizeof(t));
    cout << t.mobile << "\t" << t.address;*/

    f.close();

    getch();
}

char[n]より具体的にはバイナリファイルでファイルを操作するときのように、配列にn文字を格納できないという私の仮定は正しいですか?

必要なサイズの余分なサイズを常に1つ取る必要があります..??

私のコンパイラはTurboC++(3.0かもしれません)です。非常に古く、製造中止の製品です。

4

3 に答える 3

3

Cスタイルの文字列(char配列)はnullで終了します。nullターミネータをファイルに保存する必要はありませんが、文字列を出力するときに必要です。

あなたの例ではstrcpy、10文字の文字列をにコピーするために使用しますchar[10]strcpy宛先文字列にnullターミネータを追加するため、これは未定義の動作です。を使用する必要がありますchar[11]

あなたの例では、ファイルから10文字を読み取り、を使用してそれらを印刷しますcoutcoutヌルターミネータによって文字列の長さを決定します。持っていないのでcout、文字列の終わりを超えて読み取ります。これも未定義の動作ですが、ほとんどの場合、構造体の次のフィールドから文字を読み取ることで機能します。この配列にはnullターミネータが必要です。つまり、これについても配列サイズを11に増やす必要があります。

于 2012-12-31T20:26:19.223 に答える
2

C /C++の文字ポインタはnullで終了する必要があります。つまり、最後に「\0」の値を持つ別の文字を割り当てる必要があります。

また、関数は、コンパイル時に「helloworld \ 0」として格納されるconst文字列(例は「helloworld」)でない限り、検出strcpyされるまで、ある文字列から別の文字列にすべての文字をコピーすることに注意してください。\0

このコードを試してください:

#include <iostream.h>
#include <conio.h>
#include <string.h>
#include <fstream.h>
#include <stdio.h>

class Test
{
    public:
    char mobile[11], address[30];
};

void main()
{
    clrscr();
    Test t;
    // uncoment below to write to file
    strcpy(t.mobile, "1234567890");
    strcpy(t.address, "Mumbai");
    t.address[10] = '\0';
    fstream f("_test.bin", ios::binary | ios::out | ios::app);
    f.write((char*)&t, sizeof(t))

    // uncomment below to read from file
    fstream f("_test.bin", ios::binary | ios::in);
    f.read((char*)&t, sizeof(t));
    cout << t.mobile << "\t" << t.address;

    f.close();

    getch();
}
于 2012-12-31T20:26:42.757 に答える
1

文字列リテラル"1234567890"は10バイトではなく11バイトを占めます!

printf("%d", sizeof("1234567890"));
// 11

これは、コンパイラ\0が文字列リテラルの最後に文字(文字列マーカーの終わり)をサイレントに追加するためです。このマーカーは、を含むさまざまな文字列操作関数で使用されますstrcpy

さて、次の行:

strcpy(t.mobile, "1234567890");

文字列(10文字と\0-を加えたもの)をにコピーしようとしますt.mobilet.mobileは10バイトの長さであるため、は\0他の変数のスペース(またはそれより悪い)によって使用されるスペースにオーバーフローします。

あなたの例では:

  • strcpy(t.mobile, "1234567890")文字列を期待どおりにコピーしますが、\0によって使用されるスペースにオーバーフローしますt.address
  • strcpy(t.address, "Mumbai")文字列を期待どおりにコピーすると、\0が上書きされます
  • 印刷の結果は次のt.mobileようになります"1234567890Mumbai"

話の教訓:\0C文字列関数を使用するときは常にバイトを考慮してください。そうしないと、変数の破損、実行時エラー、またはさらに悪い結果(データ実行など)などの予期しない問題が発生します。

于 2012-12-31T21:19:01.567 に答える