csvファイルを入力する

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
DOG
記事: 27
登録日時: 5年前

csvファイルを入力する

#1

投稿記事 by DOG » 5年前

連続で質問をしてしまい、申し訳ありません。
csvファイルの数値をvectorの2次元配列に格納するプログラム書いているのですが、なかなかうまくいきません。
とりあえず、カンマ","も含めてvectorの2次元配列に格納しようとしているのですが、
Debug Assertion Failed!
Expression: vector subscript out of range
といったエラーが出ます。以下に、コードを載せます。
visual studio Express 2013を使っています。
vectorの確保領域以上の所にアクセスしているという旨のエラーらしいのですが、vectorってメモリを動的確保できるものではないのですか?
ちなみに、20行目のコメント部分を解除しても同様のエラーが出てしまいます。
原因はいったい何なのでしょうか?

コード:

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

using namespace std;

int main(int argc, char **argv){

	int i = 0;
	string str;
	vector<vector<string>> vss;
	ifstream fin;
	fin.open("sample.csv");

	if (!fin){
		cout << "入力ファイルをオープンできませんでした\n";
		return 1;
	}
	//vss.resize(100);
	while (true){
		getline(fin, str);
		vss[i].push_back(str);
		++i;
		if (fin.eof()){
			break;
		}
	}

	for (int k = 0; k < (int)vss.size(); k++){
		for (int j = 0; j < (int)vss[j].size(); j++){
			cout << vss[k][j] << endl;
		}
	}

	return 0;
}

Kaien
記事: 6
登録日時: 5年前
住所: 東京

Re: csvファイルを入力する

#2

投稿記事 by Kaien » 5年前

こんばんは。
DOG さんが書きました: vectorの確保領域以上の所にアクセスしているという旨のエラー
その通りです。それが起こりそうな所をみるしかないですね。
DOG さんが書きました: ちなみに、20行目のコメント部分を解除しても同様のエラーが出てしまいます。
解除しても、別の所で領域外をアクセスしているので、同様のエラーが出ています。
20行目の文は必要ですので、コメントは外してください。


因みに原因はfor文の方にあります。
1箇所だけ不自然な所があると思います。
よく見てみてください。

DOG
記事: 27
登録日時: 5年前

Re: csvファイルを入力する

#3

投稿記事 by DOG » 5年前

Kaienさんご返信ありがとうございます。
csvファイルの中身は、
2,3,4
6,4,1,9,0,5
7,2,5,6
となっています。
ちなみになのですが、
getline(fin, str);
でデータを格納したstrを表示させると、
2,3,4,,,
6,4,1,9,0,5
7,2,5,6,,
となりますので、
vss.size() は 3
vss[j].size() はそれぞれ 8, 11, 9
となるはずです。
う~ん、正直for文のどこが原因なのかがさっぱり分かりません・・・
この部分は正しいと思っていたもので・・・

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 8年前
住所: 東海地方
連絡を取る:

Re: csvファイルを入力する

#4

投稿記事 by softya(ソフト屋) » 5年前

デバッガでステップ実行で動作を確認されていますか? していれば気付けると思います。

> う~ん、正直for文のどこが原因なのかがさっぱり分かりません・・・
そういう思い込みを排除するためにもデバッガは有用です。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
usao
記事: 1538
登録日時: 6年前

Re: csvファイルを入力する

#5

投稿記事 by usao » 5年前

オフトピック
今回のみたいに数行しかないような箇所であれば,
 今のコードとは別にもう一度書いてみる(当たり前だと思ってることは当たり前に書かれる)
 →今のコードとdiffをとってみる(当たり前だと思ってた箇所が間違っていたのが発覚)
という手段も有効.

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 8年前
住所: 東海地方
連絡を取る:

Re: csvファイルを入力する

#6

投稿記事 by softya(ソフト屋) » 5年前

オフトピック
プログラミングというかデバッグの基本ですが自分を信用してはいけません。
信頼できない人(=自分)の書いたプログラムを検証するのはどうするのか、そこを考えてみてください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

N.R

Re: csvファイルを入力する

#7

投稿記事 by N.R » 5年前

そうですね
そういう時はソースコードを見やすく書き直してみるのも方法です。

forの中に .size() を直接書いていますが
いったん int の変数に代入してから使用してみるとか

そうする事でデバッガで変数の値も確認しやすくなります

ISLe
記事: 2645
登録日時: 8年前
連絡を取る:

Re: csvファイルを入力する

#8

投稿記事 by ISLe » 5年前

そもそも23行目で空のvectorに添字参照しようという考え方がおかしいと思います。
resizeしても確保分超えたら同じことなので問題を先送りしてるだけですよね。


質問とは関係ないですが、EOFをチェックする位置もおかしいです。


#近ごろ回答者側に確認不足が顕著な気がします。

N.R

Re: csvファイルを入力する

#9

投稿記事 by N.R » 5年前

>resizeしても確保分超えたら同じことなので問題を先送りしてるだけですよね
まずKaienさんの指摘する問題を直さないと先に進むべきではないと思います

>vectorってメモリを動的確保できるものではないのですか
と議題者は書いているのでresizeしたくないであろう事は分かっています

しかし今 resize した事によって別の間違いが浮き彫りになっている状態です
だからKaienさんはまずそれを指摘しているのだと思います
私もパッと見分からなかったので、「これは確かに議題者自身に気が付いてほしい」と思ったので同じようにヒントのみにしました
議題者自身きっとよい勉強になると思います

実際軽く動的確保に直してみるとエラーもなく通ってしまいました。
次に問題として現れるときはもっと分かりにくくなっているかもしれません

少なくとも私の周りではそういうのを問題の先送りと呼んでいます

Kaien
記事: 6
登録日時: 5年前
住所: 東京

Re: csvファイルを入力する

#10

投稿記事 by Kaien » 5年前

私の言葉不足が露呈してますね。

N.R様の言うように、まずresizeありだと別の問題が出てしまいますが、まずその間違いを直した方がいいと思いましたので、resizeのコメントを外すように書きました。

実はこの質問、約1年前に初めてSTLを触った頃の自分が陥ったミスと全く同じものでして、DOG様本人が気づいて欲しい点だと思いましたので、ヒントという形にしました。
DOG さんが書きました: う~ん、正直for文のどこが原因なのかがさっぱり分かりません・・・
この部分は正しいと思っていたもので・・・
そういう訳ですので、DOG様、頑張って見つけてください。

しかしながら、それでもresizeをする事で発生する別の問題のについては、言及すべきだったかもしれません。その件について、言葉足らずで申し訳ありませんでした。

最後に、ISLe様のおっしゃるEOFのチェック場所は素で見落としていました。
確認不足でした事、深く反省しております。

DOG
記事: 27
登録日時: 5年前

Re: csvファイルを入力する

#11

投稿記事 by DOG » 5年前

皆様、ご返信ありがとうございます。
プログラミングの勉強を始めてまだ数か月しかたっていないので、醜いコードになっているとは思いますが、どうかご容赦くださいませ。
さて、for文中の原因ですが、31行目のfor文の条件式の中の
j < (int)vss[j].size()
がおかしいことに気づきました。正しくは、
j < (int)vss[k].size()
だと思いました。
それで、20行目のコメント解除すると、正しく実行されました。

そこで、N.Rさんが仰っている
>>しかし今 resize した事によって別の間違いが浮き彫りになっている状態です
ですが、resize()で前もって確保しておかないと同じエラーが出ます。
vectorの良いところは領域の動的確保なのに、これだとvectorの良いところが消えてしまっているように思えます。
C++の入門書でvectorの2次元配列を扱っている箇所があるのですが、そこでも前もってresize()で領域確保されています。
vectorの2次元配列の場合は前もって確保しなければならないのでしょうか?

DOG
記事: 27
登録日時: 5年前

Re: csvファイルを入力する

#12

投稿記事 by DOG » 5年前

連投すみません。EOFの位置についてコメントさせて下さい。
正しくは、

コード:

while (true){
        if (fin.eof()){
            break;
        }
        getline(fin, str);
        vss[i].push_back(str);
        ++i;
    }
で、よろしいでしょうか?
よろしくお願い致します。

かずま

Re: csvファイルを入力する

#13

投稿記事 by かずま » 5年前

DOG さんが書きました: csvファイルの数値をvectorの2次元配列に格納するプログラム書いているのですが、なかなかうまくいきません。
とりあえず、カンマ","も含めてvectorの2次元配列に格納しようとしているのですが、
"," を含めなくてよいのなら、

コード:

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
 
int main(void)
{
    using namespace std;

    ifstream ifs("sample.csv");
    if (!ifs) return 1;

    vector< vector<string> > vvs;

    string line, word;
    for (size_t i = 0; getline(ifs, line); i++) {
        istringstream iss(line);
        vvs.push_back(vector<string>());
        while (getline(iss, word, ','))
            vvs[i].push_back(word);
    }
    for (size_t i = 0; i < vvs.size(); i++) {
        for (size_t j = 0; j < vvs[i].size(); j++)
            cout << " [" << vvs[i][j] << "]";
        cout << endl;
    }
    return 0;
}
sample.csv

コード:

2,3,4
6,4,1,9,0,5
7,2,5,6
実行結果

コード:

 [2] [3] [4]
 [6] [4] [1] [9] [0] [5]
 [7] [2] [5] [6]
 
それとも、次のようにしたいのですか?

コード:

 [2,] [3,] [4]
 [6,] [4,] [1,] [9,] [0,] [5]
 [7,] [2,] [5,] [6]
 

ISLe
記事: 2645
登録日時: 8年前
連絡を取る:

Re: csvファイルを入力する

#14

投稿記事 by ISLe » 5年前

質問者さんは気付いたようですが、resizeしたまま添字を直して動いたから『解決』というストーリーもあり得たと思います。

あとステップ実行すれば分かると思いますが、kのカウンタがresizeした分回るのはとても無駄だと思います。
取得したデータを加工する処理を加える際、空回りするループが邪魔になるかもしれません。

アバター
usao
記事: 1538
登録日時: 6年前

Re: csvファイルを入力する

#15

投稿記事 by usao » 5年前

DOG さんが書きました:連投すみません。EOFの位置についてコメントさせて下さい。
正しくは、

コード:

while (true){
        if (fin.eof()){
            break;
        }
        getline(fin, str);
        vss[i].push_back(str);
        ++i;
    }
で、よろしいでしょうか?
よろしくお願い致します。
最初のコードと特に動作に差が生まれないように思います.
(eof()が,ループの初回でtrueを返すことはないから)

例えば空のファイルだった場合に,どのように動くかなどを調べてみるとよいかと思います.
(eof()を使わない方法は既に示されていますが,この問いに関して誰も答えていないようなので…)

N.R

Re: csvファイルを入力する

#16

投稿記事 by N.R » 5年前

>#近ごろ回答者側に確認不足が顕著な気がします。
これは正しいですね
確認がきちんとできる人は後から後からコメントを書き換えたりしないでしょう

ISLe
記事: 2645
登録日時: 8年前
連絡を取る:

Re: csvファイルを入力する

#17

投稿記事 by ISLe » 5年前

N.R さんが書きました:>#近ごろ回答者側に確認不足が顕著な気がします。
これは正しいですね
確認がきちんとできる人は後から後からコメントを書き換えたりしないでしょう
わたしはしばしば投稿を書き換えますが、結論が変わるような書き換えはしていないつもりです。

フォーラムルールでは禁止行為として、記事の内容を無暗に変更する行為、とあります。
記事を無暗に変更する行為、ではありませんから問題無いのではないでしょうか。

ISLe
記事: 2645
登録日時: 8年前
連絡を取る:

Re: csvファイルを入力する

#18

投稿記事 by ISLe » 5年前

N.R さんが書きました:>resizeしても確保分超えたら同じことなので問題を先送りしてるだけですよね
まずKaienさんの指摘する問題を直さないと先に進むべきではないと思います
わたしが指摘した問題を直してもKaienさんが指摘した問題は無くなりません。
Kaienさんが指摘した問題を無くすと、わたしが指摘した問題は無くなったようにみえるかもしれません。
まずKaienさんの指摘する問題を直さないといけない理由は何ですか?
N.R さんが書きました:>vectorってメモリを動的確保できるものではないのですか
と議題者は書いているのでresizeしたくないであろう事は分かっています
質問者さんはresizeの有無でエラーが発生する箇所が違うことに気付いていません。
resizeをすることで動的確保が可能になる、と誤って理解してしまう可能性は少なくないと思います。
N.R さんが書きました:しかし今 resize した事によって別の間違いが浮き彫りになっている状態です
だからKaienさんはまずそれを指摘しているのだと思います
私もパッと見分からなかったので、「これは確かに議題者自身に気が付いてほしい」と思ったので同じようにヒントのみにしました
議題者自身きっとよい勉強になると思います
繰り返しますが、わたしの指摘した問題を直してもKaienさんが指摘した問題は無くなりません。
N.R さんが書きました:実際軽く動的確保に直してみるとエラーもなく通ってしまいました。
次に問題として現れるときはもっと分かりにくくなっているかもしれません

少なくとも私の周りではそういうのを問題の先送りと呼んでいます
少なくともわたしには手っ取り早く直せる方に先に手を付けただけのように見えますが。

ちなみに読み込み部分を直すことで後半のループ自体が不要になる可能性があるのでまず前半を指摘しました。

ISLe
記事: 2645
登録日時: 8年前
連絡を取る:

Re: csvファイルを入力する

#19

投稿記事 by ISLe » 5年前

Kaien さんが書きました:しかしながら、それでもresizeをする事で発生する別の問題のについては、言及すべきだったかもしれません。その件について、言葉足らずで申し訳ありませんでした。
この時点でkをカウントするループがファイルから読み込んだ行数を越えてresizeで指定した分まで空回りするということに気付いていたのか正直に教えていただけないでしょうか。

気付いていたか気付いていなかったに関わらず、質問に書かれたコードの『仕様』が変わることについて、また、そのような回答をすることについて、どうお考えなのでしょう。

ISLe
記事: 2645
登録日時: 8年前
連絡を取る:

Re: csvファイルを入力する

#20

投稿記事 by ISLe » 5年前

DOG さんが書きました:連投すみません。EOFの位置についてコメントさせて下さい。
かずまさんの投稿したコードにヒントがありますが…

コード:

while (getline(fin, str)) {
    vss[i].push_back(str);
    ++i;
}
EOF以外の状態変化にも対応するのでより汎用になります。

ISLe
記事: 2645
登録日時: 8年前
連絡を取る:

Re: csvファイルを入力する

#21

投稿記事 by ISLe » 5年前

DOG さんが書きました:そこで、N.Rさんが仰っている
>>しかし今 resize した事によって別の間違いが浮き彫りになっている状態です
ですが、resize()で前もって確保しておかないと同じエラーが出ます。
vectorの良いところは領域の動的確保なのに、これだとvectorの良いところが消えてしまっているように思えます。
C++の入門書でvectorの2次元配列を扱っている箇所があるのですが、そこでも前もってresize()で領域確保されています。
vectorの2次元配列の場合は前もって確保しなければならないのでしょうか?
いいえ、resizeするのは姑息な手段です。
少なくともわたしはDOGさんが本来望む動作を実装するのに遠回りをしていると感じます。

#ここでは姑息を本来の意味で使用しています。

N.R

Re: csvファイルを入力する

#22

投稿記事 by N.R » 5年前


私は同意したのであってISLeさんに問題があると書いたつもりはないのですが

しかし掲示板の内容を書き換える事は信頼性を揺るがす事に繋がるので多くの人がやっているように
修正線を入れるのが適切です。書き方一つでニュアンスも変わってしまいますからね。

それも「投稿前にちきんと確認していれば、そもそもそんな必要ないのにな」
という意見に何かおかしい所がありますか

アバター
みけCAT
記事: 6149
登録日時: 8年前
住所: 千葉県
連絡を取る:

Re: csvファイルを入力する

#23

投稿記事 by みけCAT » 5年前

オフトピック
N.R さんが書きました:それも「投稿前にちきんと確認していれば、そもそもそんな必要ないのにな」
という意見に何かおかしい所がありますか
「ちきんと」という部分がおかしい(ジョークとして面白い、という意味で)ですね。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

N.R

Re: csvファイルを入力する

#24

投稿記事 by N.R » 5年前

確認はするもんだ
という教訓ですw

かずま

Re: csvファイルを入力する

#25

投稿記事 by かずま » 5年前

DOG さんが書きました: csvファイルの中身は、
2,3,4
6,4,1,9,0,5
7,2,5,6
となっています。
ちなみになのですが、
getline(fin, str);
でデータを格納したstrを表示させると、
2,3,4,,,
6,4,1,9,0,5
7,2,5,6,,
となりますので、
本当ですか?
信じられません。

かずま

Re: csvファイルを入力する

#26

投稿記事 by かずま » 5年前

DOG さんが書きました:vectorの2次元配列の場合は前もって確保しなければならないのでしょうか?
push_back() を使えば、前もって確保する必要はありません。

ISLe
記事: 2645
登録日時: 8年前
連絡を取る:

Re: csvファイルを入力する

#27

投稿記事 by ISLe » 5年前

resizeしない方法は、KaienさんやN.Rさんがフォローしてくださるに違いありません。
そうでなければ問題の先送りどころか問題の棚上げですからね。

ISLe
記事: 2645
登録日時: 8年前
連絡を取る:

Re: csvファイルを入力する

#28

投稿記事 by ISLe » 5年前

オフトピック
わたしは投稿を書き換えるということについて自分の意見を述べただけです。
わたしが何を確認することについて不足を感じているかは分かっていただけないようです。
N.R さんが書きました:それも「投稿前にちきんと確認していれば、そもそもそんな必要ないのにな」
という意見に何かおかしい所がありますか
そもそも噛み合ってないので何とも言えません。

ISLe
記事: 2645
登録日時: 8年前
連絡を取る:

Re: csvファイルを入力する

#29

投稿記事 by ISLe » 5年前

そもそも
DOG さんが書きました:とりあえず、カンマ","も含めてvectorの2次元配列に格納しようとしているのですが、
というのがおかしい。

とりあえず一行ごとに読み込むなら2次元配列はおかしい。
vector<string>
で良い。

その後一行ごとに分解するときに、
vector<string> → vector<vector<int>>
と置き換えればエラーを回避するためだけに不自然なコードを記述する必要などない。

だから先に後半部分のデバッグをすることはまったく時間の無駄だとわたしには思える。


そしてかずまさんはずっと先を突っ走っている。

かずま

Re: csvファイルを入力する

#30

投稿記事 by かずま » 5年前

数値として読み込みたいのなら、vector<vector<int> > ですね。

コード:

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>

int main(void)
{
    using namespace std;

    ifstream ifs("sample.csv");
    if (!ifs) return 1;

    vector< vector<int> > vvs;

    string line;
    for (size_t i = 0; getline(ifs, line); i++) {
        istringstream iss(line);
        vvs.push_back(vector<int>());
        int value;
        while (iss >> value) {
            vvs[i].push_back(value);
            char comma;
            iss >> comma;
        }
    }
    for (size_t i = 0; i < vvs.size(); i++) {
        for (size_t j = 0; j < vvs[i].size(); j++)
            cout << " [" << vvs[i][j] << "]";
        cout << endl;
    }
    return 0;
}

閉鎖

“C言語何でも質問掲示板” へ戻る