• ベストアンサー

再検索プログラムについて

再びすみません。 先ほどは別の問題で質問させていただきました。 今回は、address2.txtに保存してあるアドレスを検索するプログラム(下記)なのですが、 (1)アドレスが一致しないときに、再び検索できるようにしたいのですが、うまくできません。 (2)address2.txtに登録してあるアドレスの7行目以降は検索されなくなってしまいます。 これらの問題解決のご指摘をお願いします。 #define FNAME "address2.txt" #define RECORDLEN 16 #include <stdio.h> #include <stdlib.h> #include <string.h> char *format = "%-15s\n"; int main() { FILE *fp; char search[16], address[16],ans[8]; int no = 0, find = 0; fp = fopen(FNAME, "r+"); if(fp==NULL){ perror("ファイルエラー\n"); return -1; } printf("アドレスの入力-- "); gets(search); while (1) { fseek(fp, RECORDLEN * no++, SEEK_SET); if (fscanf(fp, "%s", address) == EOF) break; if (strstr(address, search) != NULL) { find++; printf("アドレス: %s\n", address); } } if(find>=1){ printf("アドレスが一致しました。" ); } else { printf("アドレスが一致しません。\n"); printf("再度検索し直しますか?(Y/N)\n"); gets(ans); if(ans[0]=='y'||ans[0]=='Y') continue; else break; } fclose(fp); return 0; }

noname#89227
noname#89227

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

  • ベストアンサー
  • Senna_FF
  • ベストアンサー率45% (153/334)
回答No.3

たびたびごめんなさい。 提示したソースは、あくまでプロトですよ(~_~;) テストケースは洗いだして、おかしいところは修正してくださいね。 それから、ファイルの中身を固定長にされているようなので、 fscanf()関数でなく、fgets()の方がお勧めです。

noname#89227
質問者

お礼

 ほんとに何度も回答していただいてどうもありがとございました。Senna_FFさんのおかげで無事にプログラムが実行できました。

その他の回答 (3)

  • mac_res
  • ベストアンサー率36% (568/1571)
回答No.4

仕様がいまいちはっきりしないのですが、少なくともバッファーオーバーフローの危険がある、gets(3)は使わないほうが良いでしょう。定義したRECORDLENや、format が使われていないのも気になります。固定長レコードのしたわけは何かあるのでしょうか?などなど… 見つからなかったときにはレコードを追加できる仕様にして書き直してみました。 #define FNAME "address2.txt" #define RECORDLEN 16 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> char *format = "%-15s\n"; int main() { FILE *fp; char search[RECORDLEN], address[RECORDLEN], ans[8]; char *p; int find = 0; fp = fopen(FNAME, "a+"); if (fp == NULL) { perror("ファイルエラー"); return(errno); } while (1) { printf("アドレスの入力-- "); if (fgets(search, RECORDLEN, stdin) == 0) { break; } if ((p = strchr(search, '\n')) != NULL) *p = '\0'; fseek(fp, 0L, SEEK_SET); find = 0; while (1) { if (fgets(address, RECORDLEN, fp) == 0) break; if (strstr(address, search) != NULL) { find++; printf("アドレス: %s\n", address); } } if (find != 0) { printf("アドレスが一致しました。\n"); } else { printf("アドレスが一致しません。\n"); printf("登録しますか?(Y/N)\n"); fgets(ans, 7, stdin); if (ans[0] == 'y' || ans[0] == 'Y') { fseek(fp, 0L, SEEK_END); fprintf(fp, format, search); fflush(fp); continue; } } printf("終了しますか?(Y/N)\n"); fgets(ans, 7, stdin); if (ans[0] == 'y' || ans[0] == 'Y') break; } fclose(fp); return 0; }

noname#89227
質問者

お礼

 私が作りたかったプログラムよりも更に素晴らしいプログラムソースを載せて頂いて嬉しい限りです。期待以上の回答どうもありがとうございました。

  • Senna_FF
  • ベストアンサー率45% (153/334)
回答No.2

とりあえず、前回指摘分のループ階層、及び変数初期化を入れてみました。 更に気づいたところを、ちょこっと修正!! (久しぶりに自宅で環境使った。意外と燃えてしまいますね。) これで動確済みです。ソースを比較してみてください。 iint main(int argc, char* argv[]) {   FILE *fp;   char search[16], address[16],ans[8];   int no = 0, find = 0;     // File Open   fp = fopen(FNAME, "r+");   if(fp==NULL){     perror("ファイルエラー\n");     return -1;   }     // Main Loop Start   while(1) {     // Initialize     no = 0;     find = 0;       // Get Console     printf("アドレスの入力-- ");     gets(search);       // String Search Loop     while (1) {       fseek(fp, RECORDLEN * no++, SEEK_SET);       if (fscanf(fp, "%s", address) == EOF)         // Not Found!!         break;       if (strstr(address, search) != NULL) {         // Get String!! Do break!!         find++;         printf("アドレス: %s\n", address);         break;       }     }       if(find>=1){       printf("アドレスが一致しました。" );     }     else {       printf("アドレスが一致しません。\n");       printf("再度検索し直しますか?(Y/N)\n");       gets(ans);       if(ans[0]=='y'||ans[0]=='Y')         // Retry         continue;       else         // Loop End         break;     }   }   fclose(fp);   return 0; } ※ちなみにstrstr()関数では部分一致になるけど、それでいいのかな?  完全一致をおこなうならmemcmp(),strcmp()系関数を使用してください。 ※今後は「うまくいきません。」でなく、「XXXXXになってしまいます」とか、「XXXXエラーが出ます」のように書かれると、  レスがつきやすくなると思います。  内容知っているのは、masaved19831109さんだけですからね。  こういうのも慣れだと思いますので、くじけずがんばってください。

  • Senna_FF
  • ベストアンサー率45% (153/334)
回答No.1

7行目以降というのがよくわからないのですが・・・ 再検索後に、変数noを初期化しないとシーク位置が先頭に戻らないのでは? ちなみにデータってどんなものなのでしょう。 "address2.txt"の内容を貼り付けてもらうと、また違った観点から検証 することができると思いますが・・・ (もちろん、実データは伏せていただいてかまいません。書式を見てみたいです。改行位置とか桁数とか。)

noname#89227
質問者

補足

"address2.txt"の中身はIPアドレスを保存していて、 例えば「X.X.X.X」と保存して次の行に改行しますが、その前に次の先頭の行が16(n-1)バイト目にくるようにスペースキーと改行で設定しているはずなのですが、 どうもうまくいきません。保存の仕方に問題があるのでしょうか?

関連するQ&A

  • continueとbreakの位置

    「address2.txt」に登録してあるアドレスを検索するプログラムなのですが、アドレスが検索されない時に再度検索できるように付け足したのですが、「continueとbreakの位置が誤っている」と表示されます。どう訂正すればうまくいくのでしょうか? #define FNAME "address2.txt" #define RECORDLEN 16 #include <stdio.h> #include <stdlib.h> #include <string.h> char *format = "%-15s\n"; int main() { FILE *fp; char search[16], address[16],ans[8]; int no = 0, find = 0; fp = fopen(FNAME, "r+"); if(fp==NULL){ perror("ファイルエラー\n"); return -1; } printf("アドレスの入力-- "); gets(search); while (1) { fseek(fp, RECORDLEN * no++, SEEK_SET); if (fscanf(fp, "%s", address) == EOF) break; if (strstr(address, search) != NULL) { find++; printf("アドレス: %s\n", address); } } if(find>=1){ printf("アドレスが一致しました。" ); } else { printf("アドレスが一致しません。\n"); printf("再度検索し直しますか?(Y/N)\n"); gets(ans); if(ans[0]=='y'||ans[0]=='Y') continue; else break; } fclose(fp); return 0; }

  • プログラムの実行

    このプログラム(下)なんですが、実行はできますが、実行結果が自分が思っているのとは異なる結果がでてしまいます。 'database.txt'には、1~100までの半角数字で入力した数字が1あがるごとに改行して保存しています。 僕は、例えばこのプログラムで2を入力すると、「一致しました」と表示されて、登録されていない数字345とかを入力すると「検索されませんでした」と表示されるようにしたいのですが、適当な数字を入れても「一致しました」と表示される場合があるのでこれを改善する方法を教えてください。 #define FNAME "database.txt" #define RECORDLEN 88 #include <stdio.h> #include <stdlib.h> #include <string.h> int main() { FILE *fp; char search[8],num[2]; int no = 0, find = 0, ip; fp = fopen(FNAME, "r"); if (fp == NULL) { perror("ファイルがオープンできません\n"); return -1; } printf("検索する番号の入力-- "); gets(search); while (1) { fseek(fp, RECORDLEN * no++, SEEK_SET); if (fscanf(fp, "%s", num) == EOF) break; if (strstr(num, search) != NULL) { find++; fscanf(fp, "%d", &ip); printf("番号結果: %d\n", ip); break; } } if(find==0){ printf("検索されませんでした\n"); } else{ printf("一致しました。\n"); } fclose(fp); return 0; }

  • プログラム実行

    下記のプログラムを実行したら、 「警告 W8065 random01.c 15: プロトタイプ宣言のない関数 'strcat' の呼び出し(関数 ma in ) エラー E2342 random01.c 15: パラメータ '__path' は const signed char * 型として 定義されているので int は渡せない(関数 main ) 警告 W8065 random01.c 34: プロトタイプ宣言のない関数 'strcmp' の呼び出し(関数 ma in ) 警告 W8065 random01.c 34: プロトタイプ宣言のない関数 'strcmp' の呼び出し(関数 ma in )」 と表示されました。どこを改善すればうまくいきますか? OSはWinXPでコンパイラはボーランドのフリーコンパイラを使用しています。 #define RECORDLEN 33 #include <stdio.h> #include <stdlib.h> int main() { FILE *fp; char fname[256], data[16], ans[8]; int no; printf("ファイル名"); fp = fopen(strcat(gets(fname), ".txt"), "r"); if (fp == NULL) { perror("ファイルがオープンできません\n"); return -1; } while (1) { printf("何人目のデータを読み込みますか---"); gets(ans); no = atoi(ans); fseek(fp, RECORDLEN * (no - 1), SEEK_SET); if (fscanf(fp, "%s", data) == EOF) { perror("読み込みエラーです\n"); continue; } printf("[氏名] %s", data); fscanf(fp, "%s", data); printf("[電話] %s\n", data); printf("続けますか(y/n): "); gets(ans); if (strcmp(ans, "n") == 0 || strcmp(ans, "N") == 0) break; } fclose(fp); return 0; }

  • getsをscanfで書き直すにはどうしたらよいですか?

    現在。行数を数えるプログラムを例をみながらエディダに入力してコンパイルしてみたのですが、gets関数ではエラーが出てそれ以上すすまないです。 他の掲示板なんかをみると、getは危険だからscanfを使うといいですよと書いてあったのですが、書き換えかたがよく分からないのです。 *以下が問題にしているソースです。 /* ************************************* */ /* */ /* 行を数えるプログラム */ /* */ /* ************************************* */ #include <stdio.h> #include <stdlib.h> void main(void) { FILE *fp; char fname[256]; int c; int count; printf("ファイル名:"); if (gets(fnama) == NULL) { /* この部分 */ printf("入力エラーが発生しました。\n"); exit (-1); } if ((fp = fopen(fname,"r")) == NULL) { printf("ファイル '%s'をオープンできませんでした。\n",fname); exit (-1); } while ((c fgetc(fp)) != EOF) { if (c == '\n') { count++; } } printf(">>> ファイル %s は %d 行です。\n",fname,count); fclose(fp); }

  • ポインタと配列

    次のソースで、結果表示でポインタを使いたいのですが、うまくいきません。1件しか表示されないのです。 ポインタの扱いがおかしいのだと思いますが、どうしたらよいでしょうか? #include <stdio.h> #include <string.h> int search(char key[256],FILE *fp,char *result[256][256]); main(void) { FILE *fp; int rep,n,i; char x[256],key[256],*result[256][256]; printf("検索キーワードを入力してください。\n" "キーワード>"); gets(key); if((fp=fopen("personal.txt","r"))==NULL) { printf("ファイルをオープンできません\n"); exit(1); } printf("=====検索結果=====\n"); n=search(key,fp,result); for(i=0;i<n;i++) { printf("%s\n",result[i]); } printf("検索結果:%d件です。\n",n); fclose(fp); } int search(char key[256],FILE *fp,char *result[256][256]) { int n=0; char *p,word[256],*name; while((p=fgets(word,256,fp))!=NULL) { if(strstr(word,key)!=NULL) { name=strtok(p," "); strcpy(result[n],name); n++; } } return n; } 実行すると、下の警告がでます。 illegal pointer combination(param)

  • ファイルの出力

    コマンドラインで指定したファイルの内容を一行ずつ表示するプログラムです。一行表示するごとに次の行も表示するか尋ねます。 #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; でやると上手く実行できないのですが、なぜでずか?

  • C言語のプログラムについてご指導願えますか?

    ファイルを読み込み、そのなかにI,We,You,He,She,Theyの単語がいくつかるかカウントするプログラムを作成したいのですが、単語のカウントがうまくできません。 下記に作成したソースを記載しますので、間違っている箇所を指摘していただけませんか? #include <stdio.h> #include <stdlib.h> #include <string.h> int main( void ) { char filename[FILENAME_MAX]; int j=0; int k=0; int l=0; int m=0; int n=0; int o=0; FILE *fp; gets(filename); fp = fopen(filename,"r"); { if(fp==NULL) { printf("ERROR"); return -1; } if(strcmp("I",fp)==0) { j++; } if(strcmp("We",fp)==0) { k++; } if(strcmp("You",fp)==0) { l++; } if(strcmp("He",fp)==0) { m++; } if(strcmp("She",fp)==0) { n++; } if(strcmp("They",fp)==0) { o++; } } printf("I: %d\n",j); printf("We: %d\n",k); printf("You: %d\n",l); printf("He: %d\n",m); printf("She: %d\n",n); printf("They: %d",o); fclose(fp); return 0; }

  • 複雑なファイルの読み取り

    あるファイルからある文字と数字を読み取りたいのですがうまくいきません。 ファイル(例) A01 B02 C03 A02 B01 A03 B03 C05 A04 C04 というファイルを読み込ませ、2行目のようにCがなければ1つ前の行のCをBがなければ1つ前のBをつかうようにしたいのですが、どうしたらいいのかわかりません。 ちなみに初心者ですので本を見ながら下記のようなところまで作ってみました。 データを検索して数値を入力 printf("A,B,Cの順で入力してください(大文字で)--"); gets(search1); gets(search2); gets(search3); while (1){ fseek(fp,RECORDLEN * no++,SEEK_SET); if(fscanf(fp,"%s",b) == EOF) break; if(strstr(b,search1) != NULL){ find++; fscanf(fp,"%s",e); fscanf(fp,"%s",d); printf("A=%s\n",b); printf("B=%s\n",e); printf("C=%s\n",d); } } いまの状態で検索すると最後の行などではBのところにCが入ったりします。どうすればうまくいくでしょうか。どなたか回答のほうをよろしくお願いします。

  • プログラムが作動しない

    コマンドプロンプトで実行して ”ファイル名は?” と聞いてきてテキストファイルのフルパス(場所)を入力してエンターキーで次は ”作成先は?” と聞いてきてフルパス(場所)を入力してエンターキーで終わり、 英文のかかれたテキストファイルから全英単語を重複なく順番に新しいテキストファイル(以下、”NEWテキスト”と呼ぶ)に書き込み保存するプログラミングです。 実際の内容の結果は次のようになる。 -------------------英文.txt------------------------------- I was wondering if my plant needs friends, do I need to get more of the same plant so it can get polinated and produce peppers? ------------------new英文.txt(プログラムによって新規作成)------------------------------ I was wondering if my plant needs friends do need to get more of the same so it can polinated and produce peppers ------------------------------------------------- ポイント (1) NEWテキストの重複チェックは同じ単語でも大文字と小文字ひとつでも違えば書き込みはOKとする(プログラムが楽なよう)    例)Apple と apple では違うものとしNEWテキストに書き込みされる。また同じ単語でも記号が含まれていても違う単語と判断し、記号付きのままNEWテキストに書き込む。    例)get! と get つまり小文字、大文字を区別して一致し、さらに文字数も一致しないと重複とみなされない。 (2) Windowsで動作すること。NEWテキストのファイル名は毎回入力しないでいいように、英文のテキストファイルのファイル名の先頭に"new" をつけたものでいい。    例)英文.txt → new英文.txt このプログラムはつぎのようになります ------------------------------------------------ #include<stdio.h> #include<stdlib.h> #include<string.h> typedef struct tag_list_t{ int num; char **wordlist; }list_t; int list_add(list_t *list, char *word){ int i; for(i=0;i<list->num;i++) if(strcmp(list->wordlist[i], word)==0) return 0; list->wordlist=realloc(list->wordlist, sizeof(char*)*(list->num+1)); list->wordlist[list->num]=strdup(word); list->num+=1; return 1; } int main(void){ list_t list={0, NULL}; char fname_in[FILENAME_MAX], fname_out[FILENAME_MAX], word[1000+1]; char *find; FILE *fp_in, *fp_out; printf("”ファイル名は?”"); fgets( fname_in, FILENAME_MAX, stdin ); printf("”作成先は?”"); fgets( fname_out, FILENAME_MAX, stdin ); if ( (find = strchr(fname_in,'\n')) != NULL ) *find = '\0'; if ( (find = strchr(fname_out,'\n')) != NULL ) *find = '\0'; if((fp_in=fopen(fname_in, "r"))==NULL) return 1; if((fp_out=fopen(fname_out, "w"))==NULL) return 2; while(fscanf(fp_in, "%1000[A-Za-z]%*[^A-Za-z]", word)==1) if(list_add(&list, word)) fprintf(fp_out, "%s\n", word); fclose(fp_in); fclose(fp_out); return 0; } ----------------------------------------------- アルクの1から12 http://www.alc.co.jp/goi/svl_ichiran1.htm を全部まとめたテキスト(約12000行) をプログラムにかけると白紙でできあがります。 なぜかわかりますか?改善方法おしえてください。

  • 検索させるプログラムです。

    文字列を入力させて、その後に検索キー入力をし、先ほど入力した文字列のなかから 一致するものを検索するプログラムです。 #include <stdio.h> int searchidx(char a[],char key) { int i=0,j=0; a[3]=key; for(i=0;i<3;i++){ if (a[i] == key){ j++; break; } } if(j==0){ return(-1); }else{ return(i); } } int main(void) { int a,i; char ky=0; char x[3]; printf("3個の文字を入力してください。\n"); for (i = 0; i < 3; i++) { printf("x[%d]:", i); scanf("%s", &x[i]); } printf("検索キー:"); scanf("%s", &ky); a=searchidx(x,ky); if (a == -1){ puts("一致しません。"); }else{ printf("%d\n",a); printf("%s\n",x[a]); } } メイン関数で文字列を入力させ、その配列とキー値をサーチ関数に渡して 一致した時の配列の添え字をaに返してメイン関数で文字列の配列のその添え字x[a]で表示されるのではないか?と思ってそうしてるつもりなのですが 実行してみると最後の一致した結果を表示させるところでエラーがでます。 表示させるところの前のprintfで一致するものの要素数が帰ってくるかどうかのチェックを入れてますが ちゃんと添え字番号は正しく返ってくるのになぜ最後の printf("%s\n",x[a]); ではダメなのでしょうか? それとscanfって%sのときは&いらなかったと思うのですが この場合&を入れないとエラーになってしまいます。

専門家に質問してみよう