• ベストアンサー

エラーがないのに正常に動かない

以前質問したのものです。 アドバイス等いただき、プログラムを修正しエラーをなくしました。 しかし、プログラムが動きません。。。 プログラムの動作は CSVファイルを読み込んで、処理をする。 CSVファイルは 単語1,数値データ 単語2,数値データ のようになっており、 これをsの配列に格納したいと思っています。 プログラムの内容は #include<stdio.h> #include <string.h> int main(void) { FILE *fp; char s[5][1000][2][256]; char tp[256]; char *ttp; int i=0,ii=0; if((fp=fopen("out1.csv","r"))==NULL){ printf("ファイルオープンできませんよ\n"); return -1; } while(fgets(tp,256,fp)!=NULL){ ttp=strtok(tp,","); strcpy(&s[0][ii][i][0],ttp); puts(&s[0][ii][i][0]); while (ttp != NULL ) { i++; ttp=strtok(NULL,","); if (ttp != NULL ){ strcpy(&s[0][ii][i][0],ttp); puts(&s[0][ii][i][0]); }}i=0; ii++;if(ii>=1000)break; } return(0); } です。 わけがわからなくなりました(泣 どこが原因なのかも書いていただけるとありがたいです。

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

  • ベストアンサー
noname#144013
noname#144013
回答No.4

ionwide さん、こんにちは。 ■まず、問題点を上げます。 1)スタックサイズを大きくとる必要がある。  ※これは、【ANo.1】の koko_u_ さんが仰っていることと関連があります。  配列 s[5][1000][2][256] が大きいので、コンパイルまたはリンク時のオプションで  スタックサイズの指定を行い、そのサイズを大きく採っておく必要があります。  コンパイラによりますが、デフォルトだと大体1MBぐらいしか採られないので、デフォ  ルトのままコンパイルして実行するとおそらく異常が発生します。  今回のソースの場合、配列が約2.5MBになるので、スタックサイズは約4MBぐらい  採った方が安全だと思います。  それと、koko_u_ さんも仰っているように、この配列構造だと使われない無駄なエリアが  発生しますので、koko_u_ さんの示されているように、構造体の配列に変更された方が  良いかもしれません。  ※構造体にすることでデータのタイプ(文字列、数値等)を明確にできますし、後の処理   が楽になると思います。 2)2つ目のWhileループがいらない。  ※これは、【ANo.3】の redfox63 さんが仰っていることと同様な事柄です。  配列 s[5][1000][2][256] の3次元目の配列数が 2 となっているのに、このループを通す  ことで配列の上限を超えてアクセスすることになり、異常が発生する可能性があります。  CSVファイル内のデータ記述が2列の場合は問題ないですが、3列以上だった場合は、  問題となります。 3)CSVデータ取り出し用のデリミタにCR/LFを追加した方が良い。  fgets関数で1行テキストを取り出した場合、末尾の改行文字(CR/LF)は削除されずに  取り出した文字列に含まれます。  そのため、ttp=strtok(NULL,",") で抽出した文字列にも改行文字が含まれてしまいます。  余分な改行文字を含めたくない場合は、デリミタ文字列を ",\r\n" とした方が良いと思わ  れます。 4)ファイルクローズをしていない。  CSVファイルの読み出しが終わった後に、ファイルをクローズしていないので、オープン  したままとなり、他のアプリケーションなどからそのCSVファイルをアクセスしようとした  場合にアクセスできない可能性があります。  ひと通りファイルの処理が終了したら、ファイルをクローズした方が良いと思います。 ■修正バージョン 以上の問題点を修正したバージョンを下記に上げてみました。  ・ソース中の//##~~の行は、オリジナルソースの修正前の記述です。  ・配列構造はそのままにしてあります。 参考にして頂ければ幸いです。 ※なお、下記ソースはあくまで一例であり、これがベストな方法ではないので、 ionwide さんご自身でいろいろと対処法・改良点などを考えてみてください。 /* * getcsv.cpp:CSVファイル読込みサンプルプログラム(修正版) */ #include <stdio.h> #include <string.h> int main(void) { FILE *fp; char s[5][1000][2][256]; //←※この配列の為にスタックサイズ指定を大きくする(4MBぐらい?) char tp[256]; char *ttp = NULL; int i=0,ii=0; if((fp=fopen("out1.csv","r"))==NULL){ printf("ファイルオープンできませんよ\n"); return -1; } while(fgets(tp,256,fp)!=NULL) { //##ttp=strtok(tp,","); //←※変更(デリミタにCR/LFを追加) ttp=strtok(tp,",\r\n"); //← 〃 strcpy(&s[0][ii][i][0],ttp); puts(&s[0][ii][i][0]); //##while (ttp != NULL ) { //←※削除(このループはいらない) i++; //##ttp=strtok(NULL,","); //←※変更(デリミタにCR/LFを追加) ttp=strtok(NULL,",\r\n"); //← 〃 if (ttp != NULL ){ strcpy(&s[0][ii][i][0],ttp); puts(&s[0][ii][i][0]); } //##} //←※削除 i=0; ii++;if(ii>=1000)break; } fclose(fp); //←※追加(ファイルクローズ) return(0); }

その他の回答 (5)

  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.6

#「プログラムは思った通りには動かない。書いた通りに動く」という有名な言葉がありまして…… コード自体については概ね他の方が書かれているので、ちょっと前回の回答の補足のようなものを。 前回の質問:http://okwave.jp/qa4340465.html 前回の回答では元コードの修正が少なくなるような形で書きましたが、すでに言われている通り本来は構造体を使うべき処理です。 また数値はint、float等の数値型で持つのが一般的です。 あと、意味のある変数はちゃんと名前をつけておくと後々わかりやすいですよ。 -- example -- typedef struct _tagDatum { char word[32]; // 実際こんなもんあれば問題ないでしょう int value; } datum; datum csv_data[5][1000]; -- example -- 前回の最後にもさらっと触れましたが、データフォーマットが決まっている場合はfscanf()が便利です。 #fgets()で取ったデータをsscanf()でもOK -- example -- int elem = 0; int array_ptr = 0; while((fscanf(fp, "%s,%d\n", &(csv_data[0][elem].word[0]), &(csv_data[0][elem].value)) != 2) && (elem < 1000)) { elem ++; } -- example --

  • php504
  • ベストアンサー率42% (926/2160)
回答No.5

構造体を使ったことが無いのでしょうか これは構造体を使うべき処理なのでこの機会にぜひ#1さんの書かれたような構造体を使った処理を覚えましょう

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.3

> しかし、プログラムが動きません では 何に困っているかが理解できないのですが … 期待する結果と実行結果とその元になるデータを示しましょう 数値データが可変個数なのでしょうか? 3次元目は2つしか確保していないのに2番目3番目のデータが来ると予期しない配列の部分(またはメモリー位置)を書き換えてしまいます 単語,100 といった行のの処理なら このsの宣言でいいのですが 単語,100,200,300 単語,150 単語,60,200 などの 可変個数データには対処不能ですよ

  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.2

当該4次元配列の、各次元に関する説明をお願いいたします。

ionwide
質問者

お礼

s[1番目][2番目][3番目][4番目]とすると、 2番目は1000行のデータを入力するための配列 3番目は単語か、数値データのどちらかを決める配列 4番目は単語または数値データが入る配列 ちなみに1番目はこの配列を5つ用意するつもりでした。

  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.1

えーと。この 4次元配列じゃないとダメなんっすかねえ? 普通に CSV ファイルの 1行を struct csv_data_tag {  char word[WORD_LENGTH];  int value; }; みたいにして欲しい。

関連するQ&A

  • ファイルの入出力に関する質問

    CSVファイルを読み込んで、処理をするプログラムを書いています。 しかし、うまくいきません。 CSVファイルは 単語1,数値データ 単語2,数値データ のようになっており、 これをsの配列に格納したいと思っています。 プログラムは以下の通りなんですが。。。 strtokはhttp://www9.plala.or.jp/sgwr-t/lib/strtok.html を参考にしました。 どなたかおしえていただけないでしょうか? #include<stdio.h> #include <string.h> int main(void) { FILE *fp; char s[1000][1000]; char tp[256]; int i=0; if((fp=fopen("in.csv","r"))==NULL){ printf("ファイルオープンできませんよ\n"); exit(1); } while(fgets(tp,256,fp)!=NULL){ tp=strtok(fp,","); puts(s[i][0]=tp); while (tp != NULL ) { tp = strtok(NULL,","); if (tp= NULL ){ puts(s[i][1]=tp); }}i++; } return(0); }

  • C言語 strtok

    失礼します。現在こちらでアドバイスを頂きfgetcを使用して配列に格納をすることができたのですが、CSVをカンマ区切りで格納したいのですが上手くいかず困っています。strtokを使用方法をドキュメントを読んでもうまく区切ったものを配列に入れる方法がわかりません 何卒よろしくお願いします。 ソースコード #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include<string.h> #define MAXITEM 1400 int split(char *str, const char *delim, char *outlist[]) { char *tk; int cnt = 0; tk = strtok(str, delim); while (tk != NULL && cnt < MAXITEM) { outlist[cnt++] = tk; tk = strtok(NULL, delim); } return cnt; } int main(void) { FILE *fp; char *fname = "testfile.csv"; char *tp; char *array[1400]; char *test[11][1400]; char c; int i = 0; int n,y; char *tp[1400]; fp = fopen(fname, "r"); if (fp == NULL) { printf("%sファイルが開けません¥n", fname); return -1; } while ((c = fgetc(fp)) != EOF) { array[i] = (char)c; i++; } tp = strtok(array, ","); puts(*tp); while (tp != NULL) { tp = strtok(NULL, ","); if (tp != NULL)puts(tp); } for (n = 0; n < 11; n++) { for (y = 0; y < 1400; y++) { test[n][y] = tp[y]; printf("%c", test[n][y]); } } fclose(fp); return 0; }

  • ポインタについて

    途中までのソースコード typedef struct node{ char moji[128]; --------(1) }NODE; int main(int argc, char *argv[]){ FILE *fp; char buf[128]; NODE p[128]; char *tp; int i = 0; int j,k; int res; NODE temp; fp = fopen(argv[1],"r"); while(fscanf(fp,"%s",&buf) == 1){ tp = strtok(buf," ,.-"); strcpy(p[i].moji,tp); ---------(2) i++; while(tp != NULL){ tp = strtok(NULL," ,.-"); if(tp != NULL){ strcpy(p[i].moji, tp); --------(2) i++; } } } for(j = 0;j < i; j++) puts(p[j].moji); return 0; } file.txt これ以下の文字を読み込む -------------- The Java programming language is a general-purpose, concurrent, class-based, object-oriented language. It is designed to be simple enough that many programmers can achieve fluency in the language. 例えばこんなソースコードがあって、(1)をポインタにして、(2)のstrcpyを使わずにポインタだけで表現するとしたらどのようになるんですか?

  • C言語で、ファイルを読み込んで数字と名前に分けて配列に格納に関する質問

    C言語で、ファイルを読み込んで数字と名前に分けて配列に格納に関する質問です! ファイルを開いた後でエラーとなるのですが、何が足りないのでしょうか? ファイル内容 20 田中 10 鈴木 #include <stdio.h> #include <string.h> #include <stdlib.h> int main(int argc,char *argv[]) { FILE *fp; char str[256]; char *tp; int k,i=0; int num[10]; char na[10][20]; fp=fopen(argv[1],"r"); if(fp==NULL){ printf("ファイルを開けません\n"); return 1; }else{ printf("開けた\n"); } while(fgets(str,sizeof str,fp)!=NULL){ tp=strtok(str," "); num[i]=atoi(tp); tp=strtok(NULL," "); strcpy(na[i],tp); i++; } printf("%d\n%s\n",num[0],na[0]); printf("%d\n%s\n",num[1],na[1]); fclose(fp); return 0; }

  • C言語でファイルの内容を strtok関数 を使って数字と文字を分けて

    C言語でファイルの内容を strtok関数 を使って数字と文字を分けて配列に格納したいのですが、うまくできません。 どこが駄目なのかご指摘をお願いします! ファイル内容 20 田中 10 鈴木 #include <stdio.h> #include <string.h> #include <stdlib.h> int main(int argc,char *argv[]) { FILE *fp; char str[256]; char *tp; int i=0; int num[10]; char na[10]; fp=fopen(argv[1],"r"); while(fgets(str,sizeof str,fp)!=NULL); tp = strtok ( str, " " ); while(tp != NULL ) { num[i]=atoi(tp); tp = strtok( NULL," "); if ( tp != NULL ){ na[i]=*tp; } i++; } printf("%d\n%s",num[0],na[0]); printf("%d\n%s",num[1],na[1]); fclose(fp); return 0; }

  • csvファイルを構造体に格納したいです

    ファイル内容 ******************** あいう,,さしす たちつ,なにぬ,はひふ まみむ,, あいう,win, ******************** #include <stdio.h> #include <string.h> #define MBF 256 struct tb{ char aaa[32]; char bbb[32]; char ccc[32]; }; int main(){ struct tb tbl[20]; struct tb *tp; int ntb,itb; FILE* fi; FILE* fo; char buff[MBF]; // 入力 fi = fopen("sample.csv","r"); // 検査省略 if( fi == NULL ){ printf( "%sファイルが開けません\n" ); return -1; } ntb = 0; while ( fgets(buff,MBF,fi ) != NULL ) { strcpy(tbl[ntb].aaa,strtok(buff,",")); strcpy(tbl[ntb].bbb,strtok(NULL,",")); strcpy(tbl[ntb].ccc,strtok(NULL,",")); ntb++; } fclose( fi ); // 出力 fo = fopen("csvo.csv","w"); if( fo == NULL ){ printf( "%sファイルが開けません\n" ); return -1; } for ( itb=0;itb<ntb;itb++ ) { tp = tbl+itb; fprintf(fo,"%s%s%s",tp->aaa,tp->bbb,tp->ccc); } fclose( fo ); return 0; } csvファイルないようが以下であれば格納できるけど、すごく困ってます。 ******************** あいう,かきく,さしす たちつ,なにぬ,はひふ まみむ,やゆよ,らりる ********************

  • csvファイルを構造体に格納したいです

    ファイル内容 ******************** あいう,,さしす たちつ,なにぬ,はひふ まみむ,, あいう,win, ******************** #include <stdio.h> #include <string.h> #define MBF 256 struct tb{ char aaa[32]; char bbb[32]; char ccc[32]; }; int main(){ struct tb tbl[20]; struct tb *tp; int ntb,itb; FILE* fi; FILE* fo; char buff[MBF]; // 入力 fi = fopen("sample.csv","r"); // 検査省略 if( fi == NULL ){ printf( "%sファイルが開けません\n" ); return -1; } ntb = 0; while ( fgets(buff,MBF,fi ) != NULL ) { strcpy(tbl[ntb].aaa,strtok(buff,",")); strcpy(tbl[ntb].bbb,strtok(NULL,",")); strcpy(tbl[ntb].ccc,strtok(NULL,",")); ntb++; } fclose( fi ); // 出力 fo = fopen("csvo.csv","w"); if( fo == NULL ){ printf( "%sファイルが開けません\n" ); return -1; } for ( itb=0;itb<ntb;itb++ ) { tp = tbl+itb; fprintf(fo,"%s%s%s",tp->aaa,tp->bbb,tp->ccc); } fclose( fo ); return 0; } csvファイルないようが以下であれば格納できるけど、すごく困ってます。 ******************** あいう,かきく,さしす たちつ,なにぬ,はひふ まみむ,やゆよ,らりる ********************

  • CSVファイルの内容を構造体に格納したい(Unix使用)。

    こんにちは。私は30代の男性です。 「名前」「身長」「体重」が記載されたCSVファイルの内容を読み取って、構造体の「name」「height」「weight」に格納するプログラムを作っています。CSVの内容は A,175,80 B,167,89 C,155,45 ・ ・ ・ Z,188,70 だと仮定します。数値が読み取れているか、下記のように「tp = strtok(file_image, ",\n" );」の前後に「printf("%s\n", file_image);」を置いてみたら、strtok前では全て表示されるのに、strtok後では「ABC」しか表示されません。これでは全てのデータを構造体に格納できないので、困っています。 1.どのようにすれば、数字も取り出せる(読み取れる)でしょうか? 2.効率よく構造体に格納するには、どのようにしたらよいでしょうか? アドバイスを頂ければ幸いです。宜しくお願いいたします。 #include <stdio.h> #include <stdlib.h> #include <limits.h> #include <string.h> int main(int argc, char *argv[]) { FILE *fp = NULL; int rtn = 0; if ((fp = fopen(argv[1], "r")) == NULL) { printf("ファイルオープンに失敗しました。\n"); return 1; } if (argc != 2) { printf("ERROR: オプションの数に過不足があります。\n"); return 1; } rtn = change_csv(fp); return 0; } int change_csv(FILE *fp) { int i; int j; char file_image[256]; /* 読み込んだ先のメモリの領域 */ char *tp; for (i = 0; i <= 256; i++) { if (fgets(file_image, 256, fp) == NULL) { if (ferror(fp) != 0) { printf("ERROR: 読み込みに失敗しました。\n"); return 1; } } if (feof(fp) != 0) { break; } printf("%s\n", file_image); tp = strtok(file_image, ",\n" ); printf("%s\n", file_image); } fclose(fp); return 0; }

  • Borland C CSVファイル読み込み

    CSVファイルを読み込み、読み込んだ値で計算を行うプログラムを作っています。 ・環境はWindows VISTA UltimateでBorland C++ Compiler 5.5  ・CSVファイルのデータの形式は 1,4532 4,2131 6,4301 . . ・データ数は決まっていて今のところ全部で12個 そして以下のようにCSVの読み込みプログラムを試しに組んだ所、実行時エラーがでました。 #include <stdio.h> #include <stdlib.h> #include <string.h> void main(void) { int AN[11][1]; int i=0,j=0,c=0; char buff[1024], *tp; FILE *fp; /*配列初期化*/ for(i=0;i<11;i++) { for(j=0;j<2;j++) { AN[i][j]=0; } } fp=fopen("test1.csv","r"); if(fp==NULL) { /* オープン失敗 */ printf("ファイルがオープンできません\n"); exit(1); /* 強制終了 */ } while( fgets(buff, 1024 , fp) != NULL ) { tp=strtok(buff , ","); if (tp !=NULL) {AN[i][j] = atoi(tp);} printf("%d\n",AN[i][j]); tp = strtok(NULL , ","); if (tp !=NULL) {AN[i][j+1] = atoi(tp);} printf("%d\n",AN[i][j+1]); i++; } fclose(fp); } 実行するとファイルクローズの後、問題が発生したためプログラムを終了しましたと出ます。"AN[i][j]=atoi(tp)"の配列部分を単純に変数にするとこのようなエラーは出ないのですが。 なぜエラーが出るのか、どなたかご教授願います。

  • strtokのしくみについて

    よろしくお願い致します。 strtokは以下のように使いますよね。 (と言っても今回初めて使うのですが) 1回目はstrを渡しているので自然ですが、2回目以降はNULLですよね。なのにどうしてstrを続けて分解するということが出来るのでしょうか? うまく説明できませんが、要はstrtokはどういうコードで実現されているのでしょうか? int main(void) { char str[] = "ABCD ef.1234.G"; char *tp; /* スペース.を区切りに文字列を抽出 */ tp = strtok( str, " ." ); puts( tp ); while ( tp != NULL ) { tp = strtok( NULL," ." ); if ( tp != NULL ) puts( tp ); } return 0; }