• ベストアンサー

検索の方法を教えて頂きたいです。

現在、テキストファイルの検索プログラムを課題で行っているのですが、どう処理すればよいか、苦悩しています。先生には、構造体を利用するよう言われています。どなたか、アドバイスを頂けないでしょうか?テキストファイルの内容は自分で適当に作りました。このようにしています。 →ファイル名(soccer.txt)ファイルの中身→ 例「 番号,名前,年齢 」 1 ,川口 能活,33 38,楢崎 正剛,40 20,川島 永嗣,22 10,中澤 佑二,35 51,駒野 友一,19 9 ,中村 俊輔,29 22,遠藤 保仁,17 15,鈴木 啓太,32 19,本田 圭佑,51 28,家長 昭博,25 30,高原 直泰,18 7 ,播戸 竜二,44 問題の流れは、 (1)条件を選択して下さい[1~4]   1:全部表示   2:番号で検索   3:名前で検索   4:年齢で検索   99:終了 (2) 1番を選んだら、その名の通りファイルの中身を全部表示する。 (3) 2番を選んだら、さらに、番号の条件を選んで入力[1~4]    1: 1~9 , 2: 10~19 , 3: 20~29 , 4: 30以上 とし、条件にヒットするとその行を表示するよう、考えています。 一応、全部表示は、ソースはめちゃくちゃかもしれませんが、全部表示できたので、全部の検索方法をと言うと、図々しいと思うので、番号で検索だけでも、なにかアドバイス頂けたらと思っています。 どうぞ、宜しくお願いします。(泣) #include<stdio.h> #include <stdlib.h> #include <string.h> struct data{ int no; // 番号 char name[20]; // 氏名 int age; // 年齢 }; int search_all(struct data *lis); void search_no(int number); int main() { int a; int number; data list1[12]; while(a){ printf("条件を選択して下さい[1~4]\n"); printf(" 1:全部表示\n"); printf(" 2:番号で検索\n"); printf(" 3:名前で検索\n"); printf(" 4:年齢で検索\n"); printf(" 99:終了\n"); scanf("%d", &a); if(a == 1){ // 全部表示 printf("全部表示\n"); search_all(list1); } //番号で検索 else if(a == 2){ printf("番号の条件を選んで入力して下さい[1~4]\n"); printf(" 1: 1~9\n 2: 10~19\n 3: 20~29\n 4: 30以上\n"); scanf("%d", &number); search_no(number); } } return 0; } //ファイルの情報を取得する int search_all(struct data *lis) { FILE *fp; char s[20]; char str1[20]; //番号を格納 char str2[20]; //名前を格納 char str3[20]; //年齢を格納 fp = fopen("soccer.txt", "r"); //1行単位で読込み while(fp != NULL){ fgets(s, 20, fp); if (feof(fp)){ break; } //番号を取得する strncpy(str1, s, 2); //NULL文字追加 str1[2] = '\0'; lis->no = (int)str1; //名前を取得する strncpy(str2, &s[3], 9); //NULL文字追加 str2[9] = '\0'; strcpy(lis->name, str2); //年齢を取得する strncpy(str3, &s[13], 2); //NULL文字追加 str3[2] = '\0'; lis->age = (int)str3; printf("%s %s %s \n", lis->no, lis->name, lis->age); } fclose(fp); return 0; } //番号検索 void search_no(int number) { printf("該当の番号%dの行を表示\n", number); }

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

  • ベストアンサー
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.2

★アドバイス ・まずはテキストデータをすべて読み込んで struct data 構造体にセットする関数を  きちんと作成して下さい。回答者 No.1 さんのアドバイスにある >⇒ read_data(FILE* fp, struct data* target, size_t size); のように data型の配列にファイル……を別途作成する  ↑  このような関数を作成しましょう。  内容は search_all() 関数で記述しているのを構造体の配列にセットできるように編集します。  まずは下のような関数を作って下さい。→main() 関数はサービスで作りました。残りは自分で。 サンプル: // 最大のデータ数 #define MAX_LIST (100) // 関数のプロトタイプ宣言 void read_data( FILE *fp, struct data list[], size_t size ); void print_data( struct data list[], size_t size ); void search_num( struct data list[], size_t size ); void search_name( struct data list[], size_t size ); void search_age( struct data list[], size_t size ); // メイン関数 int main( void ) {  struct data list[ MAX_LIST ]; ←テキストのデータが 100 行以内と限定  FILE *fp;  int menu;    if ( (fp = fopen("soccer.txt","r")) != NULL ){   read_data( fp, list, MAX_LIST ); ←ここで読み込む   fclose( fp );      do {    printf( "条件を選択して下さい[1~4]\n" );    printf( " 1:全部表示\n" );    printf( " 2:番号で検索\n" );    printf( " 3:名前で検索\n" );    printf( " 4:年齢で検索\n" );    printf( "99:終了\n" );    scanf( "%d", &menu );        switch ( menu ){     case 1: print_data( list, MAX_LIST ); break;     case 2: search_num( list, MAX_LIST ); break;     case 3: search_name( list, MAX_LIST );break;     case 4: search_age( list, MAX_LIST ); break;     default: break;    }   } while ( menu != 99 ); ←これで終了      return 0;  }  printf( "soccer.txt - ファイルが見つかりません。\n" );  return 1; } // テキストデータを読み込む専用関数 void read_data( FILE *fp, struct data list[], size_t size ) {  /* 記述 */ } // 構造体の内容を表示する専用関数 void print_data( struct data list[], size_t size ) {  /* 記述 */ } // 番号で検索 void search_num( struct data list[], size_t size ) {  /* 記述 */ } // 名前で検索 void search_name( struct data list[], size_t size ) {  /* 記述 */ } // 年齢で検索 void search_age( struct data list[], size_t size ) {  /* 記述 */ }

altair56
質問者

お礼

お礼が遅くなり申し訳ありません。サンプルまで作って頂いて、超初心者の自分には、大変、参考になりました。まだまだ理解できない部分があるのですが、少しずつクリアできるようがんばって行きます。また機会があればアドバイスして頂けたらと、思ってます。ありがとうございました。

その他の回答 (2)

noname#50176
noname#50176
回答No.3

構造体を使わない場合は、 (使わないとだめなんですよね…?) 共有ループを使ってみてはどうでしょうか? 3カラムCSV形式とみなして、 //a=選択NO,p=テキストファイル先頭ポインタ for (i=0;i<12;i++){ ret=Cell(a-2,p,i)//自作関数 switch (a-2) { case 0: atoi(ret)の番号値を参照・・・ break; case 1: retの文字列を参照・・・ break; case 2: atoi(ret)の年齢値を参照・・・ } char* Cell(int a,char* p,int i) { int c=0,z=0; for (j=0;j<i;j++){ while (*p-'\r' | *(p+1)-'\n') c++;c+=2;} while (z-a) {while (*p-',') c++;z++} return p+z; } とシンプルにやっても良いと思います。

  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.1

あんまり役に立たないアドバイスらしきものを。 最も注意すべき点は、「正しい関数名を付けること」です。 search_all() で「全てを表示」と言いながら、ファイルからデータを読み込んでいるのでこれを止めましょう。 ⇒ read_data(FILE* fp, struct data* target, size_t size); のように data型の配列にファイルを読み込む処理を別途作成する ⇒ search_all() ではなく、print_data(struct data* target, size_t size) のように、作成した data 配列を印字する関数とする 最初に data 配列にファイル内容を格納すれば、後は「適当な」関数を定義して、その結果を印字できるでしょう。 しかし、print_data() をせっかく作ったので、検索関数の方は search_somehow(struct data* target, ..., struct data* result); のように結果を配列に格納するようにして、印字はすべて print_data() にさせるのが良いでしょう。

altair56
質問者

お礼

お礼の返事が遅くなり申し訳ありません。アドバイスありがとうございました。超がつく初心者なので、全てのことが役に立っています。 また質問する機会があると思いますので、お暇があるときはまた宜しくお願いします。

関連するQ&A

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

    再びすみません。 先ほどは別の問題で質問させていただきました。 今回は、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; }

  • ポインタと配列

    次のソースで、結果表示でポインタを使いたいのですが、うまくいきません。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; でやると上手く実行できないのですが、なぜでずか?

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

  • C言語で、ファイルを読み込んで数字と名前に分けて配列に格納に関する質問

    C言語で、ファイルを読み込んで数字と名前に分けて配列に格納に関する質問です! ファイルを開いた後でエラーとなるのですが、何が足りないのでしょうか? ファイル内容 20 田中 10 鈴木 #include <stdio.h> #include <string.h> #include <stdlib.h> int main(int argc,char *argv[]) { FILE *fp; char str[256]; char *tp; int k,i=0; int num[10]; char na[10][20]; fp=fopen(argv[1],"r"); if(fp==NULL){ printf("ファイルを開けません\n"); return 1; }else{ printf("開けた\n"); } while(fgets(str,sizeof str,fp)!=NULL){ tp=strtok(str," "); num[i]=atoi(tp); tp=strtok(NULL," "); strcpy(na[i],tp); i++; } printf("%d\n%s\n",num[0],na[0]); printf("%d\n%s\n",num[1],na[1]); fclose(fp); return 0; }

  • 関数化

    #include <ctype.h> #include <string.h> #include <stdlib.h> void swap(char p[], char q[]); char *get(char *str, char buf[], int line, int field); typedef struct { int number; char *class_type; char* name; char *subject; } my; my *data; int main(int argc, char* argv[]) { FILE *fp; int field = 0, line = 0; char buf[1000], *str; char *bufG; int line2 = 0; if((fp=fopen("test3.csv","r"))==NULL){ printf("ファイルが開けません"); } while(fgets(buf, 1000, fp) != NULL){ line2++; } fclose(fp); printf("%d\n", line2); if((fp=fopen("test3.csv","r"))==NULL){ printf("ファイルが開けません"); } data = (my *)malloc(sizeof(my) * line2); while(fgets(buf,1000,fp) != NULL){ str = buf; while(*str != '\0'){ bufG = get(str, buf, line, field); switch(field){ case 0: data[line].number = atoi(bufG); break; case 1: data[line].class_type = (char *)malloc(strlen(bufG) +1); strcpy(data[line].class_type, bufG); break; case 2: data[line].name = (char *)malloc(strlen(bufG) + 1); strcpy(data[line].name, bufG); break; case 3: data[line].subject =(char *)malloc(strlen(bufG) + 1); strcpy(data[line].subject, bufG); break; } str++; field++; } line++; field = 0; } fclose(fp);     for(int m = 1; m < line; m++){ printf("%d\n", data[m].number); printf("%s\n", data[m].class_type); printf("%s\n", data[m].name); printf("%s\n", data[m].subject);     } return 0; } char *get(char *str, char buf[], int line, int field) { char bufG[1111]; int i; for(i = 0; *str != ',' && *str != '\0' ; i++){ if(*str == '\n'){ bufG[i] = '\0'; } else{ bufG[i] = *str; } str++; } bufG[i] = '\0'; return bufG; } 前回の質問 http://okwave.jp/qa5094929.html で提示していただいたサンプルの関数化をはかりましたが うまくいきません。これを実行すると1しか表示されません。 原因はおそらくポインタだと思いますがどうすればいいのか わかりません。教えて下さい。bufを引数にする意味ないのでは という意見は今の所はとりあえずなしで fieldの値によってbufGが色々とってくる。 例えば1,A,山田,数学の場合 field = 0のときbufGは1 filed=1のときbufGはA field=2のときbufGは山田 filed=3のときbufGは数学という ような値が返ってくるようにしたいです。

  • C言語 ポインタと配列

    #include <stdio.h> /* scanf("%c", &search); ではなく scanf(" %c", &search); であることに注意する */ char *str_chr(const char *str, char c) { char *find; find = NULL; do { if(*str == c) { find = (char*)str; break; } } while(*str++); return(find); } int main(void) { char str[100] = {0}; char search; char *find; printf("文字列を入力してください:"); scanf("%s", str); printf("検索する文字を入力してください:"); scanf(" %c", &search); find = str_chr(str, search); if(find == NULL) { puts("検索した文字は見つかりませんでした。"); } else { printf("検索した文字 %c は\"%p\"にあります。\n", *find , find); } return(0); } このコードのfind = (char*)str;の (char*)str;の部分がどうなっているのかわかりません。 あとこのfindというのは&find[0]という解釈でいいでしょうか? 教えてくださいm(_ _ )m

  • 末尾の行が二回読み込まれてしまいます。

    末尾の行が二回読み込まれてしまいます。 以下のコードで #include <stdio.h> #include <stdlib.h> //ファイルに書き込まれた24:00:00の形式の時刻を秒単位で出力する。 int translate(char* str) { int a,b,c; int time; sscanf(str,"%d:%d:%d",&a,&b,&c); time = 60*60*a + 60*b + c; return time; } int main(int argc,char *argv[]) { FILE *fp; char str[100]; int s; fp = fopen("file.time","r"); if(fp == NULL){ printf("can not open the file.\n"); return 1; } while(!feof(fp)){ fscanf(fp,"%s",str); s = translate(str); printf("%d\n",s); } fclose(fp); return 0; } 末尾の行が二回処理されてしまいます。なにがまずいのでしょうか?よろしくお願いいたします。

  • C言語のint型の配列が分かりません

    #include<stdio.h> int main(void) { int str[ ]={0,1,2} printf("%s\n", str); return 0; } というプログラムをC言語でつくってみましたが動きません.(012と表示されて欲しかったのですが) int str[ ]={1,2,3}の部分をchar str[ ]={'0','1','2'}とすれば動きます. そこで質問なのですが, printf("~%s~", (配列名));  はchar型の配列にしか適応できないのですか? ※追記 puts関数の定義は int puts (const char *str); であるそうなので char型の仮引数にはchar型のアドレスを渡さなければいけません. ではprintf関数の定義は一体どんなものなのですか?

専門家に質問してみよう