0
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);

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

提前谢谢了,

4

6 回答 6

4

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

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

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

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

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]` */
}
于 2013-07-03T05:53:42.747 回答
3
char *cpy_input = calloc(strlen(input) + 1, sizeof(char));

比方说cpu_input0x1000点是相同的指针应该被释放free()

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

于 2013-07-03T05:57:09.933 回答
1

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

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

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

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

于 2013-07-03T06:30:12.167 回答
1

你可以改变你的循环

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

    }

}

或者做Pointer Arithmetic稍后得到初始值

于 2013-07-03T05:53:21.183 回答
1

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

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

于 2013-07-03T05:53:30.920 回答
1

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

释放原始指针或释放它的备份副本。

于 2013-07-03T05:56:30.573 回答