• ベストアンサー

指定の行をループさせてファイルに出力

C言語で"input.txt"内の文の行範囲と 繰り返す回数をキーボードから入力することにより 結果を"output.txt"に出力するプログラムを考えているのですが、うまくできません。 具体例を以下に示しておきます。 ----input.txt---- aaaa bbbb cccc dddd eeee ------------------ キーボードから繰り返す範囲、2行目と4行目を指定。 繰り返す回数を2回に指定。 ----output.txt---- aaaa bbbb cccc dddd bbbb cccc dddd eeee ------------------- と、こんな感じにしたいです。 指定した行範囲を"output.txt"に出力することはできたのですが 繰り返しの部分がうまくできません。 どなたかご教授お願いします。 自分が作ったプログラムを下に載せておきます。 これをベースに作れたらいいのですが・・・ #include<stdio.h> #include<stdlib.h> #define STR_MAX 256 int main (void) { FILE *fpin, *fpout; char buff[STR_MAX]; int line = 1; int start; int end; printf("start >>"); scanf("%d",&start); printf("end >>"); scanf("%d",&end); if((fpin = fopen("input.txt","r")) == NULL) { printf("infile can't open\n"); exit(EXIT_FAILURE); } if((fpout = fopen("output.txt","w")) == NULL) { printf("outfile can't open\n"); exit(EXIT_FAILURE); } while(fgets(buff,STR_MAX,fpin) != NULL) { if((line >= start)&&(line <= end)) { fputs(buff,fpout); } line = line + 1; } fclose(fpout); fclose(fpin); return EXIT_SUCCESS; }

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

  • ベストアンサー
  • chie65535
  • ベストアンサー率43% (8520/19368)
回答No.2

配列に入れておくのも良いけど、範囲が「2行目から30000行目」とかだと、巨大な配列が必要になります。 なので「2回目以降は、入力ファイルを頭から読み直し、必要な行のみ出力する」と言う方法を使うのが良いでしょう。 「2行目から4行目を、3回繰り返し」の場合、以下のようになります。 1回目 aaaa←出力する bbbb←出力する cccc←出力する dddd←出力する eeee←出力しない 2回目 aaaa←出力しない bbbb←出力する cccc←出力する dddd←出力する eeee←出力しない 3回目 aaaa←出力しない bbbb←出力する cccc←出力する dddd←出力する eeee←出力する 「出力する」と書かれた行を抜き出すと aaaa←出力する bbbb←出力する cccc←出力する dddd←出力する bbbb←出力する cccc←出力する dddd←出力する bbbb←出力する cccc←出力する dddd←出力する eeee←出力する となり「2行目から4行目を、3回繰り返し」された結果が出力されます。 プログラムは以下のようになります。 #include<stdio.h> #include<stdlib.h> #define STR_MAX 256 int main (void) { FILE *fpin, *fpout; char buff[STR_MAX]; int line; int start; int end; int loop; int count; printf("start >>"); scanf("%d",&start); printf("end >>"); scanf("%d",&end); printf("loop >>"); scanf("%d",&loop); if((fpout = fopen("output.txt","w")) == NULL) { printf("outfile can't open\n"); exit(EXIT_FAILURE); } for (count = 1;count <= loop;count++) { if((fpin = fopen("input.txt","r")) == NULL) { printf("infile can't open\n"); exit(EXIT_FAILURE); } line = 1; while(fgets(buff,STR_MAX,fpin) != NULL) { if(((count == 1)&&(line <= end))||((line >= start)&&(line <= end))||((count == loop)&&(line >= start))) { fputs(buff,fpout); } line++; } fclose(fpin); } fclose(fpout); return EXIT_SUCCESS; }

imorimaru
質問者

お礼

なるほど! if文の条件をこんな感じにすると実装できるんですね! あれから数時間考えていましたが、この条件は全然思いつきませんでした・・・ アルゴリズムの考え方が面白いですね。 これから他のプログラムを作る上で参考にさせていただきます。 ありがとうございました。

その他の回答 (1)

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

入力ファイルの内容を配列に格納すれば実装できます。その際、  ・繰り返す範囲(開始行、終了行)  ・繰り返す回数 を引数とする関数を作れば、プログラム全体の見通しがよくなるでしょう。

imorimaru
質問者

お礼

配列に格納することは考えたのですが自分の非力さあまり断念・・・ 今度時間があるときに配列を使用するやり方にチャレンジしたいと思います!

関連するQ&A

  • ファイル操作で全角空白を消す

    こんばんは(^o^) C言語のファイル操作について聞きたいのですが、 半角スペースを消去するところまではわかったんですけど、 全角スペースも消去するプログラムがわかりません(>_<) お手数ですが、ご指導のほうよろしくお願いしますm(_ _)m 問題 テキストファイルから空白を削除して、画面に表示するプログラムを 作成しなさい。 自分のプログラム #include <stdio.h> #include <stdlib.h> #define SIZE 15 int main(void) { char c; char finName[SIZE],foutName[SIZE]; FILE *fpin,*fpout; printf("入力ファイル名>>>"); scanf("%s",finName); if((fpin=fopen(finName,"r"))==NULL) { printf("ファイルが見つかりません。---%s\n",finName); exit(EXIT_FAILURE); } printf("出力ファイル名>>>"); scanf("%s",foutName); if((fpout=fopen(foutName,"w"))==NULL) { fclose(fpin); printf("ファイルを作成できません。---%s\n",foutName); exit(EXIT_FAILURE); } while(1) { c=fgetc(fpin); if(feof(fpin)) { break; } if(c!=' ') { fputc(c,fpout); } } fclose(fpin); fclose(fpout); return EXIT_SUCCESS; }

  • バイナリデータをテキストファイルに出力したい

    以下のソースファイル(test.c) が、 バイナリデータをテキストファイルに するものらしいのですが、 ファイル名(例えば bi.dat)を指定する方法が わかりません。 C++は勉強し始めたばかりで 詳しくありません。 よろしくお願い致します #include <stdio.h> int main( int argc, char *argv[]) { FILE *fpIn; FILE *fpOut; short snData; if( argc < 2) { printf("ファイル名を入れてください。"); return -1; } fpIn = fopen( "argv[1]" , "rb"); if( fpIn == NULL) { printf("入力ファイル %s を開けませんでした。", argv[1]); return -2; } fpOut = fopen( "output.txt", "w"); if( fpOut == NULL) { printf("出力ファイル output.txt を開けませんでした。"); fclose(fpIn); return -3; } while( fread( &snData, sizeof(short), 1, fpIn) == 1) { fprintf( fpOut, "%d\n", snData); }; fclose(fpIn); fclose(fpOut); return 0; }

  • ファイルの出力

    コマンドラインで指定したファイルの内容を一行ずつ表示するプログラムです。一行表示するごとに次の行も表示するか尋ねます。 #include<stdio.h> #include<stdlib.h> #include<ctype.h> int main(int argc, char *argv[]) {  FILE *fp;  char str[80];  char ch;  if (argc != 2){   printf("コマンドライン引数が違います\n");   exit(1);  }  if ((fp = fopen(argv[1],"r")) == NULL){   printf("ファイルが開けません");   exit(1);  }  while(!feof(fp)){   fgets(str, 79, fp);   if (!feof(fp)) printf("%s",str);   printf("追加しますか?(y/n)");   gets(str);   if ( toupper(*str) == 'N') break;   printf("\n");  }     if (fclose(fp) == EOF){   printf("ファイルを閉じれません\n");   exit(1);  }  return 0; } while文の   gets(str);  if ( toupper(*str) == 'N') break; この部分を  ch = getchar();  if ( toupper(ch) == 'N') break; でやると上手く実行できないのですが、なぜでずか?

  • perlで指定範囲を複数ファイルに分割する方法は?

    お世話になります。 perlを使用して、 下記の元ファイル[infile.txt]よりstart~endの範囲を各テキストファイルに 分割出力する方法をご教授いただけないでしょうか。  ※出力ファイル名は元のファイル名 (infile) + 1行目の文字列(単語)にします。   例>>infile_1111.txt , infile_333.txt よろしくお願いいたします。 [infile.txt] aaaa bbbb start 1111 2222 end dddd eeee start 3333 4444 end

  • C言語プログラムで、ループがうまく回りません…

    前回の質問に回答して頂いた皆さん、ありがとうございました! 読み込んだデータを格納するための構造体配列の個数が足りなかったという、ごく初歩的なミスが原因でした…/// それが解決したばかりで恐縮ですが、新たな問題が発生しました。 風力発電の発電データを1秒ごとに1日分を記録したCSVファイルを読み込み、集計して、集計用の新しいCSVファイルに書き込むプログラムを組もうとしています。以下にソースコードを記載します。 #include<stdio.h> #include<stdlib.h> static char filename[100]; static char wfname[100]; char fname2[256]; void str_copy(char[],char[]);//文字列のコピー void str_cat(char[],char[]);//文字列の連結 struct kaze { _char jikoku[16]; _double fuusoku; _double fuuko; _double denatu; _double denryoku1; _double denryoku2; _double co2; }; struct kaze data[86450]; int main() { _char date2[50]; _char date3[50]; _char month2[10]; _char year2[10]; _char path1[50]="F:\\風力発電\\風車"; _char path2[10]="年"; _char path3[10]="月\\WP"; _char buff[256]; _int month1,month,year,date; _int kensuu,i,j,uruu; _FILE *fpin,*fpout; _printf("集計する年を入力してください。\n"); _scanf("%d",&year); _printf("集計する月を入力してください。\n"); _scanf("%d",&month); _if(month==2){ __printf("閏年ですか?(はい -> 1 いいえ -> 2)"); __scanf("%d",&uruu); _} _if(month==2){ __if(uruu==1){ ___month1=29; __} __else{ ___month1=28; __} _} _else if(month==4 || month==6 || month==9 || month==11){ __month1=30; _} _else{ __month1=31; _} _date=year*100+month; _sprintf(date3,"%d",date); _str_copy(wfname,date3); _str_cat(wfname,".csv"); _sprintf(year2,"%d",year); _sprintf(month2,"%d",month); _sprintf(fname2,"%s%s%s%s%s%s",path1,year2,path2,month2,path3,wfname); _if((fpout=fopen(fname2,"w"))==NULL){ __printf("ファイルが作成できません。 --- %s\n",fname2); __exit(EXIT_FAILURE); _} _fprintf(fpout,"日付,平均風速,平均風向,平均電圧,平均発電電力、発電電力量,CO2削減量\n"); _fprintf(fpout,"年/月/日,m/s,°,V,KW,KWh,kg-c\n"); _printf("集計用ファイルを作成しました。 --- %s\n",fname2); _fclose(fpout); _date=year*10000+month*100; _for(j=1;j<=month1;j++){ //このループ __double fuusoku=0,fuuko=0,denatu=0,denryoku1=0,denryoku2=0,co2=0; __date++; __sprintf(date2,"%d",date); __str_copy(filename,date2); __str_cat(filename,".csv"); __sprintf(buff,"%s%s%s%s%s%s",path1,year2,path2,month2,path3,filename); __if((fpin=fopen(buff,"r"))==NULL){ ___printf("ファイルが見つかりません。--- %s\n",buff); ___exit(EXIT_FAILURE); __} __for(kensuu = 0; fscanf(fpin, "%[^,],%lf,%lf,%lf,%lf,%lf,%lf\n", data[kensuu].jikoku, &data[kensuu].fuusoku, &data[kensuu].fuuko, &data[kensuu].denatu, &data[kensuu].denryoku1, &data[kensuu].denryoku2, &data[kensuu].co2) != EOF; kensuu++); //ここで止まる? __for(i = 12; i < kensuu; i++){ ___fuusoku+=data[i].fuusoku; ___fuuko+=data[i].fuuko; ___denatu+=data[i].denatu; ___denryoku1+=data[i].denryoku1; } __fuusoku/=86400; __fuuko/=86400; __denatu/=86400; __denryoku1/=86400; __denryoku2=data[kensuu-1].denryoku2; __co2=data[kensuu-1].co2; __fclose(fpin); __printf("\n%d年%d月%d日の集計結果\n平均風速:%lf(m/s)\n平均風向:%lf(°)\n __________平均電圧:%lf(V)\n",year,month,j,fuusoku,fuuko,denatu); __printf("平均発電電力:%lf(kW)\n発電電力量:%lf(kWh)\nCO2削減量:%lf(kg-c)\n" ,denryoku1,denryoku2,co2); __if((fpout=fopen(fname2,"a"))==NULL){ ___printf("ファイルに追記できません。--- %s\n",fname2); ___exit(EXIT_FAILURE); __} __fprintf(fpout,"%d/%d/%d,%lf,%lf,%lf,%lf,%lf,%lf\n",year,month,j,fuusoku,fuuko,denatu,denryoku1 ,denryoku2,co2); __printf("以上の結果を記録しました。 --- %s",fname2); __fclose(fpout); } _return EXIT_SUCCESS; } void str_copy(char dst[],char src[]) { _int i; _for(i=0;src[i]!='\0';i++){ __dst[i]=src[i]; _} _dst[i]='\0'; } void str_cat(char dst[],char src[]) { _int i,j; _for(i=0;dst[i]!='\0';i++) ; _for(j=0;src[j]!='\0';j++,i++){ _dst[i]=src[j]; _} _dst[i]='\0'; } >>for(j=1;j<=month1;j++){…} のループについて、1週目は問題なく動くのですが、2週目の >>for(kensuu = 0; fscanf(fpin, "%[^,],%lf,%lf,%lf,%lf,%lf,%lf\n", data[kensuu].jikoku, &data [kensuu].fuusoku,&data[kensuu].fuuko, &data[kensuu].denatu, &data[kensuu].denryoku1, &data[kensuu].denryoku2, &data[kensuu].co2) != EOF; kensuu++); で止まる(というより無限ループになる?)ようです。このfor文の中でprintfを使い調べたところ、どうやらfscanfに問題があるということは分かりました。しかし、なにぶん最近勉強しはじめたばかりで、どこがどう悪いのか、見当もつきません(泣) 次から次へと大変恐縮ですが、心当たり程度でも結構ですので、ご意見をお願いします!

  • VBAでパスを取得した後、分割して取り扱いたい

    VBAでパスを取得するとします。 例えば、 A:\BBBB\CCCC\DDDD\EEEE.TXT この時パスを次のように分割をしようとしています。 PATH1=A:\BBBB\CCCC\DDDD\ PATH2=EEEE.TXT といった具合です。 これらの作業をどのようにプログラミングすれば良いのかわかりません。 情けない質問ですが、ご教授お願いします。

  • 加減剰余のオーバーフローについて

    今C言語で加減剰余のプログラムを作っていて、 オーバーフローのチェックだけが上手くいきません。 limits.hをインクルードして、オーバーフローのチェック を行いたいのですがどうすればよいのでしょうか? 扱いたい範囲はint型の-2147483648~2147483647です。 ちなみに開発環境はvc++2005です。 一応ソースを載せておきますので、よろしくお願いします。 #pragma warning ( disable : 4996 ) #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #include <limits.h> int main ( int argc, char *argv[] ) { int start; // 最初に入力する値(引数1) int end; // 最後に入力する値(引数3) int kekka; // 計算結果を格納 int amari; // 除算の余りを格納 int max = INT_MAX; // 表すことが出来る最大値 int min = INT_MIN; // 表すことが出来る最小値 char enzansi; // 入力する演算子 (引数2) char str1[512]; // 格納用の配列を宣言(start用) char str2[512]; // 格納用の配列を宣言(end用) /* 引数の個数チェック */ if ( argc != 4 ) { printf ( "usage : %s start enzansi end\n", argv[0] ); exit ( 0 ); } /* 引数を取得して整数型に変換 */ start = atoi ( argv[1] ); end = atoi ( argv[3] ); /* 引数の取得 */ enzansi = ( argv[2][0] ); sprintf ( str1, "%d", start ); // str1に値を格納 sprintf ( str2, "%d", end ); // str2に値を格納 /* str1とargv[1]による文字列の比較 */ if ( strcmp ( str1, argv[1] ) ) { printf ( "error : 整数を入力して下さい。\n" ); exit ( 0 ); /* str2とargv[3]による文字列の比較 */ } else if ( strcmp ( str2, argv[3] ) ) { printf ( "error : 整数を入力して下さい。\n" ); exit ( 0 ); /* argv[2]が2文字以上の場合 */ } else if ( strlen ( argv[2] ) >= 2 ) { printf ( "error : 演算子を正しく入力して下さい。\n" ); exit ( 0 ); } /* 入力された演算子の条件ごとに計算 */ if ( enzansi == '+' ) { kekka = start + end; } else if ( enzansi == '-' ) { kekka = start - end; } else if ( enzansi == '*' ) { kekka = start * end; } else if ( enzansi == '/' ) { /* startの値を0で除算する場合 */ if ( end == 0 ) { printf ( "error : 0による除算は禁止です。\n" ); exit ( 0 ); } kekka = start % end; // 剰余を求める /* 割り算の結果として余りが出なかった場合 */ if ( kekka == 0 ) { kekka = start / end; printf ( "%d %c %d = %d", start, enzansi, end, kekka ); exit ( 0 ); /* 割り算の結果として余りが出た場合 */ } else if ( kekka != 0 ) { kekka = start / end; amari = start % end; printf ( "%d %c %d = %d余り%d", start, enzansi, end, kekka, amari ); exit ( 0 ); } /* 入力された演算子が異なる場合 */ } else { printf ( "error : '+' '-' '*' '/'のいずれかの演算子を入力して下さい。\n" ); exit ( 0 ); } /* 数値1 演算子 数値2 = 演算結果の形式で出力する */ printf ( "%d %c %d = %d", start, enzansi, end, kekka ); exit ( 0 ); } もし変な部分がありましたら指摘お願いします。 一応四則演算は問題なくできます。

  • (バッチ処理) リストファイル取得と実行

    お世話になります --ここから-- cls @echo off set $aaaa=0 set $BBBB=0 echo AAAAを読む?(Yes:1 No:0) set /P $aaaa= ^>^> echo BBBBを読む?(Yes:1 No:0) set /P $bbbb= ^>^> if /i 0 EQU %$aaaa% goto next1 start /wait "AAAA BOT" "c:\prog\p.exe" -w AAAA :next1 if /i 0 EQU %$bbbb% goto next2 start /wait "BBBB BOT" "c:\prog\p.exe" -w BBBB :next2 end --ここまで-- 今までは、上記の追記・変更で対処できましたが、 数が多くなり対処しきれなくなってきたので リスト化したtxt(リストファイル.txt)を読み込み、 リストに載っている物を順次処理を行おうと考えております。 -リストファイル.txt- AAAA BBBB CCCC DDDD ---------------- ループさせたりして管理の簡素化を図りたいと思っています どのように記述を行えばよいか教えていただけませんでしょうか よろしくお願いいたします。

  • cygwinを使ってcsvファイルを読み込み、出力させようとしています

    cygwinを使ってcsvファイルを読み込み、出力させようとしています。 とりあえず、読み込みのみのプログラムを作成し、 実行させてみたのですが(run ファイル名.csv と入力) 「Error: could not start C:\cygwin\home\ユーザー名ファイル名.csv」 と出力され、読み込みができず、困っています。 プログラム初心者です。 恐縮ですがご回答よろしくお願いします。 以下に、読み込みプログラムとcsvファイルを記載します。 (プログラムは拾い物です。) <プログラム> #include <stdio.h> #define MAX_ITEM_SIZE 100 #define MAX_LINE_SIZE 1024 char *GetCSVItem(char *wp, char *buff, int size); void main(int argc, char *argv[]) { FILE *fp; char buff[MAX_LINE_SIZE], *wp, item[3][MAX_ITEM_SIZE]; int i1, len; if(argc != 2){ printf("comand error nyuuryoku keishiki\n"); return; } fp = fopen(argv[1], "r"); if(fp == NULL){ printf("can not open file[%s].\n", argv[1]); return; } for(;;){ if(fgets(buff, MAX_LINE_SIZE, fp) == NULL) break; len = strlen(buff); if(len == 0 || buff[len-1] != '\n'){ if(feof(fp) == 0){ printf("data error[%s].\n", buff); return; } } buff[len-1] = '\0'; wp = buff; if((wp = GetCSVItem(wp, item[0], MAX_ITEM_SIZE)) == NULL){ printf("error(1)\n"); break; } if((wp = GetCSVItem(wp, item[1], MAX_ITEM_SIZE)) == NULL){ printf("error(2)\n"); break; } if((wp = GetCSVItem(wp, item[2], MAX_ITEM_SIZE)) == NULL){ printf("error(3)\n"); break; } if(*wp != '\0'){ printf("error(4)\n"); break; } for(i1 = 0; i1 < 3; i1++){ printf("%d:%s\n", i1+1, item[i1]); } } fclose(fp); } char *GetCSVItem(char *wp, char *buff, int size) { int i1; buff[0] = '\0'; while(*wp == ' ' || *wp == '\t') wp++; if(*wp == '\0'){ return(NULL); } for(i1 = 0; i1 < MAX_ITEM_SIZE; i1++, wp++){ if(i1 >= size) return(NULL); buff[i1] = *wp; if(*wp == '\0'){ buff[i1] = '\0'; return(wp); } if(*wp == ','){ wp++; buff[i1] = '\0'; break; } } return(wp); } <csvファイル> 1,2,3 11,12,13 21,22,23

  • C言語 複数ファイル操作について

    Cプログラミング初心者です。 論文などの何行も文章があるようなテキストファイル(ここでは1.txtとします)と、他に予め単語をいくつか登録しているテキストファイル(2.txt)を開き、1.txtを最初の行から一行ごとに読み込み、2.txtの中にある単語が1つでもその一行の文章中に含まれていたらその一行の文章を出力し、また次の行においても2.txtの中にある単語のいずれかが含まれているかどうかを調べて含まれている場合は出力…含まれていない場合は出力せずに次の行へ…といったようにこれを1.txt内の最後の行まで繰り返し行うプログラムを作りたいのですが、自分が作ったプログラムでは含む・含まない関係なく1.txt内の文章全てが出力されてしまいます。おそらく最初のwhile文あたりがおかしいのだろうという予想はつくのですがどのように直せばよいのかわからず悩んでいます。どなたか教えていただければ嬉しいです(;_:) #include <stdio.h> #include <stdlib.h> #include <string.h> #define N 1056 void delkaigyo(char *s1,char *s2){ char *p = s1; p=strstr(s1,s2); if(p!=NULL){ strcpy(p,p+strlen(s2)); delkaigyo(p+1,s2); } } int main(void){ FILE *fp; char *filename = "2.txt"; char str1[N]; char str2[N]; char kaigyo[] = "\n"; int i; int a=0; char fname[64]; printf("file:"); scanf("%s", fname);   ←ここで1.txtを入力するとします fp = fopen(fname, "r"); while(fgets(str1, N, fp) != NULL){ delkaigyo(str1, kaigyo); memset(str1, 0, N); fread(str1, 1, N-1, fp); if((fp = fopen(filename, "r")) == NULL){ fprintf(stderr, "%serror.\n", filename); exit(EXIT_FAILURE); } while(fgets(str2, N, fp) != NULL){ delkaigyo(str2,kaigyo); if(strstr(str1,str2)!=NULL){ a = 1; printf("%s\n", str1); break; } } if(a==0){ return 0; } fclose(fp); } return EXIT_SUCCESS; }

専門家に質問してみよう