ファイルの読み書き方法についての質問

このQ&Aのポイント
  • ファイルの読み書き方法について質問です。ファイルを最初に書き込まないといけない場合、最後に文字列を追加する方法を知りたいです。
  • 現在ファイルに文字列を追加していますが、最後ではなく最初に文字列を追加したいと考えています。しかし、ファイルを2回ずつ読み込んだり書いたりするとバグが発生します。
  • 追加したい文字列が「もも」で、現在のデータが「オレンジ」と「みかん」の場合、「もも」「オレンジ」「みかん」の順でデータが追加されることを目指しています。しかし、バグのために「みかん」が3列書き込まれてしまいます。
回答を見る
  • ベストアンサー

ファイルの読み書き

ファイルに文字列を追加したいのですがファイルの開き方が "a" モードで開くと当然文章の最後に文字列が書き込まれることになります。 ですが、最後ではなく最初に文字列を追加したいためにファイルを2回づつ読み込んだり書いたりしたら2回目の読み込み時にバグが出ました どうしたらファイルの文字列を最後ではなく最初に追加できますか? 追加したい文字が: もも 今までのデーターが オレンジ みかん なら、 もも オレンジ みかん のようにしたい。 以下ソース ---ソース--- #include <stdio.h> void main(void){ FILE *fp; char *tm[1000]; char buf[400]; int i=1,sei; fp= fopen("now.txt","w+"); fprintf(fp,"もも"); fclose(fp); //何で最初に書き込んでるんだ? //という突っ込みがあるでしょうが本当に作りたいプログラムは最初にファイルに書き込まないといけないためです。 fp= fopen("now.txt","r"); while( fgets( buf, 400, fp ) != NULL ){ tm[0]=buf; } fclose(fp); printf("%s<br>",tm[0]); //確認用 この時点ではtm[0]に"もも"が入っている fp =fopen("moto.txt","r"); while( fgets( buf, 400, fp ) != NULL ){ tm[i]=buf; printf("%s<br>",tm[i]); //確認 この時点ではtm[1]に"オレンジ" tm[2]にみかんが入っている i++; } printf("%s<br>",tm[0]); //確認用 バグったtm[2]のみかんが入っている printf("%s<br>",tm[1]); //確認用 バグったtm[2]のみかんが入っている printf("%s<br>",tm[2]); //確認用 バグじゃない? fclose(fp); if(i<=1000){ sei=i; } else{ sei=1000; } fp =fopen("chat_deta.txt","w+"); for(i=0;i<sei;i++){ fprintf(fp,"%s\n",tm[i]); //バグった内容が書き込まれるためみかんが3列かきこまれる } fclose(fp); } } ---now.txt--- もも ---moto.txt--- オレンジ みかん 結果として みかん みかん みかん っとなっていますね。

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

  • ベストアンサー
  • kabe64
  • ベストアンサー率72% (13/18)
回答No.1

原因はbufを使いまわしてしまっているからです。 tmはポインタの配列なので、bufの中身ではなくbufの場所を格納しているだけですからtm[0]~[2]は全部同じ場所を格納してしまっています。 tmにbufを格納する時は以下のように別の領域を確保、コピーして格納するようにします。 tm[i] = (char*)malloc(strlen(buf)+1); strcpy(tm[i], buf); 最後にmallocで確保した領域をfreeするのも忘れずに

nanaka2222
質問者

補足

ありがとうございます 読み込む事ができるようになりました ただかきこみ字に新たなバグ画出てきたのでそのバグを取り除くための新たなバグに奮闘してました

その他の回答 (1)

回答No.2

壊れる根本の原因は#1さんが指摘したとおりですが、それ以外にも色々と突っ込みたいところがあるのでちょっと書きます。 1. fopenでちゃんとファイルを開けたかチェックしてない。 2. tmのサイズは1000しかないのに、1000件以上fgetsで読むようになっている。 3. そもそもマジックナンバーを即値で書いて使いまわしているのが最悪。例えば、tmのサイズを1000件から10,000件に変える場合の変更点は無数になる。 4. moto.txtからchat_deta.txtに変換したら改行が増えている。 5. chat_detaのスペルがおかしい。 6. 何行読み込んだかを管理している変数が特にない。 7. 読み込みのコードが同じようなことをする割に2回出てくる。 ...というところを考慮してちょっと書き換えてみました。 #include <err.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_TMS 1000 #define BUF_SIZE 400 /* * Reutnrs number of read entries if success. Otherwise, -1. * Notices: * - If max_entries are less than number of lines in the file, this only read * max_entries lines. * - This skips empty line. * - This automatically allocate memory for each entries. You SHOULD free them by yourself. */ static int read_entries(const char *filename, char** entries, size_t max_entries) { char buf[BUF_SIZE]; size_t num_entries = 0; FILE *fp; fp = fopen(filename, "r"); if (fp == NULL) return -1; while (fgets(buf, sizeof(buf), fp) != NULL && num_entries < max_entries) { /* remove end of line if exist. */ int last_char_idx = strlen(buf) - 1; if (last_char_idx >= 0 && buf[last_char_idx] == '\n') { buf[last_char_idx] = '\0'; last_char_idx--; } /* skip emtpy line */ if (last_char_idx < 0) continue; entries[num_entries] = strdup(buf); if (entries[num_entries] == NULL) { /* if failed to allocate memory, clear all entries and returns -1. */ size_t i; for (i = 0; i < num_entries - 1; i++) { free(entries[i]); } fclose(fp); return -1; } printf("entry[%ld]: %s\n", num_entries, entries[num_entries]); num_entries++; } fclose(fp); return num_entries; } int main(void){ FILE *fp; char *tm[MAX_TMS]; size_t filled = 0; int i, num_read; fp= fopen("now.txt","w+"); fprintf(fp,"もも"); fclose(fp); //何で最初に書き込んでるんだ? //という突っ込みがあるでしょうが本当に作りたいプログラムは最初にファイルに書き込まないといけないためです。 num_read = read_entries("now.txt", &tm[filled], MAX_TMS - filled); if (num_read < 0) err(errno, "failed to read entries"); filled += num_read; //printf("%s<br>",tm[0]);//確認用 この時点ではtm[0]に"もも"が入っている num_read = read_entries("moto.txt", &tm[filled], MAX_TMS - filled); if (num_read < 0) err(errno, "failed to read entries"); filled += num_read; for (i = 0; i < filled; i++) { printf("%s<br>",tm[i]); } fp =fopen("chat_data.txt","w+"); for(i=0;i < filled; i++){ fprintf(fp,"%s\n",tm[i]);//バグった内容が書き込まれるためみかんが3列かきこまれる } fclose(fp); for (i = 0; i < filled; i++) { free(tm[i]); } return EXIT_SUCCESS; } #1さんは最初からmallocで容量を確保する方法をおすすめしていますが、どうせmallocするなら必要になってから確保するほうが自分は好きです。メモリーを新たに割り当てて、コピーをするのはstrdupで一発でできるので簡単です。ただ、このプログラムだと最初から2次元配列を作っておけばmallocをしなくてもよいと思います。 あと、ぱっと見これはチャットサイトを作るためのCGIに見えるので追加アドバイス。 8. ファイルから読んで、書くまでロックをかけて守ったほうがいいです。競合状態で書き込みが起きるとデータが消えます。 9. 文字列処理をするのにC言語はあまり向いていません。個人的にはCGIはC言語で書くよりPerl、Ruby、Python、PHPなどのスクリプト言語で書くほうがおすすめです。(達成したい方向と違うところで苦労するので) 10. それでもC言語でやりたいなら、string.hに入っている関数にひと通り目を通しておくことをおすすめします。あとは場合によってはregexライブラリーのお世話になったほうがいいこともあります。 まぁ、頑張って。

nanaka2222
質問者

補足

<<壊れる根本の原因は#1さんが指摘したとおりですが、それ以外にも色々と突っ込みたいところがあるのでちょっと書きます。 何やらそんなに突っ込まれるところがあるのですね 見た感じちゃんとできてるのでよく分からなかったです 2. tmのサイズは1000しかないのに、1000件以上fgetsで読むようになっている。 ここら辺はちゃんと修正しないといけませんね 指摘ありがとうございました 3. そもそもマジックナンバーを即値で書いて使いまわしているのが最悪。例えば、tmのサイズを1000件から10,000件に変える場合の変更点は無数になる。 すみません言ってる事が全く分かりません もう少し区分かりやすく解説お願いします 変なバグをのこしたくないので 4. moto.txtからchat_deta.txtに変換したら改行が増えている。 まさしくこれが取り除きたいバグとして奮闘してました <<あと、ぱっと見これはチャットサイトを作るためのCGIに見えるので追加アドバイス。 よく分かりましたね すばらしいです 8. ファイルから読んで、書くまでロックをかけて守ったほうがいいです。競合状態で書き込みが起きるとデータが消えます。 これについては後々処理するつもりでいました しかし今の問題を解決するのがが先ですね 9. 文字列処理をするのにC言語はあまり向いていません。個人的にはCGIはC言語で書くよりPerl、Ruby、Python、PHPなどのスクリプト言語で書くほうがおすすめです。(達成したい方向と違うところで苦労するので) 10. それでもC言語でやりたいなら、string.hに入っている関数にひと通り目を通しておくことをおすすめします。あとは場合によってはregexライブラリーのお世話になったほうがいいこともあります。 いつも言われますよPealにしろと しかし私にもCでやらないといけない理由があるためアドバイスどおりstring.hに入っている関数にひと通り目を通しておきます。 後指摘もソースを書いていただいた事も本当にうれしいです うれしいのですが、これは私では使用できません なぜなら #include <err.h> #include <errno.h> とかの関数郡を全く知らないのです。 いつかは私も使うようにはなるかもしれませんが、まだ手一杯でして(mallocもつい最近知るようになったのですがこの関数自体がまだよく分からず使っているところがある)余裕がないのです そのため私から見てソース自体が意味が分からないところがいくつかあります。 本当にソースを書いていただきありがとうございました もしよかったらC言語の先生になっていただきたいのですが無理は言えませんね 本当にありがとうございました

関連するQ&A

  • ファイルに文字列を書く

    ファイルを2つ読み込んでファイルを書き直そうとしたのですが 2度目に書き込もうとしたときに改行の書き込みがおかしくなってしまいます してほしいところで改行を一回だけしてほしいと思っているのですが 実際には多数改行されます どうしたら改行が一回だけになりますか? ---ソース--- #include <stdio.h> void main(void){ FILE *fp; char *tm[1000]; char buf[400]; int i=1,sei; fp= fopen("now.txt","w+"); fprintf(fp,"もも"); fclose(fp); //何で最初に書き込んでるんだ? //という突っ込みがあるでしょうが本当に作りたいプログラムは最初にファイルに書き込まないといけないためです。 fp= fopen("now.txt","r"); while( fgets( buf, 400, fp ) != NULL ){ tm[0]=(char*)malloc(strlen(buf)+1); strcpy(tm[0], buf); } fclose(fp); fp =fopen("moto.txt","r"); while( fgets( buf, 400, fp ) != NULL ){ if(i<999){ tm[i] = (char*)malloc(strlen(buf+1)); strcpy(tm[i], buf); i++; } else{ tm[999] = (char*)malloc(strlen(buf+1)); strcpy(tm[999], buf); } } fclose(fp); if(i<1000){ sei=i; } else{ sei=1000; } fp =fopen("chat_deta.txt","w+"); for(i=0;i<sei;i++){ fprintf(fp,"%s\n",tm[i]); } if(i!=(sei-1)){ fprintf(fp,"\n"); } for(i=0;i<sei;i++){ free(tm[i]); } fclose(fp); } } ---now.txt--- もも ---moto.txt--- オレンジ みかん

  • 続jファイルに文字列を書く

    あれから後一歩と言うところにきました たぶんmallocのバグだと思いますがチャットのシステムを作ろうとしているのですが 読み込み時にエラーになります ソースの注目部分を見てほしいのですが、 注目部分はbuf+1 にすると 文字列が1文字ずつ消えていくバグになり bufにすると 3行目を書き込んだ時点で3行目がの頭の部分の文字列がおかしくなり4行目を書き込もうとするとエラーになります ちゃんと動作するにはどのように書けば良いですか? ---ソース--- #include <stdio.h> void main(void){ FILE *fp; char *tm[1000]; char buf[400]; int i=1,sei; fp= fopen("now.txt","w+"); fprintf(fp,"もも"); fclose(fp); //何で最初に書き込んでるんだ? //という突っ込みがあるでしょうが本当に作りたいプログラムは最初にファイルに書き込まないといけないためです。 fp= fopen("now.txt","r"); while( fgets( buf, 400, fp ) != NULL ){ tm[0]=(char*)malloc(strlen(buf)+1); strcpy(tm[0], buf); } fclose(fp); fp =fopen("moto.txt","r"); while( fgets( buf, 400, fp ) != NULL ){ tm[i] = (char*)malloc(strlen(buf+1)); strcpy(tm[i], buf+1); //ここを注目 if(i<999){ i++; } } fclose(fp); if(i<=1000){ sei=i; } else{ sei=1000; } fp =fopen("moto.txt","w"); for(i=0;i<sei;i++){ if(i==0){ fprintf(fp,"%s\n",tm[0]); } else{ fprintf(fp,"%s",tm[i]); } } } ---now.txt--- もも ---moto.txt--- オレンジ みかん

  • ファイルを読み込んで条件式を満たさない

    ファイルを読み込んで一部の文字列が来たら別のファイルの文字列を書き込んでもらうプログラムを作ろうとしたのですが、何故かifを使って条件分岐を試みたところ分岐してくれません。 どのようにしたら分岐しますか? 出来ればソースもお願いします。 ---ソースの内容--- #include <stdio.h> #include <string.h> void main(void){ FILE *fp,*fp2; char buf[100],buf2[100]; fp=fopen("yasa.txt","r+"); while( fgets( buf, 100, fp ) != NULL ){ if(strcmp(buf,"じゃがいも")==0){ fp2=fopen("kuda.txt","r+"); while( fgets( buf2, 100, fp2 ) != NULL ){ printf("%s",buf2); } fclose(fp2); } else{ printf("%s",buf); } } fclose(fp); } ---ソースここまで--- ---yasa.txtの内容--- きゃべつ にんじん じゃがいも だいこん セロリ ---yasa.txtここまで--- ---kuda.txtの内容--- もも オレンジ みかん ぶどう ---kuda.txtここまで---

  • ファイルに書き込む時の負荷について

    PHPバージョン5.2.4を使っています。 次のような // ------------------------------------ $fp = fopen("data.txt", "w"); $buf = ""; for ($i = 1; $i <= 3; $i++) { $buf .= "aaa$i\n"; } fwrite($fp, $buf); fclose($fp); // ------------------------------------ という変数にいったん保存してから書き込む場合と // ------------------------------------ $fp = fopen("data.txt", "w"); for ($i = 1; $i <= 3; $i++) { $buf = "aaa$i\n"; fwrite($fp, $buf); } fclose($fp); // ------------------------------------ というその都度ファイルに書き込む場合とでは どちらが良い悪いというのはあるのでしょうか? たとえばこちらのやり方は負荷がかかるなど ループが多くなっていった場合に違いがでてくるのでしょうか?

    • ベストアンサー
    • PHP
  • FILE オープンについて

    いつもお世話になります。 今ファイルデータ検索処理を検討しております。 今、search.txtには、 検索対象となるファイルパスが記載されています。 [search.txt] /home/hoge/SAMPLE1.jpg /home/hoge/SAMPLE2.jpg search.txtをfopen()し、1行ずつfgets()して、 得られるファイルパスより、そのファイルを fopen()して解析する処理がしたいですが、 fgets()より得られたファイルパスをfopen()し、 fread()するとセグメンテーションエラーになります。 どのようにしたらいいのでしょうか? 現状のコードを下記します。 FILE *fp; char *com1 = "/home/hoge/search.txt"; FILE *confp; char buf1[1024]; char buf2[1024]; int i =0; fp = fopen(com1, "r"); while( fgets(buf1, sizeof(buf1), fp )){ confp = fopen(buf1, "rb"); //*.JPGファイルをオープン //下記fread()でセグメンテーションエラー size_t size = fread( buf2, sizeof(char), 1024, confp ); for( i = 0; i<1024; i++ ){ if( (buf2[i] == 0xff) && (buf2[i+1] == 0xe0) ){ printf("%02x\n",buf[i+5]); } } } fclose(fp); fclose(confp); 上記のように、search.txtをfopen()し、読み込んだファイルパスを fopen()して、fread()読み込みをする方法を 教えて下さい。 どうぞよろしくお願い致します。

  • 同時にファイル読み込み 書き込み

    現在、ヒストグラムのプログラムを作成しています。 まず0~255の1000個の乱数ファイルdata.txtを読み込み、 ヒストグラムは出来たのですが、 エクセルでグラフを作りたいので、 data1.txtに書き込みたいので、下のソースでやってみましたが、 0~255のカウントが全部0になってしまします。 fp = fopen("data1.txt","w");が無ければ正常に処理されます。 どうか教えてください。よろしくお願いします。 #include <stdio.h> #define BUF 10 #define MAX 256 void count(FILE *fp , int* counter); int main(void) { FILE *fp; fp = fopen("data.txt","r"); fp = fopen("data1.txt","w"); int counter[MAX]; int i; for(i=0 ; i<MAX ; i++) { counter[i] = 0; } count(fp , counter); for(i=0 ; i<MAX ; i++) { printf("%d %d\n" , i, counter[i]); } fclose(fp); return 0; } void count(FILE* p_file , int* counter) { char buf[BUF]; while (fgets(buf , BUF , p_file) != NULL) { int n; sscanf(buf , "%d" , &n); counter[n]++; } }

  • [初心者です]Cでのファイル読み込み

    初めまして。質問させていただきます。 プログラミング初心者でコンパイラはgccです。 テキストファイルに書かれた10行の文字列をfgetsを使って読み込みたいので、 以下のようなプログラミングを組みました。 int i=0; char data[256]; char* dataname[256]; char filename[] = "datatext.txt"; FILE* fp = fopen( filename, "r" ); if(!fp)printf("error"); while( fgets(data, 256, fp) != NULL ) { dataname[i]=data; printf("%s",dataname[i]); i++; } fclose(fp); return 0; と、これはうまくいったのですが(初心者ゆえに)本当に上手くいってるのかと思い、 いろいろプログラミングを書き換えて確認していたら、 ・・・・・・・・・(上は同じ)・・・・・・・・・ while( fgets(data, 256, fp) != NULL ) { dataname[i]=data; i++; } fclose(fp); printf("%s",dataname[0]); printf("%s",dataname[1]); printf("%s",dataname[2]); ・・・ printf("%s",dataname[9]); return 0; とprintfの位置を変えると、表示が全て最後の行の値(dataname[9])になってしまいました・・・ これってメモリとかの関係?ですか?原因を知りたいです。 連休中ゆえ質問できる知人もおらず困っています。どうぞよろしくお願いします。

  • 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重にすることで 不具合が起きているのだと思うのですが 色々と調べた結果、これ以外に プログラミングが思いつきません。 私の理想の実行結果にするためには どこを訂正させると良いのでしょうか? 恐れ入りますが ご回答 どうかよろしくお願いいたします。

  • どうやってフローチャートを書きますか

    #include<stdio.h>   void main()   {   FILE*fp;   char buf[128];   char *rc;   char fname[20];   do{   printf("file name>>>");   scanf("%s",fname);   fp=fopen(fname,"r");   if=(fp==NULL) printf("File Open Err¥n");   }while(fp==NULL);   rc=fgets(buf,128,fp);   while(rc!=NULL){    printf("%s",buf);    rc=fgets(buf,123,fp);    }    fclose(fp);    }

  • ファイルサイズを変更したい

    visualstudio2010を使用しています。 c言語で書いているのですが、 test.txt ←abcdefg ファイルサイズ1KB Wtest.txt←書き込み用ファイル 上記のようなファイルがあり、バイナリでtest.txtを読み込みWtest.txtに書き込みたいと思っています。 その際に、1KBのtest.txtを5KBになるまでバイナリで「abcdefg」の後に0を代入したいのですがどう書けば良いのかわかりません。 FILE *fp, *fpw; char *fname = "test.txt"; char *fname_w = "Wtest.txt"; unsigned char buf[10000]; int size; fp = fopen( fname, "rb" ); if( fp == NULL ){ printf( "%sファイルが開けません\n", fname ); return -1; } fpw = fopen(fname_w, "wb"); if(fpw == NULL){ printf( "%sファイルが開けません\n", fname_w ); return -1; } size = fread( buf, sizeof( unsigned char ), sizeof (fp), fp ); /*ここに処理を追加したい*/ fwrite( buf, sizeof( unsigned char ), size, fpw);

専門家に質問してみよう