c言語を用いた文書検索に関する質問です

このQ&Aのポイント
  • c言語に詳しくないため、文書検索プログラムの実装について詳しい方に質問です。
  • ディレクトリ内の複数の文書から特定の単語を含む文書を検索し、テキストファイル名を表示するプログラムを作成中です。
  • コンパイルは通るが、コマンドラインの入力後にsegmentation faultが発生します。原因が分からず困っています。
回答を見る
  • ベストアンサー

c言語を用いた文書検索に関する質問です。

いつもお世話になっています。 c言語にあまり詳しくないので、どなたか詳しい方お願いします。 今回、ディレクトリの複数文書内で特定の単語(今回はクエリと呼びます)を含む文書を探し出すして、テキストファイル名を表示する処理を行うプログラムを作成していました。 以下に添付したソースは、コンパイル自体は通るのですがコマンドラインを ./ex12 "green" corpus/*.txt と入力するとsegmentation faultとなってしまいます。 (ex12は実行ファイル名、greenに特に意味はありません。別の単語でも同じ結果が出てしまいます。) 複数ファイルではなく1つの文書内での検索は問題なかったのですが、何が原因なのかがよく分かりません。 1つの文書内検索の際は、メインループの最初のfor文を除いての処理となります。 printfを用いていろいろ試した結果、ファイル自体はきちんと読み込めているようなのでfor文を入れたのが原因ではないようなのですが・・・。 ちょっと原因が分からなくて詰まってしまったので、どなたか詳しいかたよろしくお願いします。 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<ctype.h> int main(int argc, char* argv[]){ FILE* fp; char buffer[2048]; char kueri[256]; char* s; char* delimiter = " .,"; //単語の区切れの定義 int i; int flag = 0; /*コマンドラインが正しく入力されているかの確認*/ if(argc < 3){ printf("error1\n"); exit(1); } /*入力されたクエリをkueriに格納する*/ strcpy(kueri,argv[1]); /*英小文字を英大文字に変換する処理を\0まで繰り返す*/ s = kueri; while(*s != '\0'){ *s = toupper(*s); s++; } /*メインループ*/ for(i = 2; i < argc; i++){ /*ファイルを開く*/ if((fp = fopen(argv[i], "r")) == NULL){ printf("error2"); exit(1); } while(fgets(buffer,sizeof(buffer),fp) != NULL){ /*最後に\0を格納する*/ buffer[strlen(buffer)-1] = '\0'; /*英小文字を英大文字に変換する処理を\0まで繰り返す*/ s = buffer; while(*s != '\0'){ *s = toupper(*s); s++; } /*strtokを用いて単語毎に区切っていく(1単語目)*/ s = strtok(buffer,delimiter); if(strcmp(s,kueri) == 0){ printf("入力されたクエリを文書内に発見しました。\n"); printf("file name: %s\n",argv[i]); flag = 1; }else{ /*strtokを用いて単語毎に区切っていく(2単語目以降)*/ while((s = strtok(NULL, delimiter)) != NULL){ if(strcmp(s,kueri) == 0){ printf("入力されたクエリを文書内に発見しました。\n"); printf("file name: %s\n",argv[i]); flag = 1; } } } } fclose(fp); } if(flag == 0){ printf("クエリを文書内に発見できませんでした。\n"); } exit(0); }

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

  • ベストアンサー
  • tyatsumi
  • ベストアンサー率58% (30/51)
回答No.1

入力ファイル内に空行があると、 次の部分でSegmentation faultになるようです。 ---- /*strtokを用いて単語毎に区切っていく(1単語目)*/ s = strtok(buffer,delimiter); if(strcmp(s,kueri) == 0){ ---- bufferが空行だとstrtokが返すsがNULLになるようなんですが、 そのせいでstrcmpがSegfaultになる、ということのようです。 strtokの2回目以降の呼び出しのように、sのNULLチェックを加えれがよいと思います。 ちなみに解析にはgdbというデバッガを使いました。 Segmentation faultが何処で起きたかを調べるにはgdbが便利です。 もしgccを使っているようなら、gdbの使いかたも調べてみてください。

mikoto1129
質問者

お礼

ありがとうございます! 無事作成することができました。 gccを使っていたにで、gdbについても調べてみます。 本当にありがとうございました。

関連するQ&A

  • c言語で文書検索プログラムについて質問です。

    いつもお世話になっています。 今回、大学の課題でc言語を用いて文書検索のプログラムを作成しています。 クエリ(検索単語)を2つ入力して、クエリ2つを同じ行に含む1文が存在した場合そのテキストファイルのファイル名を出力するプログラムを作成しています。 検索する文書は、ソースファイルと同じディレクトリにあるcorpusディレクトリ内のテキストファイルについて行います。 概ね、自力で作成はできているよう思うのですが、どうしても出力がうまくいきません。 出力条件、もしくはstrcmpのあたりに原因があるような気がするのですが・・・。 以降に私の作成したソースファイルを添付しておきますので、 原因のわかる方ぜひお願いします。 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<ctype.h> int main(int argc, char* argv[]){ FILE* fp; char buffer[1024]; char kueri1[256]; char kueri2[256]; int flag_kueri = 0; //kueri1,kueri2がどちらもあれば1に int flag_kueri1 = 0; //kueri1があれば1に int flag_kueri2 = 0; //kueri2があれば1に int i; cahr* s; char* delimiter = " .,"; /*コマンドラインが正しく入力されているかの確認*/ if(argc < 4){ printf("error1\n"); exit(1); } /*入力されたクエリ1をkueri1に格納*/ strcpy(kueri1,argv[1]); /*入力されたクエリ2をkueri2に格納*/ strcpy(kueri2,argv[2]); /*kueri1の英小文字を英大文字に変換する処理を\0まで繰り返す*/ s = kueri1; while(*s != '\0'){ *s = toupper(*s); s++; } /*kueri2の英小文字を英大文字に変換する処理を\0まで繰り返す*/ s = kueri2; while(*s != '\0'){ *s = toupper(*s); s++; } /*メインループ*/ for(i = 3; i < argc; i++){ /*ファイルを開く*/ if((fp = fopen(argv[i], "r")) == NULL){ printf("error2"); exit(1); } /*文書を1行ずつ読み込んで処理を行う*/ while(fgets(buffer,sizeof(buffer),fp) != NULL){ /*最後に\0を格納*/ buffer[strlen(buffer) - 1] = '\0'; /*bufferの英小文字を英大文字に変換する処理を\0まで繰り返す*/ s = buffer; while(*s != '\0'){ *s = toupper(*s); s++; } /*strtokを用いて単語ごとに区切っていく(1単語目)*/ s = strtok(buffer,delimiter); if(s != NULL){ /*kueri1かどうか判定*/ if(strcmp(s,kueri1) == 0){ flag_kueri1 = 1; } /*kueri2かどうか判定*/ if(strcmp(s,kueri2) == 0){ flag_kueri2 = 1; } /*strtokを用いて単語ごとに区切っていく(1単語目)*/ while((s = strtok(NULL,delimiter)) != NULL){ /*kueri1かどうか判定*/ if(strcmp(s,kueri1) == 0){ flag_kueri1 = 1; } /*kueri2かどうか判定*/ if(strcmp(s,kueri2) == 0){ flag_kueri2 = 1; } } } /*kueriが両方なかったらflar_kueriを1にする*/ if(flag_kueri1 == 1 && flag_kueri2 == 1){ }else{ flag_kueri = 1; } /*両方のkueriがあればファイル名を出力*/ if(flag_kueri == 0){ s = argv[i]; printf("file_name: %s",s); } } fclose(fp); exit(0); }

  • c言語で文書を読み込み、単語の出現頻度を教える

    c言語の課題で、与えられた文書を読み込んでその中にある単語の出現頻度を教えるプログラミングを作成しているのですが、うまくいきません。 どこが間違っているのでしょうか?? ファイルの中身は As sweet as coat , green , milk And everyone think coat になっており、求めたい回答は buffer[0]=As count=1 buffer[1]=sweet count=1 buffer[2]=as count=1 buffer[3]=coat count=2 buffer[4]=green count=1 buffer[5]=milk count=1 buffer[6]=And count=1 buffer[7]=everyone count=1 buffer[8]=think count=1 Number of words:9 にしたいのです。 プログラミングは #include<stdio.h> #include<stdlib.h> #include<string.h> #include<ctype.h> typedef struct token_checker{ char * token; int count; }TOKEN_CHECKER; int main(int argc,char* argv[]){ FILE * fp; char buffer[1024]; int numword=0; char * delimiter = " .,"; char * s; TOKEN_CHECKER *t; int j; int i = 0; int flag =0; int find = -1; t=(TOKEN_CHECKER*)malloc(sizeof(TOKEN_CHECKER)*24); if(argc != 2){ printf("Parameter error.\n"); exit(1); } if((fp=fopen(argv[1],"r"))==NULL){ printf("File open error.\n"); exit(1); } while( fgets(buffer,sizeof(buffer),fp)!=NULL){ buffer[ strlen(buffer)-1]='\0'; s = strtok(buffer,delimiter); if(s != NULL){ t[numword].token=s; for(i=0;i<=numword;i++){ if(strcmp(t[numword].token,t[i].token)==0){ t[i].count++ } } printf("buffer[%d]=%s count=%d\n",numword,t[numword].token,t[numword].count); numword++; } while((s=strtok(NULL,delimiter)) != NULL){ t[numword].token=s; for(i=0;i<=numword;i++){ t[numword].count=0; if(strcmp(t[numword].token,t[i].token)==0){ t[i].count++; } } printf("buffer[%d]=%s count=%d\n",numword,t[numword].token,t[numword].count); numword++; } } printf("Number of words:%d\n",numword); free(t); fclose(fp); exit(0); } になっており、実行すると buffer[0]=As count=1 buffer[1]=sweet count=1 buffer[2]=as count=1 buffer[3]=coat count=1 buffer[4]=green count=1 buffer[5]=milk count=1 buffer[6]=And count=1 buffer[7]=everyone count=1 buffer[8]=think count=1 buffer[9]=coat count=1 Number of words:9 となってしまい、coatがカウントされないのです。

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

  • C言語でファイルの内容を strtok関数 を使って数字と文字を分けて

    C言語でファイルの内容を strtok関数 を使って数字と文字を分けて配列に格納したいのですが、うまくできません。 どこが駄目なのかご指摘をお願いします! ファイル内容 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 i=0; int num[10]; char na[10]; fp=fopen(argv[1],"r"); while(fgets(str,sizeof str,fp)!=NULL); tp = strtok ( str, " " ); while(tp != NULL ) { num[i]=atoi(tp); tp = strtok( NULL," "); if ( tp != NULL ){ na[i]=*tp; } i++; } printf("%d\n%s",num[0],na[0]); printf("%d\n%s",num[1],na[1]); fclose(fp); return 0; }

  • C言語の質問です

    下記のプログラムはテキストファイルを読み込み、AからZまでの文字(小文字、大文字は区別しない)がそれぞれ何回 現れたかを数えるプログラムです。 #include <stdio.h> #include <stdlib.h> #include <ctype.h> int count[26]; int main(int argc, char *argv[]) { FILE *fp; char ch; int i; /* ファイル名の指定を調べる */ if(argc!=2) { printf("ファイル名の指定がありません\n"); exit(1); } if((fp = fopen(argv[1], "r"))==NULL) { printf("ファイルを開くことができません\n"); exit(1); } while((ch=fgetc(fp))!=EOF) { ch = toupper(ch); if(ch>='A' && ch<='Z') count[ch-'A']++; } for(i=0; i<26; i++) printf("%c は %d 回出現\n", i+'A', count[i]); fclose(fp); return 0; } 1)int count[26]; で、なぜ26なのかが分かりません。 2)count[ch-'A']++; はどういう動作をするのか詳しく教えてほしいです。 3)よって、for文がどういう動作で表示しているのかが分かりません。 未熟者の私ですが、どなたか教えていただけないでしょうか?

  • [動的配列]C言語の勉強で簡単な単語帳プログラム

    C言語の勉強として以下のような簡単なプログラムを作りました。 テキストファイルからユーザが入力した単語を検索し、ヒットしたものだけ その単語とその説明を表示するというプログラムです。 正常に動いているようなので、 つぎはループごとに、読み込んだ文字数に合わせて 配列(mean)の要素数を動的に確保するということを しようと思うのですがどのタイミングでmallocやreallocを入れればよいのか いまいちよくわかりません。 また、このプログラムの欠点などありましたら教えていただけると助かります。 よろしくお願いします。 --------------------------------------------------------------------- //マイ単語帳プログラム #include<stdio.h> #include<stdlib.h> #include<string.h> main(){ char input[100]; //ユーザが入力した文字列を格納 char tango[200]; //ファイルの単語 char mean[1000]; //ファイルの説明 char conti; //検索を続けるかどうかの入力 int flag; //検索単語がヒットした場合に立てるフラグ FILE *fp; //単語ファイルのopen if((fp=fopen("tango.txt","r"))==NULL){ printf("ファイルが開けません。"); exit(1); } /*******************ファイルからの文字列読み込み****************************/ //Yが入力されるまで検索を続ける do{ printf("検索する単語を入力してください。\n"); scanf("%s",input); printf("検索対象:%s\n\n",input); flag=0; //ヒットしたかどうかのフラグの初期化 while((fscanf(fp," %s %s",tango,mean))!=EOF){ //fscan 書式を指定して読み込める。 if(strcmp(tango,input)==0){ //strcmpは2つの引数が同じ時0を返す printf("%s\n%s\n\n\n",tango,mean); flag=1; //ファイル内に単語があった場合にフラグを立てる。 } } rewind(fp); if(flag==0){ printf("その単語は登録されていません。\n"); } printf("検索を終了しますか? ==> Y\n"); printf("検索を続けるにはY以外の文字を入力してください。\n"); scanf(" %c",&conti); //scanfの問題点を回避するために読み込み前に半角スペース } while(conti!='Y'); /**************************************************************************/ fclose(fp); return; } ---------------------------------------------------------------- tango.txt apple リンゴ SMTP 電子メールの送信や転送を行うためのプロトコル。 rewind 形式:rewind(ファイルポインタ); C言語のファイルシステム関数。ファイルの現在位置をファイルの先頭に置くことができる。

  • ファイルの入出力に関する質問

    CSVファイルを読み込んで、処理をするプログラムを書いています。 しかし、うまくいきません。 CSVファイルは 単語1,数値データ 単語2,数値データ のようになっており、 これをsの配列に格納したいと思っています。 プログラムは以下の通りなんですが。。。 strtokはhttp://www9.plala.or.jp/sgwr-t/lib/strtok.html を参考にしました。 どなたかおしえていただけないでしょうか? #include<stdio.h> #include <string.h> int main(void) { FILE *fp; char s[1000][1000]; char tp[256]; int i=0; if((fp=fopen("in.csv","r"))==NULL){ printf("ファイルオープンできませんよ\n"); exit(1); } while(fgets(tp,256,fp)!=NULL){ tp=strtok(fp,","); puts(s[i][0]=tp); while (tp != NULL ) { tp = strtok(NULL,","); if (tp= NULL ){ puts(s[i][1]=tp); }}i++; } return(0); }

  • csvファイルの実績データをC言語で解析するのですが...

    C言語を学び始めたばかりなのに、csvファイルの実績データでフィールドが15あり、レコード数が1000000近くあるファイルの15番目のフィールドを足し合わせて、出力するということをやっているのですが、まだまだわからないことだらけです。 1レコード目がカラム名なので2レコード目から足し合わせるんですがそこのところもよくわからずじまいで... 一応、書いたプログラムが #include <stdio.h> #include <stdlib.h> #include <string.h> int main() { FILE *fp; char buffer[50],*p; int cnt, num, sum; fp = fopen("j0.csv","r"); if(fp == NULL){ printf("ファイルが開けませんでした。\n"); exit(-1); } while(fgets(buffer,fp) != NULL){ p = strtok(buffer,","); cnt = 1; while(p!=NULL){ num = atoi(p); printf("%d:%d,",cnt,num); p = strtok(NULL,","); cnt++; if(cnt==15) sum=sum+num } printf("\b\b \n"); } printf(%d \n",num); fclose(fp); return(0); } と書いたんですが、ぜんぜんな状態です。誰かご教授願えませんか?

  • C言語 strtok

    失礼します。現在こちらでアドバイスを頂きfgetcを使用して配列に格納をすることができたのですが、CSVをカンマ区切りで格納したいのですが上手くいかず困っています。strtokを使用方法をドキュメントを読んでもうまく区切ったものを配列に入れる方法がわかりません 何卒よろしくお願いします。 ソースコード #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include<string.h> #define MAXITEM 1400 int split(char *str, const char *delim, char *outlist[]) { char *tk; int cnt = 0; tk = strtok(str, delim); while (tk != NULL && cnt < MAXITEM) { outlist[cnt++] = tk; tk = strtok(NULL, delim); } return cnt; } int main(void) { FILE *fp; char *fname = "testfile.csv"; char *tp; char *array[1400]; char *test[11][1400]; char c; int i = 0; int n,y; char *tp[1400]; fp = fopen(fname, "r"); if (fp == NULL) { printf("%sファイルが開けません¥n", fname); return -1; } while ((c = fgetc(fp)) != EOF) { array[i] = (char)c; i++; } tp = strtok(array, ","); puts(*tp); while (tp != NULL) { tp = strtok(NULL, ","); if (tp != NULL)puts(tp); } for (n = 0; n < 11; n++) { for (y = 0; y < 1400; y++) { test[n][y] = tp[y]; printf("%c", test[n][y]); } } fclose(fp); return 0; }

  • 1000000レコードもあるcsvファイルの実績データをC言語で計算しているのですが...

    C言語を学び始めたばかりなのに、csvファイルの実績データでフィールドが15あり、レコード数が1000000近くあるファイルの15番目のフィールドを足し合わせて、出力するということをやっているのですが、まだまだわからないことだらけです。 一応、書いたプログラムが #include <stdio.h> #include <stdlib.h> #include <string.h> int main() { FILE *fp; char buffer[50],*p; int cnt, num, sum; fp = fopen("j0.csv","r"); if(fp == NULL){ printf("ファイルが開けませんでした。\n"); exit(-1); } while(fgets(buffer,fp) != NULL){ p = strtok(buffer,","); cnt = 1; while(p!=NULL){ num = atoi(p); printf("%d:%d,",cnt,num); p = strtok(NULL,","); cnt++; if(cnt==15) sum=sum+num } printf("\b\b \n"); } printf(%d \n",num); fclose(fp); return(0); } と書いたんですが、ぜんぜんな状態です。誰かご教授願えませんか?

専門家に質問してみよう