释放动态分配的指针数组

Freeing an array of dynamically allocated pointers

我正在备考,我对提供的样题有疑问:

Implement the function free_array with prototype void free_array(void *a[], int length). The purpose of the function is to free the dynamically allocated memory associated with each array element in the first parameter passed to the function. The function must handle the scenario in which two or more array entries point to the same memory (only one free can be applied to a single memory location).

我的第一个想法是将每个释放的索引设置为 NULL,因为在 NULL 上调用 free() 是无害的。所以我做了以下事情:

void free_array(void *a[], int length) { 
   int i;
   for (i = 0; i < length; i++) {
      free(a[i]);
      a[i] = NULL;
   }
}

提供的解决方案与我的完全不同,我不完全理解他们在做什么。这是我得到的答案:

void free_array(void *a[], int length) { 
    int i, j;
    for (i = 0; i < length; i++) {
        if (a[i] != NULL) {
            free(a[i]);
            for (j = i + 1; j < length; j++) {
                if (a[j] == a[i]) {
                    a[j] = NULL;
                }
            }
        }
    }
}

我真的很困惑这里发生了什么。看起来他们正在释放每个条目并将具有相同内容的条目标记为 NULL。但是,我认为我们不应该重新访问释放的内存?还有,我的方法还能用吗?

例如

假设你有一个字符串数组

char* ar[5]; 

你分配一些字符串并让 0 和 4 索引指向同一个分配的字符串

ar[0] = ar[4] = strdup("mycommonstring");
ar[1] = strdup("hello");
ar[2] = strdup("world");
ar[3] = strdup("!");

随着你的回答,你将首先释放 ar[0] 指向的内容,不幸的是 ar[4] 仍然指向相同的内存位置,但是当 free(ar[0]) 被调用时,它指向的内存位置是无效的。之后在 ar[4] 上调用 free 时,会报错。

给定的示例确保指向同一位置的所有指针都将设置为 NULL,以避免将无效地址传递给自由函数。所以不,内存位置没有被再次访问,只有指向内存位置

的指针

代码的意图是数组中的多个位置可以指向同一个元素但必须只释放一次。内部循环会将指向同一内存块的尚未处理的指针设置为指向 null,这样它们就不会被尝试释放两次。

但是,实现有一个严重的问题:C标准说free(x)之后x的值变成了不确定。不确定意味着在您检查变量的任何情况下,该值都可以是任何值。因此,C 编译器假定指针与任何有效指针的指针不匹配并优化 "almost correct"

是合法的
void free_array(void *a[], int length) {
   int i, j;
   for (i = 0; i < length; i++) {
      if (a[i] != NULL) {
          free(a[i]);
          for (j = i + 1; j < length; j++) {
              if (a[j] == a[i]) {
                  a[j] = NULL;
              }
           }
     }
}

void free_array(void *a[], int length) {
    int i, j;
    for (i = 0; i < length; i++) {
        if (a[i] != NULL) {
            free(a[i]);
            for (j = i + 1; j < length; j++) {
                if (false) {
                }
            }
        }
    }
}

void free_array(void *a[], int length) {
    int i, j;
    for (i = 0; i < length; i++) {
        if (a[i] != NULL) {
            free(a[i]);
        }
    }
}

正确的解决方案必须在 调用 free:

之前进行指针比较
void free_array(void *a[], int length) {
    int i, j;
    for (i = 0; i < length; i++) {
        if (a[i] != NULL) {
            for (j = i + 1; j < length; j++) {
                if (a[j] == a[i]) {
                    a[j] = NULL;
                }
            }
            free(a[i]);
        }
    }
}