为什么 free() 存在时会在我的代码中导致错误,但当它不存在时一切运行良好?

Why does free() cause an error in my code when it's there, but everything runs well when it is not there?

我的程序在运行时获取任意数量的单词并将它们存储在动态大小的单词数组中。

目前,我的程序运行良好,除了当我使用free()释放临时双指针temp的内存时。我不太清楚为什么会这样,因为我认为如果我不使用它会导致错误。

int wordSize = 10, arrSize = 1, i = 0;
char **stringArr, **temp;
char *input;

stringArr = malloc(arrSize * sizeof(char *));

puts("Accepting input...");

for (;;) {
    if (i >= arrSize) {
        arrSize += 1;
        temp = realloc(stringArr, arrSize * sizeof(char *));

        if (temp != NULL) {
            stringArr = temp;
            free(temp); // This is the line that is giving me issues; removing it works
        } else {
            puts("Could not allocate more memory");
            return 0;
        }
    }

    stringArr[i] = malloc(sizeof(input));
    input = malloc(wordSize * sizeof(char));
    scanf("%10s", input);

    if (strcmp(input, "END")) {
        strcpy(stringArr[i], input);
        i++;
    } else
        break;
       
}
free(stringArr);

在我的程序底部,我使用 free() 没有任何问题。为什么它在这里运行正常,但在程序的前面却不行。

我觉得我遗漏了一些有关 free() 工作原理的信息。

注意:这是我第一个实现 malloc()realloc() 的程序,所以我只是刚刚开始习惯它们的工作方式。如果您知道更好的方法来完成我正在做的事情,请随时描述。

free(temp); 行导致错误(稍后),因为在前面的行 stringArr = temp; 中,您分配的 地址 即存储在指向 stringArr 指针中的 temp 指针中。因此,当您释放 temp 指向的内存时,您也会释放 stringArr 指向的内存,因为它是 相同的 内存块。将指针的值从一个变量复制到另一个变量不会创建一份(单独的)内存副本。

省略 free(temp); 行是正确的,因为稍后会在 free(stringArr); 调用中释放该内存。

重新分配成功后,您不得释放重新分配的数组。如果你这样做,代码将修改这个释放的块,它有未定义的行为,当你稍后尝试重新分配或释放这个块时,你将有更多的未定义行为。

另请注意以下内容:

    大小为 1
  • pre-allocating stringArr 不是必需的。只需将 stringArr 初始化为 0 并将 arrSize 初始化为 0realloc() 可以接受一个空指针并且表现得像 malloc().

  • stringArr[i] = malloc(sizeof(input)); 是不正确的:它将根据目标体系结构上指针的大小分配大小为 4 或 8 的 char 数组,而不是 11 字节。

  • 如果wordSize是一个单词的最大长度,你应该为空终止符多分配一个字节。 %10s 中的 10 必须匹配 wordSize 的值,这很麻烦,因为没有简单的方法将其作为变量传递给 scanf()

  • 您没有检查 scanf() 的 return 值,在文件过早结束的情况下导致未定义的行为。

  • 您有内存泄漏:input 为每次迭代分配但从未释放,释放 stringArr 而不释放其元素指向的字符串会使它们无法访问。

使用本地数组尝试读取带有 scanf() 的单词会更有效,并且只分配字符串并在成功时重新分配数组。

这是修改后的版本:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    int arrSize = 0;
    char **stringArr = NULL;
    char input[11];
    
    puts("Accepting input...");
    
    while (scanf("%10s", input) == 1 && strcmp(input, "END") != 0) {
        char **temp = realloc(stringArr, (arrSize + 1) * sizeof(*stringArr));
        if (temp != NULL) {
            stringArr = temp;
        } else {
            puts("Could not allocate more memory");
            break;
        }
        stringArr[arrSize] = strdup(input);
        if (stringArr[arrSize] == NULL) {
            puts("Could not allocate more memory");
            break;
        }
        arrSize++;
    }
    puts("Array contents:");
    for (int i = 0; i < arrSize; i++) {
        printf("%i: %s\n", i, stringArr[i]);
    }
    for (int i = 0; i < arrSize; i++) {
        free(stringArr[i]);
    }
    free(stringArr);
    return 0;
}