在函数中释放C **指针malloc时出错

时间:2014-02-07 14:00:09

标签: c pointers malloc free

程序运行正常,除了最后一次免费,这导致程序冻结。 当我注释掉最后一个'免费'时它运行良好。

程序从字符串中获取所有子字符串并返回它。

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

char** getPrefixes(char* invoer);

int main()
{
    char buffer[100];
    char *input;
    char **prefixes;
    int counter = 0;

    puts("Give string.");
    fgets(buffer, 99, stdin);
    fflush(stdin);

    if (buffer[strlen(buffer) - 1] == '\n')
        buffer[strlen(buffer) - 1] = '\0';

    input= (char*)malloc(strlen(buffer) + 1);

    if (input == NULL)
    {
        puts("Error allocating memory.");
        return;
    }

    strcpy(input, buffer);

    prefixes = (char**) getPrefixes(input);

    for (counter = strlen(input); counter > 0;  counter--)
    {
        puts(prefixes[counter]);
        free(prefixes[counter]);
    }

    free(input);

    free(prefixes);
}

char** getPrefixes(char* input)
{
    char** prefixes;
    int counter;

    prefixes = malloc(strlen(input) * sizeof(char*));

    if (prefixes == NULL)
    {
        puts("ELM.");
        return NULL;
    }


    for (counter= strlen(input); counter> 0; counter--)
    {
        prefixes[counter] = (char*)malloc(counter + 1);
        strcpy(prefixes[counter], input);
        input++;
    }

    return prefixes;
}

提前致谢!

3 个答案:

答案 0 :(得分:1)

为指针分配内存:

char** cArray = (char**)malloc(N*sizeof(char*));

for(i=0;i<N;i++)
    cArray[i] = (char*)malloc(M*sizeof(char));

取消分配内存 - 按相反顺序:

for(i=0;i<N;i++)
    free(cArray[i]);
free(cArray)

我希望这会让你对错误有所了解。

答案 1 :(得分:1)

您正在使用前缀[counter]作为目标调用strcpy。但是,你只为每个前缀[counter]分配了4/8个字节,具体取决于(char *)的大小

当你调用strcpy时,你将所有输入复制到需要strlen(输入)的结尾!空间

执行此操作会破坏堆,这可能解释了程序冻结的原因。

答案 2 :(得分:1)

程序冻结的原因很简单:未定义的行为+无效的返回值:_Y main函数返回void,而不是int:尽快添加return 0!如果在执行编译后的二进制文件后在控制台中键入echo $?,则应该看到0以外的数字。这是程序的退出代码。除0之外的任何东西都意味着麻如果main没有返回int,那就是坏消息。

下一步:
未定义的行为发生在几个地方,例如就在这里:

prefixes = malloc(strlen(input) * sizeof(char*));
//allocate strlen(input) pointers, if input is 10 long => valid indexes == 0-9
for (counter= strlen(input); counter> 0; teller--)
{//teller doesn't exist, so I assume you meant "counter--"
    prefixes[teller] = (char*)malloc(counter + 1);//first call prefixes[10] ==> out of bounds
    strcpy(prefixes[counter], input);//risky, no zero-termination... use calloc + strncpy
    input++;
}

然后,在释放内存时,你不会释放指针@ offset 0,因此free(prefixes)调用无效:

for (counter = strlen(input); counter > 0;  counter--)
{//again 10 --> valid offsets are 9 -> 0
    puts(prefixes[counter]);
    free(prefixes[counter]);
}
free(prefixes);//wrong

同样,有效索引为0及以上,循环中的条件(counter > 0)意味着只要counter为0,循环就会中断。您在任何时候都不会释放第一个指针数组,索引/ offstet 0的数据。

像所有人一样编写你的循环:

for (int i=0, size_t len = strlen(input); i<len; ++i)
{
    printf("%d\n", i);//prints 0-9... 10 lines, all valid indexes
}

更改你的循环,并确保你只使用有效的抵消,你应该好好去。使用strncpy,您仍然可以获得与之前相同的结果:

for (int i=0;i<len;++i)
{
    //or malloc(i+2), char is guaranteed to be 1
    //I tend to use `calloc` to set all chars to 0 already, and ensure zero-termination
    prefixes[i] = malloc((i+2)*sizeof(*prefixes[i]));
    strncpy(prefixes[i], input, i+1);//max 1 - 10 chars are copied
}

如果我们将此应用于您的代码,并重新编写它:

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

char** getPrefixes(char* input);

int main( void )
{
    char *input;
    char **prefixes;
    int counter, i;

    input= calloc(50,1);
    if (input == NULL)
    {
        puts("Error allocating memory.");
        return;
    }
    strcpy(input, "teststring");

    prefixes = getPrefixes(input);
    counter = strlen(input);
    for (i=0; i<counter;++i)
    {
        puts(prefixes[i]);
        free(prefixes[i]);
    }

    free(input);
    free(prefixes);
    return 0;
}

char** getPrefixes(char* input)
{
    int i, counter = strlen(input);
    char** prefixes = malloc(counter * sizeof *prefixes);

    if (prefixes == NULL)
    {
        puts("ELM.");
        return NULL;
    }

    for (i=0; i<counter; ++i)
    {
        prefixes[i] = calloc(i + 2,sizeof *prefixes[i]);
        strncpy(prefixes[i], input, i+1);
    }
    return prefixes;
}

我们获得的输出是:

t
te
tes
test
tests
testst
teststr
teststri
teststrin
teststring

正如你自己看到的那样

on this codepad