• ベストアンサー

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秒以内を目指しています。 どなたかご教授御願いいたします。

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

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

No.6です。 >やっぱりポインタはイコールでつなげられないんですか。 ポインタ同士で代入(右辺のアドレスを左辺に入れる等)はできます。 まず、エラーの意味を理解してください。 簡単に書けば「型が違うから代入できない」と言っているのです。 No.6の -------- >char str[MM],*p1, *p2,ymd1[20], ymd2[20]; と定義しているのに、 >ymd1 = p1; のような使い方はできませんよ。 -------- について理解されていますでしょうか? >char str[MM],*p1, *p2,ymd1[20], ymd2[20]; をわかりやすいように分解します。 -------- char str[MM]; char *p1; char *p2; char ymd1[20]; char ymd2[20]; -------- p1、p2は「char型のポインタ」 str[]、ymd1[]、ymd2[]は「char型の配列」です。 >ymd1 = p1; は、ymd[0]に対してp1に格納されているアドレスを代入しようとしているためエラーとなっています。 ひとつアドバイス。 どんなに短いプログラムでも、どこで何の処理を行うのかコメントは降っておいた方が理解しやすいと思う。

yxia001
質問者

補足

有難う御座います。 コメントは今度から、振るように心がけたいと思います。 プログラムの直しも早速挑戦したいと思います

その他の回答 (6)

回答No.6

No.5 >ポインタの比較はできないってコンパイルできないので、 その際にエラーメッセージで行数は表示されませんでしたか? >char str[MM],*p1, *p2,ymd1[20], ymd2[20]; と定義しているのに、 >ymd1 = p1; のような使い方はできませんよ。

yxia001
質問者

補足

エラーの内容は test4.c: In function ‘main’: test4.c:27: error: incompatible types in assignment test4.c:36: error: incompatible types in assignment こう出ます。 やっぱりポインタはイコールでつなげられないんですか。 別の手法でいくしかないみたいですね。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.5

「セグメンテーション違反を直す」のは当然として, 「どこに時間がかかっているのか」をきちんと把握できていますか? #2 でも書かれていますが, 「どうしても必要な時間」より速くはできません. ちなみに sum[ymd] ではコンパイルエラーにはならないです>#1. C では a[x] において「a と x の一方が整数, もう一方がポインタ」なら (その他いくつか条件はあるけど) OK です.

yxia001
質問者

補足

限界を超えてまで早くしようとは思ってません。 目標は、目標として前回よりも早くなればいいんです。 あの、つまらない質問だと思うんですがポインタとポインタってstrcmpで比較する方法ってないんでしょうか? ちょっとスクリプトを変えたんですが #include <stdio.h> #include <string.h> #include <time.h> #define MM 256 int main() { FILE *fp; char str[MM],*p1, *p2,ymd1[20], ymd2[20]; int num, sum=0; clock_t start,end; start = clock(); fp = fopen("/data/testdata/journal/j080240.csv","r"); if(fp == NULL){ printf("ファイルが開けませんでした。\n"); return(0); } num=1; fgets(str, sizeof(str), fp); while(fgets(str, sizeof(str), fp) != NULL && num==1){ p1 = strtok(str, ","); p1 = strtok( NULL,","); ymd1 = p1; p2 = strrchr(str,','); sum = atoi(p2+1); num = 2; } while( fgets(str, sizeof(str), fp) != NULL && p1 != NULL){ p1 = strtok(str, ","); p1 = strtok(NULL,","); p2 = strrchr(str,','); ymd2 = p1; if ( p2 != NULL ) { if(strcmp(ymd1,ymd2) != 0){ printf("%s ,%d \n",ymd1,sum); strcpy(ymd1,ymd2); }else{ sum += atoi(p2+1); } } } printf("%s ,%d \n",ymd2,sum); fclose(fp); end=clock(); printf("%.2f秒\n",(double)(end-start)/CLOCKS_PER_SEC); return(0); } という風に変えたんですが、ポインタの比較はできないってコンパイルできないので、ポインタの比較ができないなら、別のアプローチを考えなきゃいけないんですが...

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

3秒ですか メモリに余裕があるのならファイルを全部メモリに読み込んでから処理すれば少しは速くなるかも あと日付が必ず同一日は連続しているとかいう保証があればプログラムも楽になりそうですが

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

C/C++に連想配列はありません。自作するなり、C++でstlなどを使います。 あと、文字列の扱いがぜんぜんなっていません。 全体的なアルゴリズムも間違っています。

  • hidebun
  • ベストアンサー率50% (92/181)
回答No.2

3秒の処理速度を実現するのは、難しそうでしょうねぇ。 対象ファイルのサイズは、200~300MBぐらいはあるのではないでしょうか? 読み出しメディアのスペックが、例えば40MB/secなら、 どれだけプログラムが速くても、5秒以上かかりますよ。

yxia001
質問者

補足

そうなんですか。 前に、むちゃくちゃに書いたスクリプトで実行したら、15秒以上かかってしまって。 これでは、使い物にならないとの事だったので、さらに早くしようと書き直している最中なんです。

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

>char str[MM],*p1, *p2,*ymd; >int num, sum; >sum[ymd] = atoi(p2+1); sumの定義と使い方が食い違っています。コンパイルエラーは出なかったのですか? char *型のymdを、配列の添字として使えるのですか?

yxia001
質問者

補足

コンパイルでは、エラーが出なかったんです。 ただ、実行するとセグメンテーション違反です、とでるだけで。 sumの定義が違いますか... C言語に触れるのも、結構久しぶりなので使い方を結構忘れていて、うろ覚えな感じで書き出したので。 最初から調べなおしてみたいと思います。