动态内存分配、字符串指针和Valgrind

5

我的程序像这样(main.c):

#include <stdlib.h>
#include <stdio.h>
void main(){
  char *first="hello ";
  char *second="world!";
  char *seq=(char *)malloc((strlen(first)+1)*sizeof(char));
  strcat(strcpy(seq,first),second);
  printf("%s\n",seq);
  free(seq);
}

我使用valgrind工具进行调试,它提示($:valgrind --tool=memcheck --leak-check=full --track-origins=yes ./main):

==5118== Memcheck, a memory error detector.
==5118== Copyright (C) 2002-2008, and GNU GPL'd, by Julian Seward et al.
==5118== Using LibVEX rev 1884, a library for dynamic binary translation.
==5118== Copyright (C) 2004-2008, and GNU GPL'd, by OpenWorks LLP.
==5118== Using valgrind-3.4.1, a dynamic binary instrumentation framework.
==5118== Copyright (C) 2000-2008, and GNU GPL'd, by Julian Seward et al.
==5118== For more details, rerun with: -v
==5118== 
==5118== Invalid write of size 1
==5118==    at 0x402575B: strcat (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==5118==    by 0x80484EB: main (main.c:7)
==5118==  Address 0x418a02f is 0 bytes after a block of size 7 alloc'd
==5118==    at 0x402522D: malloc (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==5118==    by 0x80484C3: main (main.c:6)
==5118== 
==5118== Invalid write of size 1
==5118==    at 0x4025777: strcat (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==5118==    by 0x80484EB: main (main.c:7)
==5118==  Address 0x418a034 is 5 bytes after a block of size 7 alloc'd
==5118==    at 0x402522D: malloc (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==5118==    by 0x80484C3: main (main.c:6)
==5118== 
==5118== Invalid read of size 1
==5118==    at 0x4025963: strlen (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==5118==    by 0x40A0FA4: puts (in /lib/libc-2.10.1.so)
==5118==    by 0x80484F7: main (main.c:8)
==5118==  Address 0x418a02f is 0 bytes after a block of size 7 alloc'd
==5118==    at 0x402522D: malloc (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==5118==    by 0x80484C3: main (main.c:6)
==5118== 
==5118== Invalid read of size 1
==5118==    at 0x40ACEFE: _IO_default_xsputn (in /lib/libc-2.10.1.so)
==5118==    by 0x40AA3D0: _IO_file_xsputn@@GLIBC_2.1 (in /lib/libc-2.10.1.so)
==5118==    by 0x40A1020: puts (in /lib/libc-2.10.1.so)
==5118==    by 0x80484F7: main (main.c:8)
==5118==  Address 0x418a02f is 0 bytes after a block of size 7 alloc'd
==5118==    at 0x402522D: malloc (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==5118==    by 0x80484C3: main (main.c:6)
hello world!
==5118== 
==5118== ERROR SUMMARY: 17 errors from 4 contexts (suppressed: 13 from 1)
==5118== malloc/free: in use at exit: 7 bytes in 1 blocks.
==5118== malloc/free: 1 allocs, 0 frees, 7 bytes allocated.
==5118== For counts of detected errors, rerun with: -v
==5118== searching for pointers to 1 not-freed blocks.
==5118== checked 47,492 bytes.
==5118== 
==5118== 
==5118== 7 bytes in 1 blocks are definitely lost in loss record 1 of 1
==5118==    at 0x402522D: malloc (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==5118==    by 0x80484C3: main (main.c:6)
==5118== 
==5118== LEAK SUMMARY:
==5118==    definitely lost: 7 bytes in 1 blocks.
==5118==      possibly lost: 0 bytes in 0 blocks.
==5118==    still reachable: 0 bytes in 0 blocks.
==5118==         suppressed: 0 bytes in 0 blocks.

谁能告诉我为什么出现这个问题以及如何修复它。
5个回答

17
 char *seq=(char *)malloc((strlen(first)+1)*sizeof(char));

您正在为一个大小为'first'的字符串分配内存。

  strcat(strcpy(seq,first),second);

如果你试图将第一个字符串和第二个字符串都拼接到同一个字符串中,那是行不通的。strcat无法创建更多内存,你需要在malloc中包含它。

在纯C中,没有必要对malloc的结果进行类型转换。

同时,也不必使用sizeof(char),因为它保证为1。有些人喜欢将其放在那里以明确类型(以防类型更改),而有些人则认为这是无用的冗余。


1
在C语言中,不需要对malloc()的返回值进行强制类型转换;此外,sizeof(char)始终为1 - Christoph

3

对应于 malloc()free() 在哪里呢?


哈哈,我弄丢了它,我只是想演示strcpy和strcat的错误。当然,我应该添加free(seq); 非常感谢你们。 - Charlie Epps
main() 函数返回后,内存会被操作系统隐式释放。 - Christoph
1
哇 - 我为什么还要打电话给 free() 呢? :-) - Justicle
1
在执行过程中的中间点调用free()是值得的,因为应用程序可能需要在将来分配更多的内存。但不要在main()函数的结尾处调用。 - caf
仅为了从valgrind获得干净的输出,这是值得的。您不会在代码中留下编译器警告,对吧? - Justicle
4
像valgrind这样的工具希望你释放所有的内存,否则它们会将其报告为泄漏。不过这也是一个好习惯;总有一天你会重构你的代码并忘记释放那些内存。 - Chris Arguin

2
您只为序列中的第一个元素分配了足够的空间。

1

seq的长度只有(strlen(first)+1)*sizeof(char),不足以容纳连接后的字符串first + second。


-1

我看到这行代码:

strcat(strcpy(seq,first),second);

并没有错误。原因是你在进行字符串拼接时,没有给出正确的源。如果将上述语法分成两行,它将正常工作。

strcpy(seq,first); strcat(seq,second);

这是因为当你进行字符串复制时,它会从“first”复制字符串到“seq”。现在,对于字符串拼接,由于它找不到正确的源[请记住,你没有明确指定源是“seq”],它会导致无效的写入内存泄漏问题。

希望这解答了你的问题。如果需要进一步的信息,请回复。


同样地,就如其他人所提到的一样,你需要为seq分配适当的内存来存储"second"。 - Roopesh Majeti
strcpy() 返回它的第一个参数,因此 strcat(strcpy(seq, first), second) 等同于 strcpy(seq, first); strcat(seq, second); - Adam Rosenfield

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