🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

多次元配列

1次元配列内にさらに配列を格納している配列を、多次元配列と呼びます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

解決済

1回答

918閲覧

int型のvectorからunsigned int**型配列への変換に失敗してしまう

tetatetu

総合スコア26

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

多次元配列

1次元配列内にさらに配列を格納している配列を、多次元配列と呼びます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

0クリップ

投稿2021/03/28 13:03

編集2021/03/28 13:46

問題の背景と該当のコード

C++でCSVファイルの各要素を配列に格納して返す関数を作っているのですが、バグを解決できず困っています。その関数はParseCSVToArrayという名前で、**「引数に既存のcsvファイル名(string型)を渡して、該当のcsvファイルの各要素に入っている非負整数の値をパースしてunsigned int**型の配列にして返す」**というものです。
パース処理の便宜上、csvの中身はいったんvector<vector<int>型の2次元配列arr2dにパースして、その後にunsigned int**型の2次元配列newarrに入れなおしてnewarrをreturnする、というやり方を取っています。
元のcsvファイルのデータのサイズは1025x1025です。

unsigned int** ParseCSVToArray(string filename) { ifstream csv_file; csv_file.open(filename); //csvファイルから値を読み取ってvector<vector<int>>型の2次元配列arr2dに格納 string line; vector<vector<int>> arr2d; while (getline(csv_file, line)) { string val; vector<int> row; stringstream s(line); while (getline(s, val, ',')) { row.push_back(stoi(val)); } arr2d.push_back(row); } csv_file.close(); //unsigned int**型の2次元配列newarrに変換 int sizeOfCSV = arr2d.size();//サイズは1025x1025 //デバッグ用のcout cout << "arr2d size:" << arr2d.size() << " arr2d.at(0).at(0)" << arr2d.at(0).at(0) <<endl; unsigned int** newarr = new unsigned int* [sizeOfCSV]; for (int k = 0; k < sizeOfCSV; ++k) { newarr[k] = new unsigned int[sizeOfCSV]; for (int i = 0; i < sizeOfCSV; ++i) { newarr[k][i] = arr2d.at(k).at(i); } } //デバッグ用のcout cout << "newarr size:" << sizeof(newarr) << " newarr[0][0]:" << newarr[0][0] << endl; return newarr; }

##問題点
ちゃんとcsvのファイルがarr2dにパースされていること、それが適切にnewarrに変換されていることを確かめるために、上記のデバッグ用のcoutを使って上の2つの2次元配列のサイズを調べてみました。
元のcsvファイルの2次元データのサイズは1025x1025です。

すると、arr2d.size()の値は、正常に1025と出ました。しかし、sizeof(newarr)の値は8でした。

これはarr2dからnewarrへの変換作業の途中に間違いがあるのだと思います。
どこがおかしいのでしょうか?ご回答よろしくお願い致します。

##追記
質問文を書いている途中で気付いたのですが、arr2dがint型のvectorにしているのに対して、newarrはunsigned int型、と、型が違っていてまずいのではないかと思いました。この問題に直接関係あるかはわかりませんが、とりあえずvector<vector<int>>からvector<vector<unsigned int>>に変更してみようと思います。

##追追記
このサイトを見ると、「.size()によって返される値はint型ではなくsize_t型」ということを知ったので、上記のコードの一部を以下のように書き換えました。しかし、問題はそこではなかったようです。(依然としてsizeof(newarr)の値は8のままです)

//unsigned int**型の2次元配列newarrに変換 size_t sizeOfCSV = arr2d.size();//サイズは1025x1025 //デバッグ用のcout cout << "arr2d size:" << arr2d.size() << " arr2d.at(0).at(0)" << arr2d.at(0).at(0) <<endl; unsigned int** newarr = new unsigned int* [sizeOfCSV]; for (size_t k = 0; k < sizeOfCSV; ++k) { newarr[k] = new unsigned int[sizeOfCSV]; for (size_t i = 0; i < sizeOfCSV; ++i) { newarr[k][i] = arr2d.at(k).at(i); } } //デバッグ用のcout cout << "newarr size:" << sizeof(newarr) << " newarr[0][0]:" << newarr[0][0] << endl; return newarr;

謎の挙動

また、試しに、sizeof(newarr)の値である8を超える要素newarr[10][10]を参照してみたところ、なぜか成功し、普通にcsvに書かれていた値を返しました。ただ、Visual Studioに以下の警告が出ました:

重大度レベル コード 説明 プロジェクト ファイル 行 抑制状態 警告 C6385 'newarr' から無効なデータを読み取っています: 読み取り可能なサイズは 'sizeOfCSV*8' バイトですが、'88' バイトを読み取る可能性があります。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

newarrはunsigned int型

いやいや、unsigned int** newarrとしているのですから、newarrはunsinged int**型ですよ。
ですから、sizeof(newarr)すなわちsizeof(unsigned int **)は(64bitのWindowsやLinuxなら)8で当然じゃないですか?
現代のコンピュータでsizeof(unsigned int **)が1025になる可能性はほぼありません。そこに1025を期待したことが間違いです。

謎の挙動

sizeOfCSVの値によっては配列のサイズは10より小さい値になりうるから、10にアクセスすることが安全とは言い切れない、ということでの警告でしょう。この場合は無視してもいいと思います。

投稿2021/03/28 14:36

thkana

総合スコア7703

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tetatetu

2021/03/29 08:03 編集

ご回答ありがとうございます。ご指摘を受けて調べたところ、`sizeof`関数は配列のサイズを返すのではなく、その配列(変数)のバイト数を返す関数だったようで、私の勘違いだったようです。申し訳ありません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問