简体   繁体   中英

Calling free() after malloc causes unexpected behaviour

Hi I read that I should call free() as soon as I could do that to free the memory but when I call free in this way my code stops working correctly. what's the problem?

I want to call free() in every iteration and when an error occurs.

int read_words(char *words[], int size, int max_str_len) {
    int i, j;
    char *ExtendedWord = NULL;
    for (i = 0; i < size && size != -1; ++i) {
        char tmp[1], ch, *word = tmp;
        for (j = 0; j < max_str_len; ++j) {
            if (scanf("%c", &ch) == EOF || ch == 'R') {
                size = -1;
                break;
            }
            if (ch == ' ')
                break;
            word[j] = ch;
            ExtendedWord = malloc((i + 2) * sizeof(char));
            if (ExtendedWord == NULL)
                return -1;
            strcpy(ExtendedWord, word);
            word = ExtendedWord;
            free(ExtendedWord);
        }
        word[j] = '\0';
        words[i] = word;
    }
    return i;
}
        strcpy(ExtendedWord,word);

strcpy() expects as 2nd parameter the address of the 1st character of a "C"-string, which in fact is a char -array with at least one element being equal to '\\0' .

The memory word points to does not meet such requirements.

Due to this the infamous undefined behaviour is invoked, probably messing up the program's memory management, which in turn causes free() to fail.

There are multiple problems in your code:

  • you free the newly allocated block instead of the previous one.
  • you so not null terminate the string before passing it to strcpy
  • word should be initialized as NULL or to a block of allocated memory, not to point to a local array which you cannot pass to free() .
  • you should reallocate the array before copying the new character at its end.

Here is a modified version:

int read_words(char *words[], int size, int max_str_len) {
    int i, j;
    for (i = 0; i < size; i++) {
        char *word = malloc(1);
        if (word == NULL)
            return -1;
        for (j = 0; j < max_str_len; ++j) {
            int ch;
            char *ExtendedWord;
            if ((ch = getchar()) == EOF || ch == 'R') {
                size = -1;
                break;
            }
            if (ch == ' ' || c == '\n')
                break;
            /* reallocate array for one more character and a null terminator */
            ExtendedWord = malloc(i + 2);
            if (ExtendedWord == NULL)
                return -1;
            memcpy(ExtendedWord, word, i);
            free(word);
            word = ExtendedWord;
            word[j] = ch;
        }
        if (size == -1) {
            free(word);
            break;
        }
        word[j] = '\0';
        words[i] = word;
    }
    return i;
}

I Read that I should call free() as soon as I could do that to free the memory

That description is a little ambiguous. It is reasonable only if you interpret "as soon as I could do that" to mean the same as "as soon as I no longer need the allocated memory".

but when I call free in this way my code stops working correctly. what's the problem?

The problem with respect to free is that you free the memory before you are done with it. Subsequently attempting to access that memory produces undefined behavior.

There are other problems with the code, too, discussed in other answers, but this is how the free fits into the picture.

I want to call free in every iteration and when an error occurs.

Inasmuch as it appears that your function intends to provide pointers to the allocated memory to its caller via the words array, you must not free that memory anywhere within the scope of the function, because the caller (it must be presumed) intends to use it. Therefore the caller must assume the responsibility for freeing it. The function's documentation should clearly describe that responsibility.

Perhaps the confusion arises here:

 word=ExtendedWord;

It is essential to understand that the assignment copies the pointer , not the space to which it points. Afterward, word points to the same (dynamically allocated) space that ExtendedWord does, so that freeing ExtendedWord invalidates both copies of the pointer.

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