1

char *を返す(検出する'\n') とNULLonを返す lineget 関数がありますEOF。そのmain()行から特定の単語を認識しようとしています。私はstrtokを使用しました:

int main(int argc, char **argv)
{
    char *line, *ptr;
    FILE *infile;
    FILE *outfile;
    char **helper = NULL;
    int strtoks = 0;
    void *temp;

    infile=fopen(argv[1],"r");
    outfile=fopen(argv[2],"w");

    while(((line=readline(infile))!=NULL))
    {
        ptr = strtok(line, " ");

        temp = realloc(helper, (strtoks)*sizeof(char *));
        if(temp == NULL) {
            printf("Bad alloc error\n");
            free(helper);
            return 0;
        } else {
            helper=temp;
        }
        while (ptr != NULL) {
            strtoks++;
            fputs(ptr, outfile);
            fputc(' ', outfile);
            ptr = strtok(NULL, " ");
            helper[strtoks-1] = ptr;
        }
        /*fputs(line, outfile);*/
        free(line);
    }
    fclose(infile);
    fclose(outfile);
    return 0;
}

今、トークン化されたすべての単語を配列に入れる方法がわかりません(char ** helperその目的で作成しました)ので、qsortlikeで使用できますqsort(helper, strtoks, sizeof(char*), compare_string);

広告。2 うまくいくとしても、その行をクリアして次の行の並べ替えに進む方法がわかりません。どうやってするか?

私もvalgrindをクラッシュさせました(上記のコードを使用)->「valgrind:「不可能」が発生しました:致命的なシグナルによって強制終了されました」

間違いはどこですか?

4

3 に答える 3

2

最も明白な問題 (他にもある可能性があります) は、ヘルパーを行頭の strtoks の値に再割り当てしているが、strtoks をインクリメントし、より高い値の strtoks で配列に追加していることです。たとえば、最初の行の strtoks は 0 であるため、temp = realloc(helper, (strtoks)*sizeof(char *));ヘルパーはNULLのままですが、その行のすべての単語をヘルパー配列に追加しようとします。

概念的に単純な、まったく異なるアプローチをお勧めします。

char buf[1000]; // or big enough to be bigger than any word you'll encounter
char ** helper;
int i, numwords;

while(!feof(infile)) { // most general way of testing if EOF is reached, since EOF 
                       // is just a macro and may not be machine-independent.
    for(i = 0; (ch = fgetc(infile)) != ' ' && ch != '\n'; i++) { 
        // get chars one at a time until we hit a space or a newline
        buf[i] = ch; // add char to buffer
    }
    buf[i + 1] = '\0' // terminate with null byte
    helper = realloc(++numwords * sizeof(char *)); // expand helper to fit one more word
    helper[numwords - 1] = strdup(buffer) // copy current contents of buffer to the just-created element of helper
}

私はこれをテストしていないので、正しくないか、理解できないことがあれば教えてください。ファイルのオープンとクローズ、および最後に解放することは省略しました (ヘルパー自体を解放する前に、ヘルパーのすべての要素を解放する必要があることに注意してください)。

于 2012-09-22T22:25:43.553 に答える
2

strtokのプロトタイプでわかるように:

char * strtok ( char * str, const char * delimiters );

というstrことはありませんconst。実際に行うことは、見つかった区切り文字を null バイト ( ) にstrtok置き換えて、トークンの先頭へのポインターを返すことです。\0str

例:

char in[] = "foo bar baz";
char *toks[3];

toks[0] = strtok(in, " ");
toks[1] = strtok(NULL, " ");
toks[2] = strtok(NULL, " ");

printf("%p %s\n%p %s\n%p %s\n", toks[0], toks[0], toks[1], toks[1], 
                                toks[2], toks[2]);
printf("%p %s\n%p %s\n%p %s\n", &in[0], &in[0], &in[4], &in[4], 
                                &in[8], &in[8]);

結果を見てみましょう。

0x7fffd537e870 foo
0x7fffd537e874 bar
0x7fffd537e878 baz
0x7fffd537e870 foo
0x7fffd537e874 bar
0x7fffd537e878 baz

ご覧のとおり、同じ場所toks[1]を指しています。オリジナルは変更されており、実際にはすべてのトークンが のどこかを指しています。&in[4]strtoksstr

あなたの場合、あなたの問題はあなたが解放することですline

free(line);

... 内のすべてのポインターを無効にしますhelper。を解放した後qsortにアクセスしようとすると、解放されたメモリにアクセスすることになります。helper[0]line

代わりにトークンをコピーする必要があります。

ptr = strtok(NULL, " ");
helper[strtoks-1] = malloc(strlen(ptr) + 1);
strcpy(helper[strtoks-1], ptr);

明らかに、(それ自体helperに加えて) その後の各要素を解放する必要があります。helper

于 2012-09-22T22:18:15.257 に答える
1

次の理由により、「不正な割り当て」エラーが発生するはずです。

char **helper = NULL;
int strtoks = 0;

...

while ((line = readline(infile)) != NULL)  /* Fewer, but sufficient, parentheses */
{
    ptr = strtok(line, " ");

    temp = realloc(helper, (strtoks)*sizeof(char *));
    if (temp == NULL) {
        printf("Bad alloc error\n");
        free(helper);
        return 0;
    }

これは、の値strtoksがゼロであるためです。そのため、 (それ自体がnullポインタであった)がrealloc()指すメモリを解放するように要求しています。helper外部の可能性の1つは、ライブラリがクラッシュすることです。クラッシュrealloc(0, 0)するべきではありませんが、見落とされている可能性のある奇妙なエッジケースです。もう1つの可能性は、realloc(0, 0)逆参照が許可されていない0バイトのデータへのnull以外のポインターを返すことです。コードがそれを逆参照すると、クラッシュします。NULLを返すこととNULL以外を返すことの両方が、C標準で許可されています。どの動作realloc()が表示されているかに関係なく、クラッシュするコードを記述しないでください。(の実装がrealloc()のNULL以外のポインタを返さないrealloc(0, 0)場合は、クラッシュしたコードを正確に表示していないのではないかと疑っています。valgrindrealloc(0, 0)(これは公正な成果です—おめでとうございます)プログラムがNULLを返す場合のように制御下で終了するのが見えないためです。)

次を使用すると、この問題を回避できるはずです。

    temp = realloc(helper, (strtoks+1) * sizeof(char *));

strtoksある時点で自分自身をインクリメントすることを忘れないでください。

于 2012-09-22T22:36:19.897 に答える