
以下のようなソースでカンマ区切りのテキストファイルであるcsvファイルの行数、列数、要素数を取得するプログラムを作っているのですが、終わりのメモリ解放であるdelete []strのところでプログラムが落ちてしまいます。範囲外のメモリにアクセスしてしまっているのかと思いますが、ミスを特定できないので、教えてください。
読み込むcsvファイルには以下のような小数の値が入っています。
0.23960810421811729043, 11.753428210139766463, …(省略) , 3.8736893050771881164
int main( int argc, char **argv ) {
int csvRowNum, csvColNum, csvElemNum;
GetCSVDataNum ( "C:\\Data.csv", csvRowNum, csvColNum, csvElemNum );
return 0;
}
// csvファイルから行数、列数、要素数を取得する
int GetCSVDataNum ( char *csv_name, int &rowNum, int &colNum, int &elemNum ) {
FILE *fp;
fp = fopen( csv_name, "r" );
if( fp == NULL ){
printf( "ファイルオープンエラー\n" );
exit(1);
}
// ファイルサイズの取得
int fsize;
fseek( fp, 0L, SEEK_END );
fsize = ftell( fp );
// ファイルシーク位置を先頭に戻す
fseek( fp, 0L, SEEK_SET );
// ファイルサイズに合わせて文字列領域確保
char *str;
str = new char[fsize];
char buf[10000];
// ファイルから1行ずつテキストデータを読み込み、
// 連結してbufに格納する
str[0] = '\0';
while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
strncat( str, buf, strlen(buf) );
}
int countSep = 0;// '(カンマ)の数のカウント
int cols = 0;// 各行の列数をカウント
int countNL = 0;// 改行の数をカウント
// 要素数、行数、列数の取得
for ( int i = 0; i < (int)strlen(str); i++ ) {
switch( str[i]){
case ',':
countSep++;
cols++;
break;
case '\n':
countNL++;
cols++;
// 各行で列数が異なるときは、最も大きい列数とする
colNum = (colNum > cols ) ? colNum: cols;
cols = 0;
break;
default:
break;
}
}
rowNum = countNL;
elemNum = countSep + countNL;
// strの解放で落ちる
delete[] str;
fclose( fp );
return 0;
}
No.3ベストアンサー
- 回答日時:
http://msdn.microsoft.com/ja-jp/library/0ys3hc0b …
とかですかね。>#2
私的には…
>strncat( str, buf, strlen(buf) );
もちょっとばかし違和感が。
# ありといえばあり…なんでしょうけど。
>終わりのメモリ解放であるdelete []strのところでプログラムが落ちてしまいます。範囲外のメモリにアクセスしてしまっているのかと
は、回答ある通り…ですかね。
ftell()が正しくファイルサイズを返している場合は…'\0'の分が足りない。
ファイルサイズが正しくなかった場合は…strncat()した時にオーバーラン。
回答ありがとうございます。
ヌル文字の分を忘れていました。
ファイルサイズは正しく返しているようなので、
文字列最後に加わるヌル文字の分+1して、str = new char[fsize+1];とすれば大丈夫でしょうか。
プログラムとしては動くようになったのですが、正しく理解しているか不安なもので。
strcatの部分の違和感というのも、ヌル文字の分を入れていないからでしょうか?以下のようにすればいいのでしょうか?それとも根本的に使い方がいまいちなのでしょうか?
strncat( str, buf, strlen(buf)+1 );
No.6
- 回答日時:
>strcatの部分の違和感というのも、ヌル文字の分を入れていないからでしょうか?以下のようにすればいいのでしょうか?それとも根本的に使い方がいまいちなのでしょうか?
>strncat( str, buf, strlen(buf)+1 );
バッファオーバーランしない限りはstrcat()でいいでしょう?
そして、今回は(仕様として正しい値が取れるかは不明とはいえ)ファイルサイズ+α分のバッファを動的確保しているのですから、
strncat()にする必要もない…かと思うんですが……。
strncat()の使いどころって…
「コピー先(連結先)よりコピー元の文字列長が長い場合に途中で切れてでもバッファオーバーランさせない」って場合かと思いますが。
# まぁ、元々何文字入っているのかわからないと使いにくいですが。
# strncat( str, buf, (sizeof(str) - strlen(str) - 1) ) って感じ…かな??
No.5
- 回答日時:
順番に読んで順番に処理するだけなら、strそのものを使わずに
// 要素数、行数、列数の取得
while((c=fgetc(fp))!=EOF){
switch( c ){
...
で十分な気がします。
回答ありがとうございます。
確かに順に読んで、文字数をカウントするだけならfgetcでよかったですね。
そのあと、取得した文字列から次のカンマまたは改行までの文字列分を取ってきてstrtod関数でdoubleに変換するときに文字列がいいのかと思って、そうしてしまっていました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
GlobalAlloc生成メモリの開放で...
-
ファイルの特定行の抽出
-
C言語でファイル読み書きを早く...
-
01番の二次元配列でこの実行結...
-
c言語でのfscanfについて
-
最早開始時間と最遅完了時刻を...
-
【C++】関数ポインタの使い方
-
既定のコンストラクタがありま...
-
Aの値からBの値を除するとは??
-
「Aに対するBの割合」と「Aに対...
-
信頼区間の1.96や1.65ってどこ...
-
a^2の√=a が成り立たない場合
-
VB6.0での小数点の扱いについて
-
配列をnビットシフトする
-
数学 一次関数 関数 y=-3/4x+k(...
-
c languageで 簡単な質問があ...
-
C言語 エラーの原因がわからな...
-
#define _CRT_SECURE_NO_WARNIN...
-
プログラムでの数字につく”f”の...
-
C言語で複数列のデータを1列の...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
複数ファイルの同時読み込みの...
-
C言語の課題です
-
ファイル出力で改行を入れたい!
-
fgets( ) の返り値は何?
-
C言語でファイル読み書きを早く...
-
fopenでファイル名に、変数を使...
-
ファイルに行番号を追加
-
テキストファイル内に対して, ...
-
ファイルへの書込み処理が異常...
-
C言語についてアドバイスをくだ...
-
同時にファイル読み込み 書き込み
-
初心者のc言語
-
大量の入力ファイルを扱うとき...
-
【C言語について】ファイル名の...
-
C言語 共用体の構造体の引数設定
-
C言語でのCSVソートとデータ抽...
-
エラーがわかりません、、
-
プログラムの内で、何か画面表...
-
「コマンドライン引数チェック...
-
プログラミングのデータの読み込み
おすすめ情報