【发布时间】:2017-03-02 16:05:58
【问题描述】:
我一直在想,如果我将较长的字符串文字分配给较小大小的 char 数组会发生什么。 (我知道如果我使用字符串文字作为初始值设定项,我可能会省略大小并让编译器计算字符数,或者使用 strlen()+1 作为大小。)
我有以下代码:
#include <stdio.h>
int main() {
char a[3] = "abc"; // a[2] gives an error of initializer-string for array of chars is too long
printf("%s\n", a);
printf("%p\n", a);
}
我预计它会崩溃,但它实际上在没有警告的情况下编译并且可以打印出来。但是使用 valgrind,我收到以下错误消息。
==19195== Memcheck, a memory error detector
==19195== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==19195== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==19195== Command: ./a.out
==19195==
==19195== Conditional jump or move depends on uninitialised value(s)
==19195== at 0x4E88CC0: vfprintf (vfprintf.c:1632)
==19195== by 0x4E8F898: printf (printf.c:33)
==19195== by 0x4005CC: main (main.c:5)
==19195==
==19195== Conditional jump or move depends on uninitialised value(s)
==19195== at 0x4EB475D: _IO_file_overflow@@GLIBC_2.2.5 (fileops.c:850)
==19195== by 0x4EB56AF: _IO_default_xsputn (genops.c:455)
==19195== by 0x4EB32C6: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1352)
==19195== by 0x4E8850A: vfprintf (vfprintf.c:1632)
==19195== by 0x4E8F898: printf (printf.c:33)
==19195== by 0x4005CC: main (main.c:5)
==19195==
==19195== Conditional jump or move depends on uninitialised value(s)
==19195== at 0x4EB478A: _IO_file_overflow@@GLIBC_2.2.5 (fileops.c:858)
==19195== by 0x4EB56AF: _IO_default_xsputn (genops.c:455)
==19195== by 0x4EB32C6: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1352)
==19195== by 0x4E8850A: vfprintf (vfprintf.c:1632)
==19195== by 0x4E8F898: printf (printf.c:33)
==19195== by 0x4005CC: main (main.c:5)
==19195==
==19195== Conditional jump or move depends on uninitialised value(s)
==19195== at 0x4EB56B3: _IO_default_xsputn (genops.c:455)
==19195== by 0x4EB32C6: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1352)
==19195== by 0x4E8850A: vfprintf (vfprintf.c:1632)
==19195== by 0x4E8F898: printf (printf.c:33)
==19195== by 0x4005CC: main (main.c:5)
==19195==
==19195== Syscall param write(buf) points to uninitialised byte(s)
==19195== at 0x4F306E0: __write_nocancel (syscall-template.S:84)
==19195== by 0x4EB2BFE: _IO_file_write@@GLIBC_2.2.5 (fileops.c:1263)
==19195== by 0x4EB4408: new_do_write (fileops.c:518)
==19195== by 0x4EB4408: _IO_do_write@@GLIBC_2.2.5 (fileops.c:494)
==19195== by 0x4EB347C: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1331)
==19195== by 0x4E8792C: vfprintf (vfprintf.c:1663)
==19195== by 0x4E8F898: printf (printf.c:33)
==19195== by 0x4005CC: main (main.c:5)
==19195== Address 0x5203043 is 3 bytes inside a block of size 1,024 alloc'd
==19195== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==19195== by 0x4EA71D4: _IO_file_doallocate (filedoalloc.c:127)
==19195== by 0x4EB5593: _IO_doallocbuf (genops.c:398)
==19195== by 0x4EB48F7: _IO_file_overflow@@GLIBC_2.2.5 (fileops.c:820)
==19195== by 0x4EB328C: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1331)
==19195== by 0x4E8850A: vfprintf (vfprintf.c:1632)
==19195== by 0x4E8F898: printf (printf.c:33)
==19195== by 0x4005CC: main (main.c:5)
==19195==
abc?
0xfff0003f0
==19195==
==19195== HEAP SUMMARY:
==19195== in use at exit: 0 bytes in 0 blocks
==19195== total heap usage: 1 allocs, 1 frees, 1,024 bytes allocated
==19195==
==19195== All heap blocks were freed -- no leaks are possible
==19195==
==19195== For counts of detected and suppressed errors, rerun with: -v
==19195== Use --track-origins=yes to see where uninitialised values come from
==19195== ERROR SUMMARY: 10 errors from 5 contexts (suppressed: 0 from 0)
我认为未初始化的值/字节部分是有道理的,因为没有为终止字符“\0”分配内存,当我打印出来时,最后一个字符是垃圾值。
但最后一条错误消息对我来说似乎很陌生。
地址 0x5203043 在大小为 1,024 的块中分配了 3 个字节
我知道缓冲区大小被定义为 1024。我不确定是否出现此错误是因为内存使用效率低下。
另外我想知道堆分配和释放从哪里来?那是来自字符串文字吗?
感谢您的帮助!!
(这个问题的前一个主题可能措辞混乱。我改变了它。)
【问题讨论】:
-
堆分配可能在
printf()内部。 -
@rsp 我想他明白为什么这不是初始化文字的正确方法。他特意要求对 valgrind 的警告做出解释。
-
I expect it to crashUB doesn't mean crash blog.llvm.org/2011/05/what-every-c-programmer-should-know.html -
@Barmar “不是初始化文字的正确方法。”不清楚。字符串文字
"abc"不需要初始化,char a[3] = "abc";符合 C。
标签: c arrays memory valgrind string-literals