【问题标题】:C program crashes after freeing the pointers in an array of char *C 程序在释放 char * 数组中的指针后崩溃
【发布时间】:2021-02-11 01:53:07
【问题描述】:

我是一名学习 C 的学生,我正在使用字符串数组和 malloc()。

我有以下代码,它应该使用动态创建的字符串加载字符串数组(静态创建)(如果我的术语与我拥有的代码不一致,请原谅/纠正我)。

问题是,一旦我去释放该内存,我会收到以下错误:free(): invalid pointer

代码如下:

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

#define RAM_SIZE 5

char* ram [RAM_SIZE];
int next_free_cell = 0;

void freeAndNullRam(){
    for (int i = 0 ; i < RAM_SIZE ; i++){
      printf("%d\n", i);
        free(ram[i]);
        ram[i] = NULL;
    }
}

int main(int argc, const char *argv[])
{
  for (int i= 0; i < RAM_SIZE; i++){
    ram[i] = (char*)malloc(sizeof(char*)*5);
    ram[i] = "aaaa";
  } 
  for (int i= 0; i < RAM_SIZE; i++){
    int empty = (ram[i] ==NULL);
    if(!empty){
      printf("%s\n", ram[i]);
    }
      
  }
  freeAndNullRam();
  for (int i= 0; i < RAM_SIZE; i++){
    int empty = (ram[i] ==NULL);
    printf("%d\n", empty);
  } 
  return 0;
}

我知道问题肯定出在freeAndNullRam() 函数中(显然),但我不明白为什么。我的理解是,在编译时,会创建一个包含 5 个指向 char 数组的指针的数组,但要真正填充数组的单元格,我需要 malloc 他们一些内存。为什么当我释放数组中的指针时程序会报错,而当我给它们内存时却没有?

谢谢!

【问题讨论】:

  • 你不需要NULL。只需free()。一旦你free() 某物它已经死了,就像一个幽灵,你永远不应该碰它。释放后使用的错误很严重。
  • 提示:如果有,请使用strdup()
  • @tadman 我知道我不需要NULL,严格来说,但这是我正在处理的一个更大项目的一个组件,数组中的空条目用于某些事情.
  • 提示:用有意义的名称命名变量,而不是像 ram 这样的随机垃圾,它是如此模糊以至于毫无意义。更好的选择是 namesentries
  • @tadman 再次感谢您的帮助,我想我应该删除用于其他用途的代码部分。这是一个类,我们应该在其中模拟一个需要“ram”数据结构的操作系统。因此得名。

标签: arrays c pointers


【解决方案1】:

ram[i] = "aaaa"; 重新分配a[i] 处的指针以指向静态内存,丢弃malloc 的结果。稍后您将这些指针传递给 free,但由于它们不是 *alloc 函数的结果而失败。

使用strcpy 将字符串从静态内存复制到您分配的目的地。

strcpy(a[i], "aaaa")

【讨论】:

    【解决方案2】:

    这是您的代码的修改版本,使其更符合 C 语言习惯:

    #include <stdio.h>
    #include <stdlib.h>
    
    // Create an array of arbitrary size
    char* alloc_array(size_t size) {
      // calloc() will give you a pre-zeroed (NULL) allocation, malloc() may not
      return calloc(size, sizeof(char*));
    }
    
    // Clears out all entries in the array, leaving only NULL
    void clear_array(char* array, size_t size) {
      for (size_t i = 0; i < size; ++i) {
        // free(NULL) doesn't do anything, and is easier than a test
        free(array[i]);
        array[i] = NULL;
      }
    }
    
    // Clears, then frees the array
    void free_array(char* array, size_t size) {
      clear_array(array, size);
      free(array);
    }
    
    int main(int argc, const char *argv[])
    {
      // Whenever possible use local variables, not global variables
      size_t size = 5;
      char* entries = alloc_array(size);
    
      for (size_t i = 0; i < size; ++i) {
        // Make a copy with strdup() so this can be released with free()
        // later on. A string like "..." is static, it was never allocated.
        entries[i] = strdup("aaaa");
      } 
    
      for (size_t i = 0; i < size; i++) {
        // Express conditions in the if statment directly
        if (entries[i] != NULL) {
          printf("%s\n", ram[i]);
        }
      }
      
      clear_array(entries);
    
      for (size_t i = 0; i < size; i++) {
        printf("%d\n", entries[i] != NULL);
      }
    
      // Don't forget to release any allocated memory.
      free_array(entries);
    
      return 0;
    }
    

    您的原始代码中有很多不良习惯,您应该尽快消除这些不良习惯,以免这些东西扎根。尤其是全局变量是一个需要避免的大问题。

    要记住的一件事是,除非某些东西被明确分配给malloc() 或类似calloc() 的变体,或者被赋予你的代码以理解它是以这种方式分配的,否则你不应该调用free()就可以了。

    不是每个指针都是动态分配的,也不是每个动态分配的指针都是用malloc() 分配的。因此,一些 C 代码可能会非常混乱。

    【讨论】:

    • 非常感谢您的建议和代码修改。我会把建议放在心上!我当然觉得有必要改掉坏习惯。
    【解决方案3】:

    C 的语法强烈建议"aaaa" 是一个“字符串”。人们甚至这样谈论这种语法:他们称之为“字符串”。但"aaaa" 并非如此。它是不幸命名的字符串文字,它 not 是一个字符串 - 无论是在 C 中还是在 C++ 中。 char * 也不是字符串——它是一个指针类型的值。它用于表示字符串,但它本身不是字符串 - 甚至不接近。

    相当合理地预期"aaaa" 的行为可能与“明显”类型的任何其他右值一样。唉,虽然1int 类型的整数文字,"aaaa" 是指针类型const char * 的字符串文字 - 它的值不是字符串,而是指针!

    就好像当你写42时,C给你一个const int *指向42。这就是“字符串”文字的作用。这就是 C 语言非常可悲的一面 :(

    在 C++ 中,实际上有一个字符串类型 (std::string),您甚至可以使用 C++11 中引入的新语法编写该类型的文字:"aaaa"sstd::string 类型的右值* ,并且您可以完全按照您对任何其他值类型(如int)的期望分配它们。

    由于您已经在思考 C++ 的一些内容,也许您可​​以接下来研究该语言。与 C 相比,在 C++ 中完成大量基本操作所需的工作量要少得多。

    *技术上的右值引用

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-17
      • 2022-11-19
      • 1970-01-01
      • 2012-03-12
      相关资源
      最近更新 更多