Search code examples
carraysfunctionchardynamic-memory-allocation

Modifying a char* by pointer in a function gives a crash


I'm fairly new to C and I'm trying to work out dynamic memory allocation for reading from a file. At least I think that's what I'm doing.

Anyway, this code works:

int readfromfile(FILE *filepointer)
{
    size_t size = 2;
    char *str = (char *) malloc(sizeof(char));
    int character = 0;
    size_t counter = 0;
    while((character = fgetc(filepointer)) != EOF)
    {
        str = (char *) realloc(str, size);
        str[counter] = (char) character;
        size ++;
        counter++;

    }
    str[counter] = '\0';
    printf("+%s+", str);
    free(str);
    return 0;
}

And this code does not:

int main()
{
    char *str = (char *) malloc(sizeof(char));
    ...
    readfromfile(ifpointer, &str);
}

int readfromfile(FILE *filepointer, char **str)
{
    size_t size = 2;
    int character = 0;
    size_t counter = 0;
    while((character = fgetc(filepointer)) != EOF)
    {
        *str = (char *) realloc(*str, size);
        *str[counter] = (char) character;
        size ++;
        counter++;
    }
    str[counter] = '\0';
    printf("+%s+", *str);
    free(str);
    return 0;
}

I cannot understand why because as far as I understand I'm sending a pointer to the location of the char array to the function and accessing the data everytime. The compilers shows no error messages, it just loops through once and on the second loop crashes after the realloc every time. The character assigned to the first value is garbage too.

I have spent an age trying to get this to worked and done a lot of research so I apologise if I've missed a solution but I'm truly stuck at this point.


Solution

  • You get a crash because

    *str[counter] = (char) character;
    

    is the same as

    *(str[counter]) = (char) character;
    

    as opposed to

    (*str)[counter] = (char) character;
    

    which is actually what you wanted. Read Operator Precedence on Wikipedia. You'll find that [] has more precedence than the * (dereference operator).

    Also, the cast here, as well as in the calls to realloc and malloc, is unnecessary. Don't forget to check the return value of realloc, malloc etc to see if they were successful in allocating memory.

    Now, you have another problem: free(str); in the second code should be free(*str);. Note that after *str has been freed from the function, you aren't supposed to read or write into this memory location from main as it has now become invalid for you to tamper with.