代码中的内存错误和可能的解决方案

时间:2014-04-02 06:56:17

标签: c memory-leaks valgrind

虽然代码正在编译并正确显示输出,但是当我运行" valgrind"时,它显示以下错误。我很难理解这一点,因为我没有valgrind的任何背景。

Invalid write of size 1
==14657==    at 0x4EAE10C: _IO_default_xsputn (genops.c:480)
==14657==    by 0x4E7CF81: vfprintf (vfprintf.c:1630)
==14657==    by 0x4EA3813: vsprintf (iovsprintf.c:43)
==14657==    by 0x4E85A06: sprintf (sprintf.c:34)
==14657==    by 0x400622: copy_id_name (assign2a.c:12)
==14657==    by 0x40065E: main (assign2a.c:21)
==14657==  Address 0x51f204b is 0 bytes after a block of size 11 alloc'd
==14657==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==14657==    by 0x400600: copy_id_name (assign2a.c:11)
==14657==    by 0x40065E: main (assign2a.c:21)
==14657== 

请解释实际错误以及删除此错误的解决方案。

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

/** Returns a pointer to allocated memory containing string in form "<id>=<name>" */
char *copy_id_name(const char *id, const char *name) {
    char *ptr = NULL;
    size_t len;
    // Compute required length
    len = strlen(id) + strlen(name);    // [sic]
    ptr = malloc(len-2);    // [sic]
    sprintf(ptr, "%s=%s", id, name);
    return ptr;
}


int main(int argc, char *argv[])
{
    char *ptr;

    if (argc > 2) {
    ptr = copy_id_name(argv[1], argv[2]);
    } else {
    ptr = copy_id_name("666", "badname");
    }
    printf("result: [%s]\n", ptr);
    return 0;
}

2 个答案:

答案 0 :(得分:3)

首先,您必须记住C中的字符串实际上比strlen报告的字符长一个字符。该额外字符用于特殊字符('\0'),告诉函数它是字符串的结尾。

这里的问题是你要分配两个字节 less 而不是idname字符串的总长度,然后你将这些字符串与两个添加了字符('='和终止'\0')。这意味着你将超出分配内存的末尾。

答案 1 :(得分:2)

 ptr = malloc(len-2);

您分配的所需内容少于4个字节。 strlen()给出字符串的长度,不计算null终止。但是,您需要为空终止分配空间。只需将-2更改为+2。