我正在Linux中编写一个简单的程序。其目的是显示GNU版本号。但似乎free()
函数对我尖叫。当我执行程序时。它显示以下内容:
*`./a.out':munmap_chunk()出错:指针无效:0x00007fa89f028d8a *
和Backtrace和记忆图。
以下是我的代码:
# include <stdio.h>
# include <gnu/libc-version.h>
# include <string.h>
# include <stdlib.h>
int main(void){
const char *s;
s = (const char *)malloc(16*sizeof(char));
s = gnu_get_libc_version();
printf("%s\n",s);
free((char *)s);
return 0;
}
答案 0 :(得分:2)
当您使用返回值malloc
重新初始化s
时,您已丢失gnu_get_libc_version
返回的指针。您现在正在尝试free
gnu_get_libc_version
返回的指针malloc
尚未由malloc
分配。
在致电gnu_get_libc_version
之前,您不需要free
,并且在致电后不需要{{1}}。
答案 1 :(得分:1)
s = gnu_get_libc_version();
这不符合你的想象。看起来你希望它填充你先前分配的内存,s
所指向的内存。
实际所做的是导致s
指向完全不同的地方,某处由函数gnu_get_libc_version
决定。
鉴于free
错误以及documentation中的示例用法,这个内存从堆中分配而不是的可能性要大于偶数,因此尝试免费它会导致不明确的行为。
假设gnu_get_libc_version
实际上确实返回了C风格字符串的地址而且它不是来自堆(并且这似乎是基于上面链接的情况),您不需要分配它的记忆。相反,你可以拥有:
int main(void) {
const char *s = gnu_get_libc_version();
printf("%s\n", s);
return 0;
}
甚至更短(直接使用puts
和返回值):
int main(void) {
puts(gnu_get_libc_version());
return 0;
}
如果你做想要将版本信息放到你自己分配的缓冲区中(假设你有足够的内存),你可以使用:
int main(void){
const char *s = malloc(16);
strcpy(s, gnu_get_libc_version());
printf("%s\n", s); // or puts(s)
free(s);
return 0;
}
此将字符串(从gnu_get_libc_version
返回的区域)复制到您自己的缓冲区中,而不是将s
更改为指向其他位置。
请注意,我在原始代码中更改了其他一些内容。第一种是删除malloc
返回值的显式强制转换。这是不应该在C中完成的事情,因为它可以隐藏某些微妙的错误。 C完全能够隐式地将void *
返回值转换为另一种指针类型。
第二个是free
中的演员表,由于同样的原因,这也是不必要的。
第三个也是最后一个改变是将乘法移除sizeof(char)
。标准保证此值为1
,因此没有技术原因需要它。
答案 2 :(得分:0)
此函数gnu_get_libc_version()
可能返回指向静态内存的指针。
答案 3 :(得分:0)
在这一行
s = gnu_get_libc_version();
您将s
重新分配给char *
返回的其他gnu_get_libc_version
。由s
分配的malloc
的前一个值丢失,导致内存泄漏。 char *
的{{1}}返回未由gnu_get_libc_version
分配,因此当您在malloc
未返回的指针上调用free
时,会发生一些错误。
s = gnu_get_libc_version();