- ベストアンサー
再検索プログラムについて
再びすみません。 先ほどは別の問題で質問させていただきました。 今回は、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; }
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
たびたびごめんなさい。 提示したソースは、あくまでプロトですよ(~_~;) テストケースは洗いだして、おかしいところは修正してくださいね。 それから、ファイルの中身を固定長にされているようなので、 fscanf()関数でなく、fgets()の方がお勧めです。
その他の回答 (3)
- mac_res
- ベストアンサー率36% (568/1571)
仕様がいまいちはっきりしないのですが、少なくともバッファーオーバーフローの危険がある、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; }
お礼
私が作りたかったプログラムよりも更に素晴らしいプログラムソースを載せて頂いて嬉しい限りです。期待以上の回答どうもありがとうございました。
- Senna_FF
- ベストアンサー率45% (153/334)
とりあえず、前回指摘分のループ階層、及び変数初期化を入れてみました。 更に気づいたところを、ちょこっと修正!! (久しぶりに自宅で環境使った。意外と燃えてしまいますね。) これで動確済みです。ソースを比較してみてください。 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)
7行目以降というのがよくわからないのですが・・・ 再検索後に、変数noを初期化しないとシーク位置が先頭に戻らないのでは? ちなみにデータってどんなものなのでしょう。 "address2.txt"の内容を貼り付けてもらうと、また違った観点から検証 することができると思いますが・・・ (もちろん、実データは伏せていただいてかまいません。書式を見てみたいです。改行位置とか桁数とか。)
補足
"address2.txt"の中身はIPアドレスを保存していて、 例えば「X.X.X.X」と保存して次の行に改行しますが、その前に次の先頭の行が16(n-1)バイト目にくるようにスペースキーと改行で設定しているはずなのですが、 どうもうまくいきません。保存の仕方に問題があるのでしょうか?
お礼
ほんとに何度も回答していただいてどうもありがとございました。Senna_FFさんのおかげで無事にプログラムが実行できました。