2016-04-07 22 views
0

Temelde bir cümleyi alıp her kelime içinde kaç kere göründüğü sayabilir bir C programı yapmaya çalışıyorum. Sorunu tam olarak yeniden üreten soyulmuş bir sürüm oluşturdum.Bu C programı neden bu konumda segfaultedir?

#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); 
} 

yanı sıra bir çalışma çıktısı:

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? */ 

Yetiştirme fonksiyonunu sona erdiren ve arasındaki döngü içinde kelime [0] değerini yeniden gidiş neden anlayamıyorum -> str aniden kayboldu. Kaybettiğim bir şey mi var?

[Ben de benim yöntemi prototip doğru biri değil fark malloc.I şey azat gerektiğini biliyoruz ama sadece benim sorunu göstermiştir hızlı bir program yapmak istediğini] İlk olarak

+4

İpucu: ne işe yarar ' void f (int i) {i = 7;} int main() {int x = 5; f (x); printf ("% d \ n", x); 0;} 'yazdır? Şimdi realloc (...) '' üzere 7 ' 'değiştirmek kelime ** words'' etmek I' int ve 'int x' kelimesine' için ** words' ve' – immibis

+1

Başka bir hata bir yaptık ki yanlış "dize" ayırma, bir dizenin uzunluğu, NUL sonlandırma karakterini hesaba katmak için strlen (str) + 1 'dir. I değeri tarafından geçirilen çünkü haber iletir zaman değil, –

+0

Kişisel Örnek baskılar 5 ** kelime bu yüzden herhangi bir değişiklik de ana olarak yansıtılacak bir işaretçi? Bunu yakalamak için Jean'e teşekkürler! Kötüyüm, bu değişikliği yansıtacak şekilde düzenledim. – Nateb1121

cevap

0

sorun burada ... biraz daha basit hale getirdik:

words = tmp; 

Bu ifade fonksiyonu dışında hiçbir etkisi yoktur.

(veya olmayabilir) Başka bir hafıza konumuna yeni bir işaretçi döndürebilir realloc olduğundan, kod çarpmadan önce bir kaç kez çalışabilir.

yerine kelimenin ** parametre arasında *** bir kelime kullanmak ya da sadece dönen yeni işaretçi olmalıdır:

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

Ve bu şekilde diyoruz:

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

Kelimenin değerinin üzerine yazılmasının tmp'nin adresi olmasını sağlamanın doğru yolu ne olurdu? Görünüşe göre bu kelimelerin bir işaretçi olarak aktarıldığını ve herhangi bir değişikliğin işlevin dışına yansıtılacağını düşünmekteyim ... – Nateb1121

+0

@ Nateb1121 Yeni işaretçiyi denemek yerine değer olarak döndürebilirsiniz. Bir işlev parametresini günceller. Aksi halde, kelime ** 'ye (yani kelime ***) bir işaretçi gerekli olacaktır. – zakinster

+0

Oh, duh! Sorgulama hattım için özür dilerim ama eğer doğru anlıyorsam, çünkü kelime ** kelimeler bir işaretçidir, işaretçinin içeriğini değiştirebilir ve grow() işlevinin dışında yansıyabilir, ancak sözcüklerin bulunduğu yeri değiştiremiyorum. puanlar ve büyümenin dışında herhangi bir etkisi olmasını bekler()? – Nateb1121

2

for döngüsünün yinelenmesi aşağıdaki satır başlatılmamış belleğe erişir.

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

Ayrıca

void grow(); 

bildirdikten ancak

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

yani fiili imza Önce ihtiyaç bu satır yani önce grow aramak için. Ayrıca realloc ve varsayarak orijinal pointer ana noktalarda pointer words söyledi.

bu deneyin. Ben

#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

Şimdi bunu yapmak için acele ettiğimi anladım, ancak bu sorun neden oluyor Yaşıyorum Şimdi, doğru yöntem prototipini kullandığımı anlıyorum, bu sorunu göstermek için hızlı ve kirli bir örnektir. Büyüme yönteminin (* sayımı) ++ satırı tarafından yürütüldüğü her seferinde – Nateb1121

+0

sayımı artırılır. – Nateb1121

+0

'void grow();' izin verilir, sadece derleyicinin sizin için argüman türlerini doğrulamadığı anlamına gelir. Neyse ki OP aramada doğru türleri kullandı. Elbette, prototipin kullanılması iyi bir fikirdir, böylece derleyici size yardımcı olur. –