0

私のプログラムでは、セグメンテーション違反が発生していますが、原因や原因の特定方法がわかりません。どんな助けでも大歓迎です!

コードでは、単語ごとに読み込もうとしていますが、行番号を追跡する必要があります。次に、データが単語と行番号であるリンクリストを作成しようとしています。

(一緒にコンパイルされた2つのファイルがあります)

void main(int argc, char **argv){
    file = fopen(argv[1],"r");
    struct fileIndex *fIndex = NULL;
    delimiters = " .,;:!-";/*strtok chars to seperate*/
    int wCount = wordcount(file);/*number of words in file*/
    char **str[wCount+1];/*where the lines are being stored*/
    int j=0;
    while(!feof(file)){/*inserting lines*/
        fscanf(file, "%s", &str[j]);
        j++;
    }

    char *token, *cp;
    int i;
    int len;
    for(i = 0; str[i]; i++){/*checking to insert words*/
        len = strlen(*str[i]);
        cp = xerox(*str[i]);
        token = strtok(cp, delimiters);
        if(!present(fIndex, token)){
            insert(fIndex, i+1,token);
        }

        while(token!=NULL){
            token = strtok(NULL, delimiters);
            if(!present(fIndex, token)){
                insert(fIndex, i+1,token);
            }
        }
        i++;
    }
    fclose(file);
}

int strcmpigncase(char *s1, char *s2){/*checks words*/
    for(;*s1==*s2;s1++,s2++){
        if(*s1=='\0')
            return 0;
    }
    return tolower(*s2)-tolower(*s2);
}

present(struct fileIndex* fIndex, char *findIt){/*finds if word is in structure*/
    struct fileIndex* current = fIndex;
    while(current!=NULL){
        current = current -> next;
        if(strcmpigncase(current -> str, findIt)==0){
            return current -> lineNum;
        }
    }
    return 0;
}

void insert(struct fileIndex *head, int num, char *insert){/*inserts word into structure*/
    struct fileIndex* node = malloc(sizeof(struct fileIndex));

    node -> str = insert;
    node -> lineNum = num;

    node -> next = head;
    head = node;
}

#define IN_WORD 1
#define OUT_WORD 0

int wordcount(FILE *input)/*number of words in file*/
{
    FILE *open = input;
    int cur;         /* current character */
    int lc=0;      /* line count */
    int state=OUT_WORD;
    while ((cur=fgetc(open))!=EOF) {
        if (cur=='\n')
            lc++;
        if (!isspace(cur) && state == OUT_WORD) {
            state=IN_WORD;
        }
        else if (state==IN_WORD && isspace(cur)) {
            state=OUT_WORD;
        } 
    }
    return lc;
}

char *xerox(char *s){
    int i = strlen(s);
    char *buffer = (char *)(malloc(i+1));
    if(buffer == NULL)
        return NULL;

    char *t = buffer;
    while(*s!='\0'){
        *t=*s;
        s++; t++;
    }
    *t = '\0';
    return buffer;
}
4

2 に答える 2

3

このコードにはかなり高い割合の問題があります。最初の数行だけを分析して、アイデアを示します。

void main(int argc、char ** argv){

mainintではなく、を返す必要がありvoidます。おそらくあなたの問題を引き起こしていませんが、どちらも正しくありません。

file = fopen(argv[1],"r");

argcを使用する前に、の値を確認する必要がありますargv[1]。引数なしでプログラムを呼び出すと、問題が発生する可能性があります。呼び出し方によっては、これが問題の原因である可能性があります。

struct fileIndex *fIndex = NULL;

表示していないヘッダーをいくつか含めない限り、これはコンパイルされるべきではありません-struct fileIndex定義されていないようです(また、投稿したコードで確認できる場所でも定義されていないようです)。

delimiters = " .,;:!-";/*strtok chars to seperate*/
int wCount = wordcount(file);/*number of words in file*/

これ(wordcount)はファイルの最後まで読み取りますが、後でファイルを巻き戻すことはありません。

char **str[wCount+1];/*where the lines are being stored*/

あなたの説明から、あなたは実際には行(複数)を保存する必要はまったくありません。おそらく必要なのは、1行を読み取り、それをトークン化し、個々のトークンを(行番号とともに)インデックスに挿入してから、次の行を読み取ることです。しかし、あなたが言ったことから、一度に複数の生のラインを保存する本当の理由はありません。

int j=0;
while(!feof(file)){/*inserting lines*/

上記のように、以前にファイルの最後まで読んだことがあり、ファイルを巻き戻したことはありません。feof(file)したがって、ここに到達するとすぐにを返す必要があるため、このループ内では何も実行されませんtrue。それを処理すると、このループは正しく機能しません。実際、フォームのループwhile (!feof(file))は本質的に常に間違っています。そのような状況では、次のfscanfような結果を確認する必要があります。

while (1 == fscanf(file, "%1023s", line))

...したがって、読み取りに失敗したときにループを終了します。

    fscanf(file, "%s", &str[j]);

ここにあるものは、基本的に悪名高いものと同等getsです。入力をバッファのサイズに制限するために何もしていません。上に示したように、通常はを使用します%[some_number]s。ここで、some_numberは使用しているバッファのサイズより1つ小さいです(もちろん、これを行うには、バッファが必要ですが、どちらもありません)。

また、行数を割り当てたスペースの量に制限するために何もしていません(ただし、個々の行と同様に、割り当てていません)。ただし、(上記のように)説明から、とにかく複数の行を格納する理由はないように思われるため、これについてはほとんど言及することを躊躇します。

あなたのコードはまた、それが割り当てるすべてのメモリをリークします-あなたはへの呼び出しを持っていますが、どこmallocへの単一の呼び出しもありません。free

実際、上記のアドバイスのいくつかは(ついに多かれ少なかれ)間違っています。コードの個々の行を修正する方法を検討していますが、実際には、一般的にコードの構造を少し変えたいと思うでしょう。ファイルを2回読み取るのではなく、1回読み取って単語をカウントし、次にもう一度読み取って単語のインデックスを作成する場合は、一度に1行ずつ読み取る必要があります(おそらく、を使用してfgets、行を単語に分割し、挿入するときに各単語をカウントします)。ああ、そしてあなたはほぼ間違いなくあなたのインデックスにリンクリストを使いたくないでしょう。ツリーやハッシュテーブルはその仕事にとって非常に理にかなっています。

また、このコードでデバッガーを使用するという方向での提案にも同意しません。デバッガーが大幅に優れたコードにつながる可能性は低いです。ローカライズされた問題のいくつかを見つけるのに役立つ可能性がありますが、大幅に優れたプログラムにつながる可能性は低いです。代わりに、実際に使用する必要のあるツールとして、鉛筆と紙をお勧めします。あなたの現在の問題は、主に、目標を達成するために必要な手順を実際に理解するのに十分な問題について考えていなかったことが原因であると思います。デバッガーは、その質問に対する答えを見つけるのにあまり役立たないでしょう。

于 2012-04-09T08:41:41.770 に答える
2

優れたデバッガーが手元にない場合、適切なフォールバックはprintf、コードのステップでいくつかのステートメントを追加することです。これにより、クラッシュする前にどれだけ遠くまで到達するかを確認できます。

このコードでは:

char **str[wCount+1];/*where the lines are being stored*/
int j=0;
while(!feof(file)){/*inserting lines*/
   fscanf(file, "%s", &str[j]);
   j++;
}

strsへのポインタの配列ですchar *。ループでは、入力の各部分をその中のスロットに読み込んでいます。いくつかの問題があります。

  1. *sとsの数には誤りがあると思います&(私は通常、それらについてそれほど深く考える必要を避けるために、それほど多くのレベルのポインター間接参照をプログラムしません;-)。 &str[j]はその配列要素のアドレスですが、その配列要素はポインタへのポインタです。これで、ポインタへのポインタができました。代わりにchar *str[wCount+1]、を読んで読んだらstr[j]、一致するかもしれないと思います。(また、私はあまり使用しないfscanfので、おそらく誰かがそれをどのように使用するのが最善かを確認することができます。)

  2. さらに明らかに、文字列データに実際にメモリを割り当てているわけではありません。アレイ自体に割り当てるだけです。おそらく、それぞれに固定量を割り当てたいと思うでしょう(各fscanf呼び出しの前にループでそれを行うことができます)。実際には、その固定サイズを超えて読み取る可能性があり、別のメモリエラーが発生する可能fscanf性があることを忘れないでください。繰り返しますが、これを回避するには、使用法の専門家が必要です。fscanf

これがスタートに役立つことを願っています。printf提案が失敗するコード内のより具体的なポイントを見つけた場合は、それを質問に追加します。

于 2012-04-09T05:12:39.460 に答える