• 締切済み

C言語 CSVからTXTへ書き込み

CSVファイルのデータを配列に格納してtest.txtに書き込みたいです。 その際、指定した列だけを書き込むのですが、うまくいきません。 a.txtの中身が a1,a2,a3,a4,a5 b1,b2,b3,b4,b5 c1,c2,c3,c4,c5 だとしたら、a1,a2,a3,a4,a5だけしか書き込めていません。 test.txtに書き込みたいのは、 a3 b3 c3 のようにしたいです。 初心者ですが、なかなかうまくいかないのでくやしいです。。。 お詳しい方、ご教授よろしくお願いします。 #define LINE_MAX 1024 #define ITEM_MAX 200 FILE *fp; char in_file[] = "a.txt"; char line[LINE_MAX]; char delmit[] = ",\n";      char item[ITEM_MAX][100]; char *item_p; int item_idx,ii; if((fp = fopen(fnamebuff, "r")) != NULL) { while(fgets(line, LINE_MAX, fp) != NULL) { if((item_p = strtok(line, delmit)) != NULL) { strcpy(&item[0][0], item_p); for(item_idx = 1; item_idx < ITEM_MAX; ++item_idx) { if((item_p = strtok(NULL, delmit)) != NULL) { strcpy(&item[item_idx][0], item_p); } else { item[item_idx][0] = '\0'; } } } FILE *fl; fl=fopen("test.txt","w"); for(ii=0;ii<200;ii++){ fprintf(fl," %s ", &item[ii][0]); } fclose(fl); fclose(fp); } }

みんなの回答

回答No.7

>計算をさせているのですが、ちゃんと出力されません。 わかる範囲ではもちろん、対応しますけど。 ”ちゃんと”ではわからないので、どうしたい?のかを 書いてもらえますか? それと、 for(i=0;i<line_no;i++) { t[i] = atoi(item[i+3][1])-atoi(item[i+2][1]); v[i] = atoi(&item[i+3][2])-atoi(&item[i+2][2]); 現在のiは、最大値が、読み込めた行数なので、 最大行数に+3や、+2を足してはいけないのでは? item[ ここは何行目 ][ こっちが何カラム目 ] です。 a 1,2,3,4, b c d カラムは、X方向で、1234の位置で、行は、abcdのY方向です。 これをマトリックス的に見るならですが。 その辺を直してみてはいかがでしょうか? atoi でINT型にして、いるのになぜ、受け取りの方が、 double t[28600],v[28600]; DOUBLEなのかが、よくわかっていませんが、 値がDOUBLEなのであれば、表示もDOUBLEにするべきではないかと、 fprintf(fl,"%s %s %d\n",&item[i][1],&item[i][2],v[i]/t[i]); "%d"ではなく、"%f" にしておいたほうがいいかと。。 http://www9.plala.or.jp/sgwr-t/c/sec05.html printfの、後ろに書いているパラメーターは、キャストされないので、 注意が必要です。可変パラメーターを使っているため、何を書いてもいいという特性があるので、 INTだろうが、DOUBLEだろうが、エラーは出ません。。 v[i]/t[i] をINTで出すなら、最初からINTでキャストしておくべきかと。 (int)(v[i]/t[i])など。この場合、"%d"で表示。ただし、INTなので、小数点関連はありません。 "%f" で受け取れる場合は、そのままでもいいんですが、 個人的な書式では、その位置が、DOUBLEだということを、他の人が呼んでもわかるようにと (double)(v[i]/t[i]) とわざと、無意味なキャストを行っています。 実際には、double -> doubleなので、何もおきませんが、他の人が このソースを見たとき、ここが、DOUBLEなのだ!とすぐにわかるという意味合いでですが・・ ここは、好みで!

回答No.6

あくまでこんなものは、サンプルなので、、 細かいチェックはしてませんから、そこはご注意を! たとえば、 item[line_no][item_idx][0] = '\0'; これですが、最初のstrtokがいきなりNULLだった場合は スルーしているので、初期化さえされないので、値は不定ですし。 文字の長さも決めうちなので、1バイトでもオーバーフローしたら メモリ破壊しまくりますので。 ちゃんとやるなら、長さを測ったり、可変長を扱えるライブラリなり関数を 用意して使うべきでしょうし。 暇つぶし回答なので、それほどは、本気になさらないでくださいね。 それでは!

yuta20041214
質問者

補足

こんばんわ!ご回答ありがとうございます! 今度は配列に格納したデータに少し計算を加えてTXTファイルに出力したいのですが、 charからdoubleにatoiを使って変換し、計算をさせているのですが、ちゃんと出力されません。 元データは文字と数字が含まれています。 "a1,b1,c1,d1" "1,2,3,4" "5,6,7,8" "9,10,11,12" "13,14,15,16" こんな感じです。実際はもっと大きなデータです。 お時間があればご回答よろしくお願いします。 #include <stdio.h> #include <string.h> #define LINE_MAX 3250 #define ITEM_MAX 200 FILE *fp,*fl; char line[LINE_MAX]; char delmit[] = ",\n"; char item[28600][ITEM_MAX][100]; char *item_p; int i; int item_idx; int line_no; double t[28600],v[28600]; int main(){ line_no=0; if((fp = fopen("a.txt", "r")) != NULL) { while(fgets(line, LINE_MAX, fp) != NULL) { if((item_p = strtok(line, delmit)) != NULL) { strcpy(&item[line_no][0][0], item_p); for(item_idx = 1; item_idx < ITEM_MAX; ++item_idx) { if((item_p = strtok(NULL, delmit)) != NULL) { strcpy(&item[line_no][item_idx][0], item_p); }else{ item[line_no][item_idx][0] = '\0'; } } } line_no++; } } fl=fopen("test.txt","w"); for(i=0;i<line_no;i++) { t[i] = atoi(item[i+3][1])-atoi(item[i+2][1]); v[i] = atoi(&item[i+3][2])-atoi(&item[i+2][2]); fprintf(fl,"%s %s %d\n",&item[i][1],&item[i][2],v[i]/t[i]); } fclose(fl); fclose(fp); }

回答No.5

a1,a2,a3,a4,a5,a3 b1,b2,b3,b4,b5,b3 c1,c2,c3,c4,c5,c3 最後に3番カラムを結合したい?ということであれば、 少し変更して、、 ------------- #include <stdio.h> #include <string.h> #define fnamebuff "a.csv" /* ファイル名変数なかったので、適当に作成 */ #define LINE_MAX 1024 #define ITEM_MAX 200 FILE *fp; char in_file[] = "a.txt"; char line[LINE_MAX]; char delmit[] = ",\n"; char item[200][ITEM_MAX][100]; /* 次元追加 */ char *item_p; int item_idx,ii; int line_no; /* 行番号追加 */ int culum_no; void text_filter(char *p) { int l=strlen(p); while(l>0) { l--; if (p[l]==10 || p[l]==13) { p[l]=0; }else{ return; } } return; } int main() { line_no=0; /* 行番号初期化 */ if((fp = fopen(fnamebuff, "r")) != NULL) { while(fgets(line, LINE_MAX, fp) != NULL) { text_filter(line); if((item_p = strtok(line, delmit)) != NULL) { strcpy(&item[line_no][0][0], item_p); for(item_idx = 1; item_idx < ITEM_MAX; ++item_idx) { if((item_p = strtok(NULL, delmit)) != NULL) { strcpy(&item[line_no][item_idx][0], item_p); }else{ item[line_no][item_idx][0] = '\0'; } } } line_no++; } } /* 画面表示タイプ */ for(ii=0;ii<line_no;ii++) { for(culum_no=0;culum_no<999;culum_no++) { if (item[ii][culum_no][0]) { if (culum_no) printf(","); printf("%s",item[ii][culum_no]); }else{ break; } } /* 最後に結合したいものを書いた */ if (culum_no) printf(","); printf("%s\n",item[ii][2]); } /* 文字列作成タイプ */ char line_buffer[256]; for(ii=0;ii<line_no;ii++) { line_buffer[0]=0; for(culum_no=0;culum_no<999;culum_no++) { if (item[ii][culum_no][0]) { if (culum_no) strcat(line_buffer,","); strcat(line_buffer,item[ii][culum_no]); }else{ break; } } /* 最後に結合したいものを書いた */ if (culum_no) strcat(line_buffer,","); strcat(line_buffer,item[ii][2]); /* 出力、fprintfでもなんでも好きに */ printf("out = \"%s\"\n",line_buffer); } } ------------- では、いかがでしょうか? ちなみ、先ほどのサンプル、ポインタが一部まちがってまして。 item[ii][2]これに&がついてました・・・失礼しました。 &つけるなら、&item[ii][2][0]ですね。ヘボミス連発です。 このサンプルの実行結果は、 $ cc a.c && ./a <-ここはこちらのコンパイラの名前ですので、無視してください。 a1,a2,a3,a4,a5,a3 b1,b2,b3,b4,b5,b3 c1,c2,c3,c4,c5,c3 out = "a1,a2,a3,a4,a5,a3" out = "b1,b2,b3,b4,b5,b3" out = "c1,c2,c3,c4,c5,c3" と出ますが、これでよろしかったでしょうか?

回答No.4

>配列に格納したデータをCstringクラスの最後の列に代入したいのですが、 Cstring str; for(ii=0;ii<line_no;ii++) { str+=item[ii][2] } どういう、結果になれば正しいのでしょうか? "Cstring" < 私の方は、この書き方がわからないという感じはあります。 これだと、 "a3b3c3"こうなっちゃう?ということでいいのでしょうかね? 私の使うCで同じことをするのであれば、 char str[ 任意のバッファー ]; /* 余裕を見てサイズは作成 */ str[0]=0; < NULLを作成。 for(ii=0;ii<line_no;ii++) { /* a + ,b + ,c +,d = a,b,c,d */ /* カンマが着いていないのは、最初の一回のみなので、iiが0以外で","を結合 */ if (ii) strcat(str,","); /* もしもカンマ区切りにしたいならこの行を使う */ strcat(str,item[ii][2]); } と同じかな? この質問、結果がよくわからないので、どうしたい?のか 教えてもらえれば、回答できるとは思います。 こちら、GCCというコンパイラで、基本的な命令だけで、遊んでいるので。 マイクロソフト系?の書き方はよくわかっていませんで。そこはすいません。

yuta20041214
質問者

補足

私の質問の仕方が悪かったです。わかりにくくてすみません。。。 元のデータ a1,a2,a3,a4,a5 b1,b2,b3,b4,b5 c1,c2,c3,c4,c5 取り出したデータ a3 b3 c3 元のデータに取り出したデータを追加したいです。 a1,a2,a3,a4,a5,a3 b1,b2,b3,b4,b5,b3 c1,c2,c3,c4,c5,c3 上記のように。この元データがCstringクラスで宣言していたのですが、おっしゃる通りマイクロソフト系の宣言です。 AsarKingChangさん流の書き方を教えてくれませんか?

回答No.3

ミスったままだと、恥ずかしいので、 #include <stdio.h> #include <string.h> #define fnamebuff "a.csv" /* ファイル名変数なかったので、適当に作成 */ #define LINE_MAX 1024 #define ITEM_MAX 200 FILE *fp; char in_file[] = "a.txt"; char line[LINE_MAX]; char delmit[] = ",\n"; char item[200][ITEM_MAX][100]; /* 次元追加 */ char *item_p; int item_idx,ii; int line_no; /* 行番号追加 */ int main() { line_no=0; /* 行番号初期化 */ if((fp = fopen(fnamebuff, "r")) != NULL) { while(fgets(line, LINE_MAX, fp) != NULL) { if((item_p = strtok(line, delmit)) != NULL) { strcpy(&item[line_no][0][0], item_p); for(item_idx = 1; item_idx < ITEM_MAX; ++item_idx) { if((item_p = strtok(NULL, delmit)) != NULL) { strcpy(&item[line_no][item_idx][0], item_p); }else{ item[line_no][item_idx][0] = '\0'; } } } line_no++; } } for(ii=0;ii<line_no;ii++) { printf("%s ",&item[ii][2]); } } 作りました。 ファイルに出力せず、画面表示になっているので、 そこは、fprintfなりに入れ替えて置いてください。

yuta20041214
質問者

補足

ありがとうございます!できました!!AsarKingChangさん、お詳しいので追加で質問させていただきます。配列に格納したデータをCstringクラスの最後の列に代入したいのですが、 Cstring str; for(ii=0;ii<line_no;ii++) { str+=item[ii][2] } でよろしいでしょうか。他に良い方法はありますか。よろしくお願いします。

回答No.2

あ、失礼。ミスってました。最初の無視してください。

回答No.1

char delmit[] = ",\n";   デメリタは、","だけでは? なので、分解できていないと思いますよ。 一括で取り込む方式でやりたいのであれば、 item[][] これも、3次元配列のほうがいいのではないかと item[][][100] = 100は文字を格納するバッファーとして。 a1,a2,a3,a4,a5 b1,b2,b3,b4,b5 c1,c2,c3,c4,c5 item [0]= 0ライン目 item [0][0]= 0カラム目="a1"など item [0][0][0]="a1"などの文字列用の実体。 そうすれば、 item [ ライン番号 ][ カラム番号 ] で処理できるため、後々効率はいいかもしれません。 >test.txtに書き込みたいのは、 >a3 >b3 >c3 ならば、 item [0][2] が"a3".. item [1][2] が"b3".. item [2][2] が"c3".. あと、読み込めた行数を覚えておけば、最後に強制的に200行と指定している部分が 不要になるので、余計なバグを生まなくてすみます。 ただし、fgets の先頭が文字かは、軽くチェックした方がいいかもしれません。 改行コードや、EOFコードが入って来ることもありえる為。 #汎用性を求めるなら、やっておく方が親切でしょうね。 私の方では、こういう処理の時、 終端の改行コードを一番最初に削除しています。 最後のカラムは ”a5”に見えますが、実際には"a5"+改行コードがくっついてくるためです。 空行も、改行コードが入っていることがあり、この状態で、終端改行コード削除を行うと バッファーの先頭が0になるので、処理するか?の判定に使えて便利です。 C言語以外では、trimと呼ばれる処理ですが。trim_r()のほうが近いかな。 ということで、私なりの回答でした。

関連するQ&A

  • 改行されたtxtファイルの読み込み(C++)

    3374356,4785323,7043817,5111179,8267572, 6486903,3258714,6344689,8620512,7434933, 8088837,8231528,6524254,5928445,7101798, 5338215,5233711,4753647,5930266,7512232, 5343749,5813061,6439450,6257874,5724787, 5864114,9006652,4871427,6158077,7343041, 7615426,7168142,5866379,8154664,7342803, という形式のデータ数1000のtxtファイルがあります。 解析に使用したいのでCに読み込みたいのですが、方法が調べても分からず困っています。とりあえず以下が、データが一行の際に使用しているソースコードです。 FILE *fp; char linebuf[4096]; char *p; int array[1024]; int data=0; fp=fopen("randombetarev.txt","r"); if(!fp) return 1; fgets(linebuf,4096,fp); fclose(fp); p=strtok(linebuf,","); do{ array[data]=atoi(p); data++; }while(p=strtok(NULL,","));//ここまででデータを配列に格納 これでは改行の判別ができないので初めの一行目のデータしか読み込めません。どなたかご教授ください。

  • c言語  2つのファイルを行ごとに読み込むプログラミング

    c言語  2つのファイルを行ごとに読み込むプログラミング 0.txt と 1.txt という2つのテキストフォルダがあり 0.txt の中身は a a b b 1.txt の中身は c c d d というものとします。 これら2つのフォルダを読み込むとき まず1つのフォルダの1行目(a a)を表示し 他方の1行目(c c) 2行目(d d)を表示させて 続いて1つのフォルダの2行目(b b)を表示し 他方の1行目(c c) 2行目(d d)を表示させたいのです。 つまり実行結果が a a c c a a d d b b  ←理想の実行結果です c c b b d d となるようにしたいのですが #include <stdio.h> #include <stdlib.h> #define STR_MAX 256 int main(void) { FILE *fp, *fp2; int i, j, k; char buf[STR_MAX]; char buf2[STR_MAX]; fp = fopen("0.txt", "r"); fp2 = fopen("1.txt", "r"); if (fp == NULL && fp2 == NULL){ printf("\n"); } while(fgets(buf, STR_MAX, fp) != NULL){ while(fgets(buf2, STR_MAX, fp2) != NULL){ printf("%s%s", buf,buf2); } printf("\n"); } fclose(fp); fclose(fp2); return 0; } このプログラミングの実行結果は a a c c a a d d となり、0.txtの2行目(b b)は表示されません。 おそらく while 文 を2重にすることで 不具合が起きているのだと思うのですが 色々と調べた結果、これ以外に プログラミングが思いつきません。 私の理想の実行結果にするためには どこを訂正させると良いのでしょうか? 恐れ入りますが ご回答 どうかよろしくお願いいたします。

  • 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); } と書いたんですが、ぜんぜんな状態です。誰かご教授願えませんか?

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

  • test.csvの内容

    test.csvの内容 "a","b","c","d" "e","f","g","h" "i","j","k","l" "m","n","o","p" "q","r","s","t" "u","v","w","x" "あ","い","う","え" "か","き","く","け" "さ","し","す","せ" "た","ち","つ","て" とし、真ん中のq,r,s,t以降の内容を表示させたく、下のようなプログラムを作成しました しかし、コンパイル後実行しようとするとエラーになってしまいます。どう直したらよいか教えて頂けますでしょうか? #include <stdio.h> #include <stdlib.h> #include <string.h> #define NAME "test.csv" #define SIZE 32 struct tb{ char a[SIZE]; char b[SIZE]; char c[SIZE]; char d[SIZE]; }; int main(void) { struct tb test; FILE *fp; char buff[SIZE]; long pos; pos=ftell(fp); fseek(fp,pos,SEEK_SET); while(fgets(buff,SIZE,fp) != NULL){ //各項目の設定 strcpy(test.a,strtok(buff,",\"")); strcpy(test.b,strtok(NULL,",\"")); strcpy(test.c,strtok(NULL,",\"")); strcpy(test.d,strtok(NULL,",\"")); printf("%s %s %s %s \n",test.a,test.b,test.c,test.d); } }

  • C言語でのカンマ区切りについて

    結果テキストファイルから特定の値のみ抽出するプログラムを作成しているのですが、思うように動いてくれません。どなたか教えてくださいませんか。お願いします。 <テキストファイルの形式> 様々な文字や記号slm,0.070000,-53458.000000様々な文字や記号 これが1行に4つ程含まれるものが10行ほどあるのですが、 2つ目のカンマの後の数値部分のみ抽出したいのです。 <プログラム> char line[MAXLINE]; char a1[]="slm"; char *r; char *s[2]; while (fgets(line, MAXLINE, fp) != NULL){ if(strstr(line, a1)!=NULL){ for (r = line ;r = strstr(r, a1); r += 27 ){ for(int p=0;p>2;p++){ s[p]=strtok( strstr(r, a1), "," ); printf("%s",s[3]); } } printf(" \n"); i++; } } そこでこのようなプログラムを作ってみたのですが、実行すると何も表示されません。 どなたか改善策を教えてください。本当に困っています。

  • C言語でセグメンテーションエラー

    環境はUbuntu Feisty Fawn gcc 4.1.2 #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 32 #define DEBUG struct node{ char *moji; struct node *left,*right; }; typedef struct node NODE; void error(char *msg){ fflush(stdout); fprintf(stderr, "%s\n", msg); exit(1); } NODE *createNode(char *x){ NODE *new; new = malloc(sizeof(NODE)); if(new == NULL){ error("メモリがありません。\n"); } new->moji = x; new->left = NULL; new->right = NULL; return new; } NODE *insertNode(NODE *p, char *x){ if(p == NULL){ p = createNode(x); }else if(strcmp(p->moji, x) == 0){ return NULL; }else if(strcmp(p->moji, x) > 0){ p->left = insertNode(p->left, x); }else{ p->right = insertNode(p->right, x); } return p; } void printTree(NODE *p){ if(p == NULL) return; printTree(p->left); printf("%s\n",p->moji); printTree(p->right); } int main(int argc, char *argv[]){ FILE *fp; char *buf = malloc(sizeof(char) * MAX); char *ans = malloc(sizeof(char) * MAX); NODE *p = malloc(sizeof(NODE)); if( argc > 2 ){ printf("ファイルの指定は一つだけです。\n"); return -1; }else if(argc == 1){ printf("ファイルを指定してください。\n"); return -1; } fp = fopen( argv[1] , "r" ); if( fp == NULL ){ printf("ファイル読み込みに失敗しました。\n"); return -1; } while(fscanf(fp,"%s",buf) == 1){ ans = strtok(buf," -,."); p = insertNode(p, ans); while(ans != NULL){ ans = strtok(NULL," -,."); if(ans != NULL){ p = insertNode(p, ans); } } } printTree(p); fclose(fp); 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. どこがいけないとおもいますか?

  • C言語について

    以下のプログラムについてです test.txtから単語を読み込んでその異なる単語の数を求めるプログラムです。 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<stddef.h> #include<ctype.h> #define NMAX 80 #define LMAX 5000 void count(FILE*, int); void all_words(FILE *); FILE *fp, *fp2; char *fn="test.txt"; char *fn2="total word.txt"; const char *ignore="\n !?()*-;:.,_\"[]"; int main(void){ int p=0, x=0, c, l, t=0,k=0; char word3[LMAX][NMAX]; char word1[NMAX]; char word2[NMAX]; char *tp; char *tp2; if((fp=fopen(fn,"r"))==NULL){ printf("Can't open '%s'.\n",fn); return -1; } if((fp2=fopen(fn2,"w"))==NULL){ printf("Can't open '%s'.\n",fn2); return -1; } for(c=0;c<LMAX;c++){ if(fgets(word3[c],NMAX,fp)==NULL)break; p++; } for(c=0;c<p;c++){ for(x=0;x<NMAX;x++){ word1[x]=tolower(word3[c][x]); } tp=word1; while((tp2=strtok(tp,ignore))!=NULL){ if(*tp2=='\''){ if(*(tp2+1)=='`'){ t=1; } tp2++; } free(tp); strcpy(word2,tp2); k=l=strlen(word2)-1; if(word2[k]==('\'' & l)){ word2[l]='\0'; } if(word2[0] =='\'' &&t==0){ if(word2[1]!='\0'){ fputs(word2+1,fp2); fputc('\n',fp2); } } else{ if(word2[0]!='\0'){ fputs(word2,fp2); fputc('\n',fp2); } } tp=NULL; } } fclose(fp); fclose(fp2); all_words(fp2); return 0; } void all_words(FILE* fp2){ char word3[NMAX]; int n=0; if((fp2=fopen(fn2,"r"))==NULL){ printf("Can't open '%s'.\n", fn2); return; } for(;;){ if(fgets(word3, NMAX,fp2)==NULL){ break; } n++; } fclose(fp2); count(fp2,n); } void count(FILE* fp2, int n){ int c, x, y=0; char *m=(char *)malloc(n*NMAX); char *xp; char *yp; if((fp2=fopen(fn2,"r"))==NULL){ printf("Can't open '%s'.\n", fn2); free(m); return; } for(c=0,xp=m; c<n;c++,xp+=NMAX){ fgets(xp,NMAX,fp2); } qsort(m,n,NMAX,(int (*)(const void*, const void*))strcmp); c=1; for(x=0,xp=m,yp=m+NMAX;x<n-1;xp+=NMAX,yp+=NMAX,x++){ if(strcmp(xp,yp)==0){ y++; c++; } else{ c=1; } } printf("KIDN OF WORD:%d\n",n-y); free(m); fclose(fp2); } このプログラムについてメモリリークになってしまうのですが 確保していないメモリー領域に代入しているのが原因らしいのですが 具体的にどこを直せば良いのでしょうか? よろしくお願いします

  • C言語について

    以下のプログラムについてです。 test.txtというファイルを読み込み、その中の異なる単語の数を求めるプログラムです。 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<stddef.h> #include<ctype.h> #define NMAX 80 #define LMAX 5000 void count(FILE*, int); void all_words(FILE *); FILE *fp, *fp2; char *fn="test.txt"; char *fn2="total word.txt"; const char *ignore="\n !?()*-;:.,_\"[]"; int main(void){ int p=0, x=0, c, l, t=0; char word3[LMAX][NMAX]; char word1[NMAX]; char word2[NMAX]; char *tp; char *tp2; if((fp=fopen(fn,"r"))==NULL){ printf("Can't open '%s'.\n",fn); return -1; } if((fp2=fopen(fn2,"w"))==NULL){ printf("Can't open '%s'.\n",fn2); return -1; } for(c=0;c<LMAX;c++){ if(fgets(word3[c],NMAX,fp)==NULL)break; p++; } for(c=0;c<p;c++){ for(x=0;x<NMAX;x++){ word1[x]=tolower(word3[c][x]); } tp=word1; while((tp2=strtok(tp,ignore))!=NULL){ if(*tp2=='\''){ if(*(tp2+1)=='`'){ t=1; } tp2++; } strcpy(word2,tp2); l=strlen(word2)-1; if(word2[l]==('\'' && l)){ word2[l]='\0'; } if(word2[0] =='\'' &&t==0){ if(word2[1]!='\0'){ fputs(word2+1,fp2); fputc('\n',fp2); } } else{ if(word2[0]!='\0'){ fputs(word2,fp2); fputc('\n',fp2); } } tp=NULL; } } fclose(fp); fclose(fp2); all_words(fp2); return 0; } void all_words(FILE* fp2){ char word3[NMAX]; int n=0; if((fp2=fopen(fn2,"r"))==NULL){ printf("Can't open '%s'.\n", fn2); return; } for(;;){ if(fgets(word3, NMAX,fp2)==NULL){ break; } n++; } count(fp2,n); } void count(FILE* fp2, int n){ int c, x, y=0; char *m=(char *)malloc(n*NMAX); char *xp; char *yp; if((fp2=fopen(fn2,"r"))==NULL){ printf("Can't open '%s'.\n", fn2); free(m); return; } for(c=0,xp=m; c<n;c++,xp+=NMAX){ fgets(xp,NMAX,fp2); } qsort(m,n,NMAX,(int (*)(const void*, const void*))strcmp); c=1; for(x=0,xp=m,yp=m+NMAX;x<n-1;xp+=NMAX,yp+=NMAX,x++){ if(strcmp(xp,yp)==0){ y++; c++; } else{ c=1; } } printf("KIDN OF WORD:%d\n",n-y); free(m); fclose(fp2); } このプログラムでメモリリークの原因が確保していないメモリ領域に代入しているのが原因らしいのですがどこをどう直して良いかわかりません 具体的に教えていただけないでしょうか? よろしくお願いします