问题描述
首先,我知道有人问过类似的问题.但是,我想对真正原始的C数据类型有一个更一般的简单问题.所以就在这里.
在 main.c
中,我调用一个函数来填充这些字符串:
intmain(int argc,char * argv []){char * host = NULL;char *数据库;字符* collection_name;char * filename =";char * fields = NULL;char * query = NULL;...get_options(argc,argv,& host,&数据库,& collection_name,&文件名,& fields,& query,& aggregation);
内部 get_options
:
if (*filename == NULL ) {* filename =(char *)realloc(* filename,strlen(* collection_name)* sizeof(char)+4);strcpy(*文件名,*集合名);strcat(* filename,".tde");#行69}
我的程序运行正常,但随后Valgrind告诉我我做错了:
== 8608 == Memcheck,内存错误检测器== 8608 ==朱利安·塞沃德(Julian Seward)等人的版权(C)2002-2011和GNU GPL.== 8608 ==使用Valgrind-3.7.0和LibVEX;使用-h重新运行以获取版权信息== 8608 ==命令:./coll2tde -h localhost -d test -c test== 8608 ==== 8608 ==大小为1的无效写入==8608== 在 0x403BE2:get_options (coll2tde.c:69)== 8608 ==通过0x402213:main(coll2tde.c:92)== 8608 ==地址0xa2edd18是分配了大小为8的块后的0字节== 8608 ==在0x4C28BED:malloc(在/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)==8608== 由 0x4C28D6F:realloc(在/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so 中)== 8608 ==通过0x403BBC:get_options(coll2tde.c:67)== 8608 ==通过0x402213:main(coll2tde.c:92)
您能解释一下错误吗?地址0xa2edd18是一个大小为8的块分配后的0个字节
?我该如何解决这个问题?
strcpy
添加空终止符 '\0'
.您忘记为其分配空间了:
*filename = (char*)realloc(*filename, strlen(*collection_name)*sizeof(char)+5);
您需要添加5个字符的空间:后缀为.tde"
的4个字符,以及'\ 0'
终止符的另一个字符.您当前的代码仅分配4,因此最后一次写入是在您为新文件名分配的块之后(即紧随其后的0字节)立即在该空间中完成.
注意::您的代码有一个常见问题-将 realloc
的结果直接分配给要重新分配的指针.这在 realloc
成功时很好,但在失败时会造成内存泄漏.要解决此错误,需要将 realloc
的结果存储在单独的变量中,并在将值分配回 * filename
: NULL ./p>
char * tmp =(char *)realloc(*文件名,strlen(* collection_name)* sizeof(char)+5);如果(tmp!= NULL){*文件名= tmp;} 别的 {//对失败的分配进行处理}
直接分配给 * filename
会导致内存泄漏,因为 * filename
指向下方的指针在发生故障时将被覆盖,变得不可恢复./p>
First, I know similar questions have been asked. However, I'd like to have a more general simple question with really primitive C data types. So here it is.
In main.c
I call a function to populate those string:
int
main (int argc, char *argv[]){
char *host = NULL ;
char *database ;
char *collection_name;
char *filename = "";
char *fields = NULL;
char *query = NULL;
...
get_options(argc, argv, &host, &database, &collection_name, &filename,
&fields, &query, &aggregation);
Inside get_options
:
if (*filename == NULL ) {
*filename = (char*)realloc(*filename, strlen(*collection_name)*sizeof(char)+4);
strcpy(*filename, *collection_name);
strcat(*filename, ".tde"); # line 69
}
My program works fine, but then Valgrind tells me I'm doing it wrong:
==8608== Memcheck, a memory error detector
==8608== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==8608== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==8608== Command: ./coll2tde -h localhost -d test -c test
==8608==
==8608== Invalid write of size 1
==8608== at 0x403BE2: get_options (coll2tde.c:69)
==8608== by 0x402213: main (coll2tde.c:92)
==8608== Address 0xa2edd18 is 0 bytes after a block of size 8 alloc'd
==8608== at 0x4C28BED: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8608== by 0x4C28D6F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8608== by 0x403BBC: get_options (coll2tde.c:67)
==8608== by 0x402213: main (coll2tde.c:92)
Can you explain the error Address 0xa2edd18 is 0 bytes after a block of size 8 alloc'd
?How can I solve this issue?
strcpy
adds a null terminator character '\0'
. You forgot to allocate space for it:
*filename = (char*)realloc(*filename, strlen(*collection_name)*sizeof(char)+5);
You need to add space for 5 characters: 4 for ".tde"
suffix, and one more for the '\0'
terminator. Your current code allocates only 4, so the last write is done into the space immediately after the block that you have allocated for the new filename (i.e. 0 bytes after it).
Note: Your code has a common problem - it assigns the results of realloc
directly to a pointer being reallocated. This is fine when realloc
is successful, but creates a memory leak when it fails. Fixing this error requires storing the result of realloc
in a separate variable, and checking it for NULL
before assigning the value back to *filename
:
char *tmp = (char*)realloc(*filename, strlen(*collection_name)*sizeof(char)+5);
if (tmp != NULL) {
*filename = tmp;
} else {
// Do something about the failed allocation
}
Assigning directly to *filename
creates a memory leak, because the pointer the *filename
has been pointing to below would become overwritten on failure, becoming non-recoverable.
这篇关于valgrind-地址----是在分配了大小为8的块后为0字节的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!