2016-04-07 16 views
0

私は基本的に文をとって、各単語が何回出現するのかを数えることができるCプログラムを作ることに取り組んでいます。私は、問題を正確に再現したバージョンを削除しました。このCプログラムはなぜこの場所でセグメンテーションしていますか?

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

typedef struct testStrut{ 
    char * string; 
    int uses; 
}word; 

void grow(); 

int main(){ 
    int i; 
    int count = 1; 
    word ** words; 

    words = (word **) malloc(count * sizeof(word *)); 
    words[0] = (word *) malloc(sizeof(word)); 

    for(i = 0; i < 10; i++){ 
     printf("Re-looping i: %d \n", i); 
     printf("words[0]->string = %s \n", words[0]->string); 
     grow("TEST", words, &count); 
    } 

    printf("Done."); 
    return 0; 
} 

void grow(char * str, word ** words, int * count){ 
    word ** tmp; 

    tmp = realloc(words, (*count) * sizeof(word *)); 

    if(tmp){ 
     tmp[(*count)-1] = malloc(sizeof(word)); 
     tmp[(*count)-1]->string = malloc(strlen(str)+1); /*+1 for null terminator as pointed out */ 
     strcpy(tmp[(*count)-1]->string, str); 
     tmp[(*count)-1]->uses = 1;  
     words = tmp; 
     (*count)++; 
    } else{ 
     printf("Failure to allocate. \n"); 
     exit(0); 
    } 
    printf("Count: %d and word[0] %s \n", (*count), str); 
} 

としてだけでなく、実行からの出力:

Re-looping i: 0 
words[0]->string = (null) 
Count: 2 and word[0] TEST 
Re-looping i: 1 
words[0]->string = TEST 
Count: 3 and word[0] TEST 
Re-looping i: 2 
words[0]->string = TEST 
Count: 4 and word[0] TEST 
Re-looping i: 3 
words[0]->string = TEST 
Count: 5 and word[0] TEST   /*Prints it fine? */ 
Re-looping i: 4 
Segmentation fault (core dumped)  /*Suddenly unable to print it? */ 

グロー機能を終了するとの間でループを言葉[0]の値を再行く理由を私は理解していませんよ - > strは突然失われます。私は行方不明のものがありますか?

[私は私がまた私のメソッドのプロトタイプが正しいものではありません実現malloc.I何かを解放する必要があることを知っていますが、私はちょうど私の問題を実証した迅速なプログラムを作りたいと思っ]

+4

ヒント:何がします ' void f(int i){i = 7;} int main(){int x = 5; f(x) printf( "%d \ n"、x); return 0;} 'print? 'int i'を' word ** words'に、 'int x'を' word ** words'に、 '7'を' realloc(...) 'に変更してください。 – immibis

+1

もう一つの間違いは、間違った "文字列"の割り当てでは、文字列の長さは 'strlen(str)+ 1'で、NUL終端文字を考慮に入れます。 –

+0

あなたの例では、値が渡されてから5が出力されます。単語**を渡すとそれはポインタになりませんので、変更はメインにも反映されますか? これをキャッチしてくれてありがとうJean!私の悪い、私はその変更を反映するように編集しました。 – Nateb1121

答えて

0

問題はここにある...少し簡略化されました:

words = tmp; 

この文では、関数の外では効果がありません。

reallocは別のメモリ位置に新しいポインタを返すことがあります(またはそうでないかもしれない)ので、コードはクラッシュする前に数回動作するかもしれません。

あなたは**パラメータの代わりに単語の***の単語を使用するか、単に新しいポインタを返す必要があります。

word** grow(char * str, word ** words, int * count){ 
    word ** tmp; 

    tmp = realloc(words, (*count) * sizeof(word *)); 

    if(tmp){ 
     tmp[(*count)-1] = malloc(sizeof(word)); 
     tmp[(*count)-1]->string = malloc(strlen(str)+1); /*+1 for null terminator as pointed out */ 
     strcpy(tmp[(*count)-1]->string, str); 
     tmp[(*count)-1]->uses = 1; 
     (*count)++; 
    } else{ 
     printf("Failure to allocate. \n"); 
     exit(0); 
    } 
    printf("Count: %d and word[0] %s \n", (*count), str); 
    return tmp; 
} 

をこのようにそれを呼び出す:

words = grow("TEST", words, &count); 
+0

wordの値がtmpのアドレスに上書きされることを保証する適切な方法は何ですか?私の前提では、単語**の単語がポインタとして渡され、その変更が関数の外部に反映されると誤解されているようです... – Nateb1121

+0

@ Nateb1121新しいポインタを値として返すことができます関数パラメータを更新します。さもなければ、単語**へのポインタ(すなわち、単語***)が必要であろう。 – zakinster

+0

ああ、そうです!質問の私の行のためにお詫びしますが、単語**の単語がポインタであるために私は理解している場合、私はそのポインタの内容を変更し、grow()関数の外に反映させることができますが、 ()の外側に何らかの効果を期待していますか? – Nateb1121

2

最初に次の行が初期化されていないメモリにアクセスしているforループの繰り返し。

printf("words[0]->string = %s \n", words[0]->string); 

また、あなたはそのラインすなわち前growをコールする必要があり

void grow(char * str, word ** words, int * count) 

すなわち

void grow(); 

が、実際の署名を宣言しました。あなたはまたreallocであり、元のポインタを指すポインタwordsがメインポイントであると仮定します。

これを試してください。私は

#include <assert.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
typedef struct testStrut{ 
    char * string; 
    int uses; 
} word; 

void grow(const char *str, word *words, int count); 

int main(){ 
    int i; 
    word * words; 
    printf("sizeof word == %zu\n", sizeof(word)); 
    assert(sizeof(word) == 16); 
    words = malloc(sizeof(word)); 
    for(i = 0; i < 10; i++){ 
    printf("Re-looping i: %d \n", i); 
    grow("TEST", words, i); 
    printf("words[0]->string = %s \n", words[0].string); 
    } 
    printf("Done."); 
    return 0; 
} 
void grow(const char * str, word *words, int count){ 
    word ** tmp; 
    int idx = count - 1; 
    printf("size == %zu\n", count * sizeof(word)); 
    tmp = realloc(words, count * sizeof(word)); 
    size_t str_len = strlen(str); 
    if(tmp != NULL) { 
    tmp[idx]   = malloc(sizeof(word*)); 
    tmp[idx]->string = malloc(str_len + 1); 
    strcpy(tmp[idx]->string, str); 
    tmp[idx]->string[4] = '\0'; 
    tmp[idx]->uses = 1; 
    } else{ 
    printf("Failure to allocate. \n"); 
    exit(0); 
    } 
    printf("Count: %d and word[0] %s \n", count, str); 
} 
+0

これを実現するために急いでいることがわかりましたが、それが問題の原因になるでしょう私は経験している? 正しいプロトタイププロトタイプを使用していることを理解していますが、これは問題を実証するための素早い汚れた例です。 – Nateb1121

+0

countは、growメソッドが(* count)++行で実行されるたびにインクリメントされます。 – Nateb1121

+0

'void grow();'が許されているのは、コンパイラが引数の型を検証しないことを意味します。幸いなことに、OPはコールで正しいタイプを使用しました。もちろん、コンパイラがあなたを助けるようにプロトタイプを使うのは良い考えです。 –

関連する問題