• ベストアンサー

csvファイルの実績データをC言語で解析するのですが...

C言語を学び始めたばかりなのに、csvファイルの実績データでフィールドが15あり、レコード数が1000000近くあるファイルの15番目のフィールドを足し合わせて、出力するということをやっているのですが、まだまだわからないことだらけです。 1レコード目がカラム名なので2レコード目から足し合わせるんですがそこのところもよくわからずじまいで... 一応、書いたプログラムが #include <stdio.h> #include <stdlib.h> #include <string.h> int main() { FILE *fp; char buffer[50],*p; int cnt, num, sum; fp = fopen("j0.csv","r"); if(fp == NULL){ printf("ファイルが開けませんでした。\n"); exit(-1); } while(fgets(buffer,fp) != NULL){ p = strtok(buffer,","); cnt = 1; while(p!=NULL){ num = atoi(p); printf("%d:%d,",cnt,num); p = strtok(NULL,","); cnt++; if(cnt==15) sum=sum+num } printf("\b\b \n"); } printf(%d \n",num); fclose(fp); return(0); } と書いたんですが、ぜんぜんな状態です。誰かご教授願えませんか?

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

  • ベストアンサー
  • nda23
  • ベストアンサー率54% (777/1415)
回答No.2

while(fgets(buffer,fp) != NULL){ p = strtok(buffer,","); cnt = 1; while(p!=NULL){ num = atoi(p); printf("%d:%d,",cnt,num); p = strtok(NULL,","); cnt++; if(cnt==15) sum=sum+num }     ↓ sum = 0; //初期化 while( fgets(buffer, sizeof(buffer), fp) != NULL){   p = strrchr(buffer,','); //カンマを後ろから探す   if ( p == NULL ) {     //カンマが無い→オカシイデータの処理   } else {     sum += atoi(p+1); //カンマの次の文字から変換   } } もし、49バイト以上の行、カンマが14個でない行、このようなデータが あると、正しく動作しません。また、カンマの直後に空白があったり しても上手く変換できないことがあります。

fzgu1984
質問者

補足

早速書き直してみたんですが、 #include <stdio.h> #include <stdlib.h> #include <string.h> int main() { FILE *fp; char buffer[50],*p; int cnt, num, sum; fp = fopen("j0.csv","r"); if(fp == NULL){ printf("ファイルが開けませんでした。\n"); exit(-1); } sum = 0; while( fgets(buffer, sizeof(buffer), fp) != NULL){   p = strchr(buffer,',');   if ( p == NULL ) {        } else {     sum += atoi(p+1);   } } printf("%d \n",sum); fclose(fp); return(0); } これで、実行してみたら、大量のerror: stray ~ in program というエラーが出てきて、こんなエラーはじめてみたので今、ひっちゃかめっちゃかになってしまっているんですが、どうしたらよいでしょうか?

その他の回答 (3)

  • nda23
  • ベストアンサー率54% (777/1415)
回答No.4

もしかしてコピペした? インデントに漢字空白を使っているので、回答をそのままコピペ するとエラーになってしまいますよ。

fzgu1984
質問者

お礼

有賀と御座います。無事に動きました。 これで何とか、次の作業に移れそうです。

  • titokani
  • ベストアンサー率19% (341/1726)
回答No.3

CSVは本式にやると非常に大変ですが、一行のフォーマットによっては、sscanfが便利です。 例えば、一行の内容が 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 と、すべて数値なら、 int num; sscanf(buffer,"%*d,%*d,%*d,%*d,%*d,%*d,%*d,%*d,%*d,%*d,%*d,%*d,%*d,%*d,%d",&num) ; でnumに15番目の値が入ります。 念のため、sscanfの戻りをチェックするといいでしょう。

fzgu1984
質問者

お礼

ssanfというものがあることを知りませんでした。早速、調べてみます。

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

>ぜんぜんな状態です。 具体的に書いてください。 ソースをざっと見たところでは、少なくとも 1)fgetsの引数の再確認 2)sumの初期化(足し込んでいくので初期値はゼロ) が必要です。他にも問題点があるかもしれません。

関連するQ&A

  • 1000000レコードもあるcsvファイルの実績データをC言語で計算しているのですが...

    C言語を学び始めたばかりなのに、csvファイルの実績データでフィールドが15あり、レコード数が1000000近くあるファイルの15番目のフィールドを足し合わせて、出力するということをやっているのですが、まだまだわからないことだらけです。 一応、書いたプログラムが #include <stdio.h> #include <stdlib.h> #include <string.h> int main() { FILE *fp; char buffer[50],*p; int cnt, num, sum; fp = fopen("j0.csv","r"); if(fp == NULL){ printf("ファイルが開けませんでした。\n"); exit(-1); } while(fgets(buffer,fp) != NULL){ p = strtok(buffer,","); cnt = 1; while(p!=NULL){ num = atoi(p); printf("%d:%d,",cnt,num); p = strtok(NULL,","); cnt++; if(cnt==15) sum=sum+num } printf("\b\b \n"); } printf(%d \n",num); fclose(fp); return(0); } と書いたんですが、ぜんぜんな状態です。誰かご教授願えませんか?

  • C言語でcsvファイルの日別の金額を足し合たいんですが..

    csvファイルのフィールドが15あるうちの2番目に日にち、15番目に金額が書いてあり、日にちには同じ日がいくつもあるので、その金額をそれぞれ足し合わせたものを出力するというものをやろうとしているのですが、C初心者何ですけど一応書いたプログラムが #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> int main(void) { char buffer1[512], buffer2[512],*p,*tp; FILE *fp; int i,j,num,sum; clock_t start,end; start = clock(); fp=fopen("j0.csv","r"); if(fp == NULL){ printf("ファイルが開けませんでした。\n"); exit(-1); } sum=0; while(fgets(buffer1,256,fp)!=NULL && fgets(buffer2,256,fp)!=NULL){ tp = strchr(buffer1, ','); p = strchr(buffer2, ','); tp = strchr(p+1, ','); for(j=0;j<13;j++) p = strchr(p+1, ','); num=atoi(p+1); sum+=num; if(tp==tp+1); sum+=atoi(p+1); else{ printf("%cでは%d円であった。\n",tp,sum); sum=0; } } return 0; } こんな感じなんですが、どうかご指導御願いします。

  • c言語でcsvファイルの処理で、処理速度が速いプログラムを書こうと思っ

    c言語でcsvファイルの処理で、処理速度が速いプログラムを書こうと思っています。 以下のようなcsvファイル、件数は約10000000件以上あるものを使います shop,ymd,gend,age,area,amt 20,2008-05-01,3,5,014,128 22,2008-05-01,2,4,015,350 : 二列目の日別、つまりymd別に最後列のamdの小計を出したいんですが、組んだプログラムを実行してみると、セグメンテーション違反ですと出てしまうんです。以下のようなプログラムを組んだんですが #include <stdio.h> #include <string.h> #include <time.h> #define MM 256 int main() { FILE *fp; char str[MM],*p1, *p2,*ymd; int num, sum; clock_t start,end; start = clock(); fp = fopen("csv.csv","r"); if(fp == NULL){ printf("ファイルが開けませんでした。\n"); return(0); } sum = 0; fgets(str, sizeof(str), fp); while(fgets(str, sizeof(str), fp) != NULL){ p1 = strtok(str, ","); p1 = strtok( NULL,","); ymd = p1; p2 = strrchr(str,','); sum[ymd] = atoi(p2+1); break; } while( fgets(str, sizeof(str), fp) != NULL && p1 != NULL){ p1 = strtok(str, ","); p1 = strtok( NULL,","); p2 = strrchr(str,','); if ( p2 != NULL ) { if(ymd == p1){ sum[ymd] += atoi(p2+1); }else{ printf("%s ,%d \n",ymd,sum[ymd]); strcpy(ymd,p1); } } } printf("%s ,%d \n",p1,sum); fclose(fp); end=clock(); printf("%.2f秒\n",(double)(end-start)/CLOCKS_PER_SEC); return(0); } うまくいきません。大体、処理速度は3秒以内を目指しています。 どなたかご教授御願いいたします。

  • 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; }

  • 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; }

  • C言語のqsortについて

    現在、qsortのコードに取り組んでいます。 if (strcmp(ad, "ASC") == 0) { qsort(sin, sizeof(cnt), sizeof(sin[0]), cmp_u); } else { qsort(sin, sizeof(cnt), sizeof(sin[0]), cmp_d); } 恐らくこちらのqsortでの第二引数が書き方を間違えていると思うのですが、修正の方法が分からず、どなたか教えて頂けないでしょうか? #include <stdio.h> #include <time.h> #include <string.h> #include <stdlib.h> static char ad[10]; int cmp_u(const void* a, const void* d) { return strcmp((char*)a, (char*)d); } int cmp_d(const void* a, const void* d) { return strcmp((char*)d, (char*)a); } int main() { int num1, num2; char op; float answer; int r,i; FILE* fp; char c[11]; char sin[1000][1000]; char ad[8]; fp = fopen("log.txt", "a+"); if (fp == NULL) { printf("ファイルオープン失敗\n"); return -1; } while (1) { r = scanf("%d%c%d", &num1, &op, &num2); if (r != 3) { puts("input error"); return 1; } if (op == '+') { answer = num1 + num2; } else if (op == '-') { answer = num1 - num2; } else if (op == '*') { answer = num1 * num2; } else if (op == '/') { answer = (float)num1 / num2; } time_t t = time(NULL); struct tm* tm = localtime(&t); printf("%d/%02d/%02d ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); printf("%02d:%02d:%02d ", tm->tm_hour, tm->tm_min, tm->tm_sec); printf("%d%c%d,%f\n", num1, op, num2, answer); fprintf(fp, "%d/%02d/%02d ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); fprintf(fp, "%02d:%02d:%02d ", tm->tm_hour, tm->tm_min, tm->tm_sec); fprintf(fp, "%d%c%d,%f\n", num1, op, num2, answer); printf("計算を続けますか?"); scanf("%s\n", &c); if (strcmp(c, "no") == 0) { break ; } } fclose(fp); fp = fopen("log.txt", "r"); int cnt = 0; for (i = 0;i < 1000;i = i + 1) { if (fgets(sin[i], sizeof(sin[0]), fp)) ++cnt; else break; } fclose(fp); printf("ASC or DESC: "); scanf("%s", ad); if (strcmp(ad, "ASC") == 0) { qsort(sin, sizeof(cnt), sizeof(sin[0]), cmp_u); } else { qsort(sin, sizeof(cnt), sizeof(sin[0]), cmp_d); } for (i = 0;i < cnt;i = i + 1) { printf("%s", sin[i]); } 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)"の配列部分を単純に変数にするとこのようなエラーは出ないのですが。 なぜエラーが出るのか、どなたかご教授願います。

  • C言語の質問です。

    前にも質問したのですがなかなかうまくいかないのでよろしくお願いします。 データの書いてあるファイルを読み込んで処理するプログラムを書きたいと考えています。 読み込むデータ 0.012500 0.499167 1.382500 1.534444 2.489167 3.635000 3.775000 5.407500 5.705000 5.916667 6.115833 6.295278 6.825278 7.079722 . . . . この様な数値のかいてあるデータを使って0.5ずつに区切ってその中に何個データがあるか数えたいと考えています。(データは1万5千個以上あります) 例えば上のデータで考えると 0~0.5の範囲のデータは2個 0.5~1の範囲のデータは0個 1~1.5の範囲のデータは1個 1.5~2の範囲のデータは1個 2~2.5の範囲のデータは0個。。。 という風に数えるプログラムにしたいです。 僕が分からないところはどのように場合分けしていくか。。。です。 #include<stdio.h> //#include<process.h> int main(void) { FILE *fp; double n; int cnt,i,Cnt; fp=fopen("1.dat","r"); if(fp==NULL) { printf("file open error!!\n"); exit(1); } i=0; cnt=0; Cnt=0; while(fscanf(fp,"%lf\n",&n)!=EOF){ if(i<=n<(i+0.5)){ cnt++; printf("%lf %d\n",i,cnt); } else if((i+0.5)<=n<(i+1)){ Cnt++; printf("%lf %d\n",i,Cnt); } else{ i++; } } fclose(fp); return 0; } 僕の考えはデータを読み込む 変数 i を使って if文で i <= n <i+0.5の範囲のときはcntを足していく     i+0.5<= n <i+1の範囲のときはCntを足していく それ以外のときは i を+1して同じことを繰り返す というようなやり方を考えました。 しかしうまくいきませんでした。 どのようにすればよいでしょうか。 よろしくお願いします。

  • C言語についてアドバイスをください。

    CSVファイルの内容をfreadで読み込み、strtokを使わずにbuffに格納した後、 buffから1文字ずつbuff2へコピーさせていって、コンマがきたら数字、 改行がきたら名前と判別して、自作関数に渡して表示させたいです。 CSVファイルの内容は 『11,名前1(改行) 15,名前2(改行) 18,名前3』 といった感じです。 ------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE 1 #include <stdio.h> #include <string.h> #include <stdlib.h> #define NUM 256 struct kou { short nenrei; char namae[30]; }; void pri(struct kou *o) { printf("%d\n%s\n",o->nenrei,o->namae); } int main(void) { FILE *fp; // ファイルポインタ char buff1[NUM] = {0}; char buff2[NUM] = {0}; char *fname = "text1.csv"; // ファイル名を指定 short i = 0; int n = 0; struct kou p; fp = fopen(fname, "r"); if(fp == NULL) { printf("%sファイルをオープンできませんでした。\n",fname); } fread(buff, 1, NUM, fp); while(buff1[n] != NULL) { buff2[n] = buff1[n]; // buff2[0]からbuff1の中を一文字ずつコピーしていく。 if(buff2[n] == ',') // buff2に格納されていく中にコンマがきたら以下の作業を行う。 { i = (short)atoi(buff2); // char型からshort型への変換 p.nenrei = i; } if(buff2[n] == '\n') { strcpy(p.namae,buff2); // p.namaeにbuff2をコピー。 pri(&p); } n++; } fclose(fp); printf("ファイルをクローズしました。\n"); return 0; } ------------------------------------------------------- 今のままだと 『11 11,名前1 11 11,名前1 15,名前2』 という表示になってしまいます。 while 内で既に読み込んだ部分を読み込ませないよう(表示させないよう)にできたら良いと思うんですが、そういったやり方はあるのでしょうか? むしろやり方を変えたほうが良いでしょうか・・・。 まだC言語を学び始めて日が浅いので、色々間違っている部分もあると思いますが、 そういったことを含めてアドバイスをいただけたらと思います。 よろしくお願いします。

専門家に質問してみよう