-2

私は C++ とコーディング全般にかなり慣れていません。Visual Studio 2013 デスクトップを使用して、.CSV ファイルからデータを収集して操作を実行する簡単なプログラムを作成しています。プログラムは正常にコンパイルおよび実行されているようで、開くファイルの名前を入力するように求められます。意図したとおり、無効なファイル名を入力すると、プログラムはエラー メッセージを表示して終了しますが、正しい名前を入力すると、次のようなメッセージが表示されます。

「TestIO.exe の 0x0F16A9E8 (msvcr120d.dll) で未処理の例外: 0xC0000005: 場所 0xCCCCCCC0 を読み取るアクセス違反」。

中断または継続のオプション付き。[続行] を押すと、同じメッセージが再び表示され、[中断] を押してデバッグを停止するまで無限に続きます。ここで何が起こっているのかまったくわかりません。誰かがこれに光を当てることができますか? それは大歓迎です。

編集: これが私の main() です。これがさらに役立つことを願っています。以前に含めなかったことをお詫びします。

int main()
{
    int numDays = 0, streams;
    string* date;
    string line, filename;
    DailyData* days;
    cout << "Enter file name: ";
    getline(cin, filename);
    ifstream infile;
    infile.open(filename); 
    if (infile.fail())
    {
        cout << "Error opening input file" << endl;
        return 0;
    }
    while (getline(infile, line))
        numDays++;
    date = new string[numDays];
    for (int i = 0; i < numDays; i++)
        getline(infile, date[i]);
    days = new DailyData[numDays];
    for (int i = 0; i < numDays; i++)
    {
        getData(date[i], streams);
        days[i] = DailyData(date[i], streams);
    }
    cout << "Max Streams: " << maxStreams(days, numDays) << endl;
    cout << "Min Streams: " << minStreams(days, numDays) << endl;
    cout << "Avg Streams: " << average(days, numDays) << endl;
    cout << "Tot Streams: " << total(days, numDays) << endl;
    delete[] days;
    delete[] date;
    infile.close();
    return 0;
}

編集 2: これは皆さんが求めたものの一部です

void getData(string& d, int& s)
{
    int start = 0, end = 0, i = 0;
    string p[14];
    while (start != string::npos)
    {
        end = d.find(",", start); 
        p[i] = d.substr(start, end - start);
        start = end + 1;
        i++;
    }
    d = p[0];
    s = atoi(p[5].c_str());
}

そして、これがDailyDataとそのコンストラクターです

class DailyData
{
    public:
    DailyData() :date("NULL"), streams(0){}
    DailyData(string d, int s) :date(d), streams(s){}
    string getDate(){ return date; }
    int getStreams(){ return streams; }
    friend ostream& operator << (ostream&, DailyData&);
    private:
        string date;
        int streams;
};

編集 3: 配列の代わりにベクトルを使用するようにコードを変更しました。int main() の変更に加えて、すべての関数定義/宣言で引数を変更するようにしました。最初に発生したのと同じ未処理の例外エラーがまだ発生しています。新しいコード スニペットは次のとおりです。

vector<string> date;
vector<DailyData> days;

//...

while (getline(infile, line))
{
    date.push_back(line);
    getData(date.back(), streams);
    days.push_back(DailyData(date.back(), streams));
}
numDays = days.size();
4

1 に答える 1

2

ファイルの最後まで読み取った後、コードが入力ファイルで getline を呼び出しているようです

while (getline(infile, line))
    numDays++;

// above reads every line in the file,
// then you call this, even though while(getline) has returned false:

for (int i = 0; i < numDays; i++)
    getline(infile, date[i]);

プログラミングに慣れていない場合は、常に中かっこを使用してループの本体を表示し、ループ ブロックの実行の開始位置と終了位置を確認できるようにします。

また、実際には、デバッガーの使い方を学ぶのが最善です。これは、プログラマーとして最も価値のあることです。

編集:

固定サイズの配列の代わりに、動的にサイズ変更可能なベクターを使用する方法は次のとおりです。

std::vector<string> dates;

//...

while( getline(infile, line) )
{
    dates.push_back(line);
}

さらに情報が必要な場合は、C++ ベクトルを検索してください。

編集2:

getData のコードが投稿されたので、問題はそこにあると思います。このコードを開始するには:

while (start != string::npos)
{
    end = d.find(",", start); 
    p[i] = d.substr(start, end - start);
    start = end + 1;
    i++;
}

非常に危険に見えます。

p[i] = d.substr(start, end - start); 

end == string::npos の場合、d.find がコンマを見つけられない場合に発生する奇妙な動作が発生します。

同様に、 end == string::npos の場合、start = end + 1 は期待どおりに動作しません

さらに p[i] = ... は、i の値が 13 未満の場合にのみ機能します。これを保証するチェックはありません。

私の最初の提案は、 end == string::npos かどうかを確認し、そうでない場合にのみ他の操作を実行することです。

このコードの動作は、入力データがどのように見えるかに大きく依存するため、デバッガーを使用するのが最善です。

于 2014-05-26T01:43:10.000 に答える