• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:test.csvの内容が以下のように100件位あったとして、)

ソート機能を追加したCSVファイルの作成プログラム

このQ&Aのポイント
  • test.csvの内容を読み込み、2列目をキーとして昇順にソートし、「test1.csv」に書き込むプログラムを作成しました。
  • さらに、ソートされたデータからキリのいい位置のデータを抜き出して「test2.csv」に書き込む処理も追加しました。
  • しかし、ソートの段階でエラーが発生し、プログラムの実行が途中で止まってしまいます。ソート処理の修正方法についてアドバイスをいただけないでしょうか?

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

  • ベストアンサー
  • anicicle
  • ベストアンサー率36% (129/356)
回答No.5

No.4 >tbpはキャスト必要でしたか…参考にしたHPにはキャストする必要無いみたいな事書いてあったので… malloc()の戻りは「void *」です。利用には通常キャストが必要です。 >>struct tb tbl[SIZE]; (中略) >また、他にもwhile文やfprintf文のtblも同様に書き換えなければいけないんですよね? はい。 malloc()で確保したメモリは「確保しただけ」です。 確保したものを利用するためにはtbl[]の部分は全て変更が必要です。

yamaomoto
質問者

補足

いつもありがとうございます。 anicicle様の的確なアドバイスのおかげで無事、「Segmentation fault」も出ることなく 大きなデータでもcsvファイルソートが出来る事が出来ました。 一応同じ悩みの方が出てきた時用に、ソースを残しておきます。(コンパイル済み) #include <stdio.h> #include <stdlib.h> #include <string.h> #define NAME "test.csv" #define NAME1 "test1.csv" #define NAME2 "test2.csv" #define SIZE 1024 struct tb{ char a[SIZE]; char b[SIZE]; char c[SIZE]; }; int comp(const void *, const void *); int main(void) { struct tb *tbp; //構造体のポインタ FILE *fp,*fq,*fr; char buff[SIZE], string_buff[SIZE]; int j,n; tbp =(struct tb *)malloc(sizeof(struct tb)*SIZE); //メモリの確保 if((fp=fopen(NAME,"r")) == NULL){ printf("ファイル%sが開けません\n",NAME); return -1; } if((fq=fopen(NAME1,"w")) == NULL){ printf("ファイル%sが開けません\n",NAME1); return -1; } if((fr=fopen(NAME2,"w")) == NULL){ printf("ファイル%sが開けません\n",NAME2); return -1; } j=0; while(fgets(buff,SIZE,fp)!=NULL){ if( j>= SIZE ){ printf("buffer Over!"); break; } strcpy((tbp+j)->a,strtok(buff,",\"")); strcpy((tbp+j)->b,strtok(NULL,",\"")); strcpy((tbp+j)->c,strtok(NULL,",\"")); j++; } fclose(fp); printf("test.csvの表示"); for(n=0; (n<j) && (n<SIZE); n++){ printf("%s %s %s\n",(tbp+n)->a,(tbp+n)->b,(tbp+n)->c); } printf("\n"); qsort(tbp, j, sizeof(struct tb), comp); printf("ソート後\n(test2.csv?)"); for(n=0; (n<j) && (n<SIZE); n++){ printf("%s %s %s\n",(tbp+n)->a,(tbp+n)->b,(tbp+n)->c); fprintf(fq,"%s,%s,%s\n",(tbp+n)->a,(tbp+n)->b,(tbp+n)->c); } fclose(fq); printf("\n"); printf("キリのいい所だけ(test3.csv?)\n"); for(n=0; (n<j) && (n<SIZE); n++){ if(n%10==0){ //「%10」ここを変えればキリ番を自由に設定可 printf("%s %s %s\n",(tbp+n)->a,(tbp+n)->b,(tbp+n)->c); fprintf(fr,"%s,%s,%s\n",(tbp+n)->a,(tbp+n)->b,(tbp+n)->c); } } fclose(fr); printf("\n"); free(tbp); //メモリの開放 return 0; } int comp(const void *_p0, const void *_p1) { struct tb *p0 = (struct tb *)_p0; struct tb *p1 = (struct tb *)_p1; return strcmp(p0->b, p1->b); //ここを変えれば好きなキー(列)でソート可 } 本当にありがとうございました。

その他の回答 (4)

  • anicicle
  • ベストアンサー率36% (129/356)
回答No.4

No.1、3です。 ソースがどうりだとしたら、これコンパイル通りませんよ? 軽くコンパイラを通して文法チェックしただけですが ----------------------- >int main(main) int main(void) >struct tb tbl[SIZE]; mallocで使用するように変更したのなら不要。変数宣言自体がメモリの無駄遣い >tbp =malloc(sizeof(struct tb)*件数); //メモリの確保?(追加) tbp = (struct tb *)malloc(sizeof(struct tb)*SIZE); //メモリの確保?(追加) >if((fq=fopen(NAME1,"w")) == NULL){ >if((fq=fopen(NAME2,"w")) == NULL){ 定義がない >fprintf("%s %s %s\n",tbl[n].a,tbl[n].b,tbl[n].c); fprintf(fp, "%s %s %s\n", tbl[n].a, tbl[n].b,tbl[n].c); >fcolse(fq); fclose(fq); ----------------------- に問題があります。 ソース通りで、exeファイルを実行したとしたら、それは「コンパイルができていた」時点の古いものです。 よく作成日時を確認してみてください。 それとmalloc()で確保した「tbp」を使用するなら、根本的に「tbl」の部分の置き換えも必要です。

yamaomoto
質問者

補足

ご指摘ありがとうございます。ご指摘頂いた所はコピペミスでした。 大変失礼致しました。 tbpはキャスト必要でしたか…参考にしたHPにはキャストする必要無いみたいな事書いてあったので… >>struct tb tbl[SIZE]; >mallocで使用するように変更したのなら不要。変数宣言自体がメモリの無駄遣い という事ですが、これを消すとqsortエラーが出るのですが、これも >根本的に「tbl」の部分の置き換えも必要です。 という事で書き換えで何とかなるという事ですよね? また、他にもwhile文やfprintf文のtblも同様に書き換えなければいけないんですよね? 質問ばかりでほんとすいません。

  • anicicle
  • ベストアンサー率36% (129/356)
回答No.3

No.1です。 >しかし大きなデータのcsvファイルにしたら「Segmentation fault」に 「Segmentation fault」の原因は「メモリアクセスの不備」によるものです。 確保していない領域をアクセスすることが主な原因です。 目立つところでは、 >struct tb tbl[SIZE]; ですね。 最低でも(SIZE*3)*SIZE、1024なら、3MByte、コレだけの領域をローカル変数で確保することはできないと考えたほうがいいでしょう。 tblはmalloc()で領域を確保してください。 >while(fgets(buff,SIZE,fp)!=NULL) も危険です。 読み込むデータの件数が超えた場合に問題が発生します。 while(fgets(buff,SIZE,fp)!=NULL) { __j++; __if( j>= SIZE ) __{ ____printf("buffer Over!"); ____break; __} } のようにフェイルセーフは入れておくべきです。 >for( n = 0; n < j; n++ ) も同様。 for( n = 0; (n < j) && (n < SIZE); n++ ) としておくと危険度が減ります。

yamaomoto
質問者

補足

チェックありがとうございます。また自分なりに修正してみたのですが(と言ってもアドバイス頂いた所をバカ正直に直してみただけですが…) まだ、「Segmentation fault」になるという事はまだ、どっかが足りないという事ですよね。 もしかしたら、修正すら上手くいって無いとか… #include <stdio.h> #include <stdlib.h> #include <string.h> #define NAME "test.csv" #define SIZE 1024 struct tb{ char a[SIZE]; char b[SIZE]; char c[SIZE]; }; int comp(const void *, const void *); int main(main) { struct tb tbl[SIZE]; struct tb *tbp; //構造体のポインタ(追加) FILE *fp,*fq,*fr; char buff[SIZE], string_buff[SIZE]; int j,n; tbp =malloc(sizeof(struct tb)*件数); //メモリの確保?(追加) if((fp=fopen(NAME,"r")) == NULL){ printf("ファイル%sが開けません\n",NAME); return -1; } if((fq=fopen(NAME1,"w")) == NULL){ printf("ファイル%sが開けません\n",NAME1); return -1; } if((fr=fopen(NAME2,"w")) == NULL){ printf("ファイル%sが開けません\n",NAME1); return -1; } j=0; while(fgets(buff,SIZE,fp)!=NULL){ if( j>= SIZE ){ printf("buffer Over!"); break; } strcpy(tbl[j].a,strtok(buff,",\"")); strcpy(tbl[j].b,strtok(NULL,",\"")); strcpy(tbl[j].c,strtok(NULL,",\"")); j++; } fclose(fp); printf("test.csvの表示"); for(n=0; (n<j) && (n<SIZE); n++){ printf("%s %s %s\n",tbl[n].a,tbl[n].b,tbl[n].c); } printf("\n"); qsort(tbl, j, sizeof(struct tb), comp); printf("ソート後\n(test2.csv?)"); for(n=0; (n<j) && (n<SIZE); n++) { printf("%s %s %s\n",tbl[n].a,tbl[n].b,tbl[n].c); fprintf("%s %s %s\n",tbl[n].a,tbl[n].b,tbl[n].c); } fcolse(fq); printf("\n"); printf("キリのいい所だけ(test3.csv?)\n"); for(n=0; (n<j) && (n<SIZE); n++){ if(n%10==0){ printf("%s %s %s\n",tbl[n].a,tbl[n].b,tbl[n].c); fprintf("%s %s %s\n",tbl[n].a,tbl[n].b,tbl[n].c); } } fclose(fr); printf("\n"); free(tbl); //メモリの開放?(追加) return 0; } int comp(const void *_p0, const void *_p1) { struct tb *p0 = (struct tb *)_p0; struct tb *p1 = (struct tb *)_p1; return strcmp(p0->b, p1->b); }

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.2

えーと、Cじゃないと駄目ですか? Cのプログラムを作ること自体が目的でないのなら、Perlとかで使うと楽なんですが

yamaomoto
質問者

補足

>>えーと、Cじゃないと駄目ですか? Cオーダーです。申し訳ありません。

  • anicicle
  • ベストアンサー率36% (129/356)
回答No.1

とりあえず、test.csvを一旦全部読みこんで、そのデータをソートしてからtest1.csvに書き出す。 test1.csvから適宜必要な部分を読み込み、test2.csvを作る。 それと、提示の者にはtest2.csvへの書き込み処理ないよ?

yamaomoto
質問者

お礼

お礼の所ですいません。 printfにfprintfも追加したら対象ファイルに書き込めました。 しかし大きなデータのcsvファイルにしたら「Segmentation fault」に もう何がなんだかわからない状態です。ちゃんとfopen,fcloseはしてあるのですが…

yamaomoto
質問者

補足

ありがとうございます。ご提示いただいたやり方かどうか分かりませんが、自分なりにつくってみました。こちらのプログラムで test.csvファイルの表示、2列目をキーとしたソート(test1.csv)、キリのいい所の表示(test2.csv)は出来たのですが、 あとはそれぞれのファイルへの書き込み処理をどうしようか迷っています… #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #define NAME "test.csv" #define SIZE 1024 struct tb{ char a[SIZE]; char b[SIZE]; char c[SIZE]; }; int comp(const void *, const void *); int main(main) { struct tb tbl[SIZE]; FILE *fp; char buff[SIZE], string_buff[SIZE]; int j,n; clock_t start,end; start = clock(); if((fp=fopen(NAME,"r")) == NULL){ printf("ファイル%sが開けません\n",NAME); return -1; } j=0; while(fgets(buff,SIZE,fp)!=NULL){ strcpy(tbl[j].a,strtok(buff,",\"")); strcpy(tbl[j].b,strtok(NULL,",\"")); strcpy(tbl[j].c,strtok(NULL,",\"")); j++; } fclose(fp); printf("test.csvの表示"); for(n=0; n<j; n++){ printf("%s %s %s\n",tbl[n].a,tbl[n].b,tbl[n].c); } printf("\n"); qsort(tbl, j, sizeof(struct tb), comp); printf("ソート後\n(test2.csv?)"); for(n=0;n < j;n++) { printf("%s %s %s\n",tbl[n].a,tbl[n].b,tbl[n].c); } printf("\n"); printf("キリのいい所だけ(test3.csv?)\n"); for(n=0; n<j ;n++){ if(n%10==0){ printf("%s %s %s\n",tbl[n].a,tbl[n].b,tbl[n].c); } } end = clock(); printf("%.30f秒かかりました\n",(double)(end-start)/CLOCKS_PER_SEC); printf("\n"); return 0; } int comp(const void *_p0, const void *_p1) { struct tb *p0 = (struct tb *)_p0; struct tb *p1 = (struct tb *)_p1; return strcmp(p0->b, p1->b); }

関連するQ&A