简体   繁体   中英

Why is this C program segfaulting at this location?

I'm working on making a C program that basically can take a sentence and count how many times each word appears in it. I've made a stripped down version that reproduces the issue exactly.

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

As well as the output from a run:

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

I'm not understanding why between ending the grow function and re-going through the loop the value of words[0]->str is suddenly lost. Is there something I'm missing?

[I do know that I should be freeing anything I malloc.I also realize my method prototype isn't the correct one but I just wanted to make a quick program that demonstrated my issue]

On the first iteration of the for loop the following line is accessing uninitialized memory.

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

You have also declared

void grow();

but the actual signature ie

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

You first need to call grow before that line ie. You are also realloc and assuming that the pointer words in main points to the original pointer.

Try this. I've simplified a little bit...

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

The problem is here :

words = tmp; 

This statement has no effect outside of the function.

Since realloc may (or may not) return a new pointer to another memory location, you code may work a few times before crashing.

You should use a word*** instead of the word** parameter or simply return the new pointer:

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

And call it this way:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM