为什么这个C程序会在这个位置发生错误?

时间:2016-04-07 05:34:56

标签: c segmentation-fault

我正在制作一个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] - &gt; str的值突然丢失。有什么我想念的吗?

[我知道我应该释放任何我malloc。我也意识到我的方法原型不是正确的,但我只是想做一个快速的程序来证明我的问题]

2 个答案:

答案 0 :(得分:2)

在for循环的第一次迭代中,以下行访问未初始化的内存。

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

您还宣布了

void grow();

但实际签名即

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

首先需要在该行之前调用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);
}

答案 1 :(得分: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);