我不理解为什么我会收到这个valgrind错误。

3
我收到了下面的代码:
/* main.c */

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

int main (){
  int i;
  char *msg = "This is a simple and small message";
  int len = strlen (msg);
  char *new_msg = (char *) malloc (len);
  for (i = 0; i < len; i++)
    new_msg[i] = 'A';
  printf ("%s\n", new_msg);
  free (new_msg);
  return 0;
}

我编译了它,然后使用以下命令在valgrind中运行它:

valgrind --leak-check=full --show-reachable=yes ./main

我收到了以下输出:
==8286== Memcheck, a memory error detector
==8286== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==8286== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==8286== Command: ./main
==8286== 
==8286== Invalid read of size 1
==8286==    at 0x4C2C1B4: strlen (vg_replace_strmem.c:412)
==8286==    by 0x4EA09FB: puts (ioputs.c:36)
==8286==    by 0x400636: main (main.c:12)
==8286==  Address 0x51de062 is 0 bytes after a block of size 34 alloc'd
==8286==    at 0x4C28C20: malloc (vg_replace_malloc.c:296)
==8286==    by 0x400601: main (main.c:9)
==8286== 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
==8286== 
==8286== HEAP SUMMARY:
==8286==     in use at exit: 0 bytes in 0 blocks
==8286==   total heap usage: 1 allocs, 1 frees, 34 bytes allocated
==8286== 
==8286== All heap blocks were freed -- no leaks are possible
==8286== 
==8286== For counts of detected and suppressed errors, rerun with: -v
==8286== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

我看到所有分配的内存都已被释放,但仍然出现一个我不理解的错误。

感谢您的帮助。

3个回答

10

这是一个非常明显的错误:由于缺少空终止符,new_msg 的读取是无效的。

你已经分配了与原始字符串长度相等的char数目,因此当前没有空间容纳 '\0' ,这会导致未定义行为。请按照以下方法更改代码以解决问题:

char *new_msg = malloc (len+1);
for (i = 0; i < len; i++)
    new_msg[i] = 'A';
new_msg[len] = '\0';

首先,感谢您的解释。现在它可以工作了。其次,我看到您删除了malloc的转换。为什么这样做?我使用和不使用转换运行它,仍然得到相同的输出(即使在valgrind上)。有什么区别吗? - mik mik
@mikmik 这里有一个关于转换malloc结果的好问题和答案。不进行转换的想法是你已经指定了类型,所以你在重复相同的代码。转换也可能会隐藏一些微妙的错误。 - Sergey Kalinichenko

1

你的代码需要做出一些更改。

1) len 应该是 size_t 类型,而不是 int 类型,因为 strlen() 返回的是 size_t 类型。

2) (char *) malloc (len); 不需要强制转换。虽然这不是一个错误,但有理由不进行强制转换。

3) new_msg 没有以 \0 结尾。这就是发生错误的原因。


1
数字1和2不是此问题的原因。提及它们没有关系,但请清晰地进行区分。 - user694733
@Haris 强制类型转换不是错误,而是非常有用的信息,一方面可以防止不正确的赋值,另一方面可以实现数据类型的转换。 - Vlad from Moscow

0
你使用 strlen() 来获取长度,但不包含 '\0'。
因此当你 malloc 一个新数组时,应该使用 len + 1,并设置 new_msg[len]'\0'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接