【问题标题】:freeing memory after you have incremented the pointer增加指针后释放内存
【发布时间】:2013-06-30 16:59:35
【问题描述】:
gcc (GCC) 4.7.2
c89

你好,

All error checking removed from snippet - to keep the code short.

我在释放一些已分配并将字符串复制到的内存时遇到问题。

我的程序将检查数字并增加指针直到它到达非数字。

当我去释放内存时,我得到了一个无效空闲的堆栈转储。

我认为这是因为我增加了指针,现在它指向字符串的中间,因为那是非数字开始的时候。 如果我不增加它可以免费。但是,如果我增加它然后尝试释放,我会得到堆栈转储。

int parse_input(const char *input)
{
    char *cpy_input = calloc(strlen(input) + 1, sizeof(char));
    size_t i = 0;

    apr_cpystrn(cpy_input, input, strlen(input) + 1);



    /* Are we looking for a range of channels */
    for(i = 0; i < strlen(cpy_input); i++) {
        if(isdigit(*cpy_input)) {
        /* Do something here */
            cpy_input++;
        }
    }

    /* Where finished free the memory */
    free(cpy_input); /* Crash here */

    return 0;
}

我通过声明另一个指针并分配地址解决了这个问题,所以它指向第一个字符,然后我释放它。它工作正常,即

  char *mem_input = cpy_input;
  free(mem_input);

我的问题是为什么我需要声明另一个指针才能释放内存?还有其他方法吗?

非常感谢,

【问题讨论】:

  • 你可以使用另一个变量来处理分配的内存,其中将cpy_input声明为char * const cpy_input,重要的是你是free(same_address);,你是从malloc()的调用中得到的
  • 您只能向free() 提供以前由malloc()calloc()realloc() 返回的指针。将指针返回到分配的空间是不够的;它必须与返回的值完全相同。

标签: c free


【解决方案1】:

你可以改变你的循环

for(i = 0; i < strlen(cpy_input); i++) {
    if(isdigit(cpy_input[i])) {
    /* Do something here */

    }

}

或者稍后做指针算术得到初始值

【讨论】:

    【解决方案2】:

    好吧,当然还有另一种方法:只需将cpy_input 指针减少多少次就等于增加它的次数。或者从最终的cpy_input 值中减去字符串的长度(假设您保存了它)。这样您将恢复原始的cpy_input 值并正确释放内存。

    这里的底线很简单:您必须将您从calloc 收到的指针值传递给free。没有办法解决它。因此,以一种或另一种方式,您必须能够获得原始指针值。将其保存在另一个指针中实际上是您情况下的最佳解决方案。但是,如果您知道如何以任何其他方式做到这一点 - 请继续使用您最喜欢的任何方式。

    【讨论】:

      【解决方案3】:

      您需要保存原始指针。释放内存时只能使用原始指针。您可以创建另一个变量来保存原始指针。

      或者将循环放在一个单独的函数中。由于默认情况下变量是按值传递的,即复制,所以当您在函数中更改指针时,您只会更改指针的副本。

      除此之外,您的循环似乎有点奇怪。您使用从零到字符串长度的索引进行循环,因此您可以轻松地使用该索引而不是修改指针。要么这样,要么将循环更改为while (*cpy_input != '\0') 之类的东西。我从未见过这两种变体混合在一起。

      顺便说一句,您的代码中有一个错误。如果当前字符是数字,则仅增加指针。但是如果第一个字符 not 是数字,则循环将一直循环直到到达字符串的末尾,但指针将 not 增加,您将检查第一个字符一遍又一遍。如果您只想从字符串中获取前导数字(如果有),则可以使用循环,例如

      for (; isdigit(*cpy_input); cpy_input++)
      {
          /* do something, using `*cpy_input` */
      }
      

      当然可以

      for (int i = 0; i < strlen(cpy_input); i++)
      {
          /* do something, using `cpy_input[i]` */
      }
      

      【讨论】:

      • 我认为将cpy_input 声明为const 应该是一个好习惯。
      【解决方案4】:

      calloc 返回指向从内存请求的内存块的指针。因此,您只能释放从 calloc 返回的相同指针位置。

      要么释放原始指针,要么释放它的备份副本。

      【讨论】:

        【解决方案5】:
        char *cpy_input = calloc(strlen(input) + 1, sizeof(char));
        

        假设cpu_input0x1000。点是相同的指针应该在free() 中被释放。

        根据您的逻辑,如果输入长度为 5,则在 for 循环之后 cpy_input 指向 0x1005 位置。如果你调用free(cpy_input),它是free(0x1005),它是免费的无效指针,它会崩溃。

        【讨论】:

        • 实际上是未定义的行为
        【解决方案6】:

        重要的是要理解,指针只是一个内存地址。

        freecalloc 背后的资源管理系统将保留一些与内存块相关的簿记数据,特别是您通过调用calloc 请求的块有多大。这可能在某个查找容器中,它存储了与calloc 返回的指针相关的信息(即cpu_input 的初始值),或者此信息存储在内存中,就在块的前面,最远我知道比较常见。

        如果您现在将 cpu_input 中的更改值传递给 free,它要么在其查找容器中找不到簿记数据,要么将在指针前面查找簿记数据,它会在其中找到你字符串的数据,这可能根本没有意义。

        因此,您保留原始指针副本的解决方案是合适的。

        【讨论】:

          猜你喜欢
          • 2014-03-28
          • 1970-01-01
          • 2020-06-23
          • 1970-01-01
          • 2017-03-01
          • 2014-02-15
          • 2016-03-06
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多