因malloc而导致出界和内存泄漏

时间:2016-07-12 15:37:01

标签: c memory-management memory-leaks malloc strtok

我正在尝试对字符串进行标记。

存在于输入数组(char **)

中的行不同

使用以下函数存储生成到不同数组中的不同标记。

int  tokenize_string(int max_lines,char *input_lines[max_lines],char **tokens)
{
    char *token;
    int index,token_index=0;

    for(index = 0; index < max_lines;++index)
    {
        token = strtok(input_lines[index]," ");

        while(token != NULL)
        {
            tokens[token_index] = malloc(sizeof(char*));
            tokens[token_index] = token;
            token = strtok(NULL," ");
            token_index++;
        }
    }
    return token_index;
}

使用valgrind时会显示以下内容

==25710== Invalid write of size 8
==25710==    at 0x400AA6: tokenize_string (functions.c:28)
==25710==    by 0x400953: main (main.c:29)
==25710==  Address 0x51c3048 is 0 bytes after a block of size 8 alloc'd
==25710==    at 0x4C27A2E: malloc (vg_replace_malloc.c:270)
==25710==    by 0x40091B: main (main.c:25)
==25710==
==25710== Invalid write of size 8
==25710==    at 0x400ABA: tokenize_string (functions.c:29)
==25710==    by 0x400953: main (main.c:29)
==25710==  Address 0x51c3048 is 0 bytes after a block of size 8 alloc'd
==25710==    at 0x4C27A2E: malloc (vg_replace_malloc.c:270)
==25710==    by 0x40091B: main (main.c:25)

我知道问题出在mallocfor循环上。

//编辑

int main(int argc,char *argv[])
{
    int max_lines = atoi(argv[1]);
    char *input_lines[max_lines];
    char **tokens;
    char *output_string;
    int token_index;
    tokens=malloc(sizeof(char*));

    get_input(max_lines,input_lines);
    token_index = tokenize_string(max_lines,input_lines,tokens);
    output_string= concat_string(tokens,output_string,token_index);
    print_string(output_string);
}

void get_input(int max_lines,char *input_lines[max_lines])
{
   int index;
   printf("Enter %d lines",max_lines);

   for(index = 0; index < max_lines;++index)
   {
       input_lines[index] = malloc(sizeof(char*));
       fgets(input_lines[index],50,stdin);
   }
}

有什么建议吗?

谢谢

2 个答案:

答案 0 :(得分:2)

让我们仔细看看这两行:

tokens[token_index] = malloc(sizeof(char*));
tokens[token_index] = token;

在第一个中为指针分配空间并将其分配给tokens[token_index]。下一行 重新分配 tokens[token_index]指向不同的地方,丢失malloc返回的指针。与拥有int变量(让我们将其命名为i)没有区别,正在做

i = 5;
i = 10;

然后想知道为什么i不是5

如果调用函数中tokens的生命周期小于(或等于)input_lines的生命周期,那么您不需要在此处分配内存,来自{{{ 1}}(第二行)就足够了。

还有其他问题,例如你没有在任何地方增加token

至于&#34;无效写&#34;如果没有合适的Minimal, Complete, and Verifiable Example来说明如何调用此函数,很难说出来。

答案 1 :(得分:1)

malloc()中,您为指针本身分配空间,然后将值指定为指向该指针。下一行,你覆盖它。

假设您需要在此函数的生命周期后使用标记作为标记数组,您需要的是以下内容。您为tokens数组中的标记包含的字符串创建空间,然后将其复制。

int tokenize_string(int max_lines,char *input_lines[max_lines],char **tokens)
{
    char *token;
    int index,token_index=0;

    for(index = 0; index < max_lines;++index)
    {
        token = strtok(input_lines[index]," ");

        while(token != NULL)
        {
            size_t len = strlen(token) + 1;
            tokens[token_index] = malloc(len);
            strcpy(tokens[token_index], token);
            token = strtok(NULL," ");
        }
    }
    return token_index;
}

另请注意,除非您在循环中的某处更改它,否则此函数将覆盖相同的token_index。您还必须确保tokens[]能够适合您需要创建的字符串的所有指针。

修改

好的,我会从一开始就开始工作,但是

tokens=malloc(sizeof(char*));

没有创建一个指向字符串的指针数组,因为我相信你期待的。这只是说tokens指向一个内存区域,有足够的空间用于指向char的单个指针。您需要预先指定的最大字符串数,或者找到提前知道的方法。

get_input()中,您正在做类似的事情 - 您使用

input_lines[index] = malloc(sizeof(char*));

尝试为新字符串创建空间,但这只是指向指向char的指针。根据您的fgets()电话和50个字符的限制,您只需执行

即可
input_lines[index] = malloc(50);

这样你就可以拥有50个字符的空间。之后,您需要确保它是一个以空字符结尾的字符串。

最重要的一点是malloc(sizeof(char *)) NOT 为字符串分配空间,只为指针分配空间。这些不一样,我建议再多阅读一下here

基本上,你似乎是在你正在分配的记忆范围之外写作。