• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:型によらないCSVファイルの読み込みC言語プログラ)

型によらないCSVファイルの読み込みC言語プログラム

このQ&Aのポイント
  • N行*M列のエクセルデータをCSV形式に変換し、C言語で読み込むプログラムを作成しました。
  • NとMの値に関わらず、任意のサイズのCSVデータを読み込むことができます。
  • CSVデータを読み込み、配列に保存して出力するC言語プログラムです。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.6

>あらかじめ型のわかっているN行*M列のエクセルデータをCSV形式にし、読み込むプログラムを作成しました。 >これをNとMがどんな値であれ読み込めるようにするにはどうすれいいでしょうか 要するに、N行M列のCSVファイルをフリーの動的サイズで処理したいということですね? 試験的にSCVファイルで一度実験してみて行数Nが合わないようでしたら SAFTY を+5行とか+10行とかで補正してください。 /* Sample program ----- 実行形式 ----- ./a.out file_name */ #include <stdio.h> #include <stdlib.h> /* exit() */ #include <errno.h> /* errno */ #define SIZE 256 #define SAFTY 0 /* もしもの行数をこれで補正 >5 */ int main(int argc, char *argv[]) { char line[SIZE],*p; int M, N; FILE *fp; if(argc != 2) return 0; if((fp = fopen(argv[1],"r")) == NULL){ fprintf(stderr, "%s\n", strerror(errno)); exit(EXIT_FAILURE); } /* 取り合えず、1行読み込み */ fgets(line, SIZE, fp); /* カンマ(,)の数を列数M 数える */ M = 1; p = line; while(*p){ if(*p++ == ',') M++; } printf("M= %d : %s", M, line); /* シリンダーヘッドを末尾に移動し、行数N を求める */ fseek(fp, 0, SEEK_END); N = ftell(fp) / (p - line) + SAFTY; printf("N= %d\n", N); /* ここで malloc()を使う */ //csvdata = (double(*)[M])malloc(sizeof(double[M]) * N); /* シリンダーヘッドを最初に戻し */ fseek(fp, 0, SEEK_SET); /* 以下、通常のCSVファイル処理を継続する(省略してます)。*/ while(fgets(line, SIZE, fp) != NULL){ printf("%s", line); } fclose(fp); return 0; }

umenuki
質問者

お礼

ありがとうございました

umenuki
質問者

補足

実行してみましたが、何も表示されず処理が終わってしまいました。 C++として実行していますので、 #include <string.h> を追記しました

その他の回答 (6)

  • yama5140
  • ベストアンサー率54% (136/250)
回答No.7

#4 です。 >実行してみましたが、動きませんでした >>大きくは、冒頭の3行を直すだけで、「実際にいれる」ことができ  まさか、本当に3行を直した「だけ」で実行したのですか。  #3 のソースをそのまま実行してみて下さい。  データ配列が異なるので、思いどおりに出力しないのは当たり前ですが、「動く」はずです。  (再度動作確認済み) >おそらく勘違いされていると思うのですが、 >NとMの値はcsvの行・列数にしたいので、 >defineで決めるのがそもそもおかしい気がするのですが  「NとMの値はcsvの行・列数」のあたりは、いじってませんし、  私が「defineで決める」ようにしたわけでもありません。  勘違いのしようがないのですが・・。 もし、勘違いしてたら、#3 で >>(確認済み) とはできませんよ。ダミーデータすらできないのだから。また、 >>なお、デバック段階では、N と M は下のように小さくし、ダミーデータもそれに揃えた方が楽です。 「NとMの値はcsvの行・列数」と認識しているからの記述です。

umenuki
質問者

お礼

ありがとうございました

noname#140082
noname#140082
回答No.5

No.2です。 >ほとんど理解できていません 正直、何を目指しているのか理解できません。 もし、宿題などであれば、理解もしないで答えだけ提出してもすぐにバレてしまいますし、今後を考えれば難しくなればなるほど、自分では解決できなくなってしまいます。 差し出がましいようですが、実行環境があるようなので、1ステップずつ実行してみたり、あるいはprintf()などで値を確認するなどして、理解された方がいいでしょう。 No.3さんより >メモリ確保関数を用いるより、変数の宣言のほうが楽です。 この言葉どおりで、まずは大きめに領域を確保しておき、それに代入するのがいいでしょう。 たとえば、N行=1000,M列=100ぐらいで。 また、静的(static double csvdata[N][M];)に領域を確保した方が安心安全です。 ソースを見ると、確かにポインターを使って難しそうに見えます。 しかし、やっていることは、1行読み込んでそれからカンマ区切りを見つけながら、浮動小数点文字列をdouble値に変換し、2次元配列に代入しているだけです。

  • yama5140
  • ベストアンサー率54% (136/250)
回答No.4

#3 です。 >今は環境がないので実行できませんが、 ★うぅ~、無銭飲食か~。 >これだと3行2列の形式にしか対応してないんじゃないですか? >>なお、デバック段階では、N と M は下のように小さくし、 >これはコピペした時に空白が消えてしまっただけで、 ★ならば正常に動きます。 >これをNとMがどんな値であれ読み込めるようにするにはどうすれいいでしょうか >>N と M に変更があれば、コンパイルし直さなければなりません。

umenuki
質問者

補足

実行してみましたが、動きませんでした おそらく勘違いされていると思うのですが、 NとMの値はcsvの行・列数にしたいので、 defineで決めるのがそもそもおかしい気がするのですが

  • yama5140
  • ベストアンサー率54% (136/250)
回答No.3

>・・既存のプログラムは少しいじっただけなのでほとんど理解できていません >実際にいれる文が欲しいです  コンパイルしてみれば、少しは理解できると思います。  大きくは、冒頭の3行を直すだけで、「実際にいれる」ことができました(確認済み)。 ★要は、#define N23 と、#define N 23 は大違い、ということです。 +++++++++++++++ 以降、蛇足 ++++++++++++++++++++++ >型っていうのはMとNの値です  N と M に変更があれば、コンパイルし直さなければなりません。  このようなプログラムでは、(コンパイルし直す必要のない動的な)メモリ確保関数を用いるより、変数の宣言(◆)のほうが楽です。  http://homepage3.nifty.com/mmgames/c_guide/q_malloc.html  なお、デバック段階では、N と M は下のように小さくし、ダミーデータもそれに揃えた方が楽です。 以上をふまえたものを示します、参考にして下さい。  大きな変更 // ******* の付いた行  追加 // ++++++++ の付いた行  (超蛇足:C++記述を、C記述へ直しちゃいました) #include <stdio.h> #include <stdlib.h> #include <string.h> #define N 3 // ******* #define M 2 // ******* #define SEP_DATA ',' // ******* int csv_read( char filename[], double csv[N][M] ) {  FILE *fp;  char line[256], *ptr;  int i = 0, j;  if( ( fp = fopen( filename, "r" ) ) == NULL ){   printf( " file open error!!\n" );   return -1;  }  while( fgets( line, 256, fp ) != NULL ){   printf( "*%s", line );   ptr = line; j = 0;   do{    csv[i][j] = atof( ptr );    ptr = strchr( ptr, SEP_DATA );    if( ptr != NULL ){ ptr++; }    j++;   }while( ptr != NULL && j < M );   i++;   if( N <= i ) break; // ++++++++  }  fclose( fp );  return 0; } int main( int argv, char *argc[] ) {  int i, j;  char filename[256];  double csvdata[ N ][ M ]; // ◆ ++++++++  if( argv > 1 ){   strcpy( filename, argc[1] );  }else{   printf( "Please Input Filename:" );   scanf( "%s", filename );  }  for( i = 0; i < N; i++ ){   for( j = 0; j < M; j++ ){    csvdata[i][j] = 0.0;   }  }  if( csv_read( filename, csvdata ) < 0 ) return -1;  for( i = 0; i < N; i++ ){   printf( "%f", csvdata[i][0] ); // *** %lf   for( j = 1; j < M; j++ ){    printf( "\t%f", csvdata[i][j] ); // *** %lf   }   printf( "\n" );  }  return 0; } 注:インデントに全角空白を用いています。コピペ後、タブに一括変換して下さい。

umenuki
質問者

補足

今は環境がないので実行できませんが、 これだと3行2列の形式にしか対応してないんじゃないですか? >#define N23 と、#define N 23 これはコピペした時に空白が消えてしまっただけで、実際には右側のように書いてあります

noname#140082
noname#140082
回答No.2

ここまでできているのなら最初に1行読み込んで、列数を求め、以降はrealloc()で1行読むたびにメモリを拡張していけばいいでしょう。 でも >型によらないCSVファイル… この「型」って?

umenuki
質問者

補足

型っていうのはMとNの値です 適切な言葉がわかりませんでした プログラムを作成した、 とは言っても既存のプログラムは少しいじっただけなので ほとんど理解できていません 実際にいれる文が欲しいです

回答No.1

方法A (1) とりあえず、一行読み込んで列数をカウント (2) 一旦、行数カウントのためだけにファイルを読み込んで行数をカウント (3) 必要なメモリを確保 (4) 今までと同じ流れでファイルの先頭から読み込み 方法B とりあえず、一行読み込んで列数をカウント 一行分のデータを 次の行へのポインタ+配列 の線形リストにして、一行一行、 メモリ確保 → ファイルから一行読み込み → 確保したメモリにデータをセット とする。 二次元配列でなければならないのであれば、一旦、線形リストの形で読み込んでおいて、 全行読み込んだ後でリストの先頭からたどって二次元配列にセットしなおすとか。 線形リストについては、 http://www.cc.kyoto-su.ac.jp/~yamada/ap/list.html とか、検索するといろいろ出てくると思います。

umenuki
質問者

補足

プログラムを作成した、 とは言っても既存のプログラムは少しいじっただけなので ほとんど理解できていません 実際にいれる文が欲しいです

関連するQ&A

専門家に質問してみよう