繁体   English   中英

释放c中的char指针会导致segfault

[英]freeing char pointer in c causes segfault

主题说了全部,这是用简单文件编写的相关代码。

char* fn = NULL;
SDL_Log("fn pre address is: %p\n",fn);
fn = get_resource("test.txt");
SDL_Log("fn pos address is: %p\n",fn);
//free(fn); <--this causes seg fault if I uncomment it

INFO: fn pre address is: 0x0
INFO: fn pre address is: 0x7fa882501a00
INFO: fn pos address is: 0x7fa882501a00

get_resource(const char* filename) {
    char* string = (char*)calloc(1, sizeof(strlen(res_dir) + strlen(filename)));
    //i also tried with strncpy
    //strncpy(string, res_dir, strlen(res_dir));
    //strncpy(string + strlen(res_dir), filename, strlen(filename));

    memcpy(string, "/usr/test/files", strlen(res_dir));
    memcpy(string + strlen("/usr/test/files"), filename, strlen(filename));
    string[strlen(filename) + strlen("/usr/test/files")] = '\0';
    return string;
}

得到相同的行为。 如果释放分配的字符串,将出现段错误。 而且这也不总是总是发生,这很奇怪。

char* string = (char*)calloc(1, sizeof(strlen(res_dir) + strlen(filename)));

这行没有任何意义, sizeof是用于确定类型或某种类型的表达式所需的存储大小的运算符。(*)

您想要的是这样的:

char* string = calloc(1, strlen(res_dir) + strlen(filename) + 1);

注意那里的+ 1 ,它为c样式字符串中的终止0字节保留空间。 还请注意,强制转换void *指针(由malloc()和C中的朋友返回)是没有意义的。 在C ++中这是必需的,但是在C中, void *通用指针类型,并且隐式转换为任何其他数据指针类型。

进一步挖掘您的代码(按照alk的注释)...我想res_dir只是"/usr/test/files" 您可能在此处缺少斜杠(取决于filename的内容),但通常,对于串联字符串,已经有C语言的函数在string.h声明。 只需编写如下简单内容:

char* string = calloc(1, strlen(res_dir) + strlen(filename) + 1);
strcpy(string, res_dir);
strcat(string, filename);

到此为止。 注意,您甚至不需要使用此方法的calloc()malloc()会很好。


(*)在此处添加更多说明:由于明显的原因,您可能会看到sizeof经常与内存分配一起使用。 您要为char类型保留内存。 您希望将一些char容纳到此内存中。 因此,正确的公式如下所示:

malloc( (strlen(res_dir) + strlen(filename) + 1) * sizeof(char) )

那为什么要忽略sizeof(char)呢? 这是因为char的大小实际上定义1 x * 1仍然是x ,因此无需在此处使用sizeof :)

首先这句话

char* string = (char*)calloc( 1, sizeof(strlen(res_dir) + strlen(filename)));

是不正确的。 表达

sizeof(strlen(res_dir) + strlen(filename))

相当于

sizeof( size_t )

可以等于4或8,具体取决于使用的环境。 有关此表达式的更多信息

sizeof(strlen(res_dir) + strlen(filename))

没有被评估 也就是说,该表达式中未调用 strlen函数。

正确的陈述看起来像

char *string = calloc( strlen( res_dir ) + strlen( filename ) + 1, sizeof( char ) );

考虑到您还需要为终止的零保留内存。

但是,即使此语句也不正确。

考虑你想做什么

memcpy(string, "/usr/test/files", strlen(res_dir));
memcpy(string + strlen("/usr/test/files"), filename, strlen(filename));

当您传递字符串"test.txt"您将获得

"/usr/test/filestest.txt"

我想你的意思是以下

"/usr/test/files/test.txt"

如果是这样,那么内存分配必须看起来像

char *string = calloc( strlen( res_dir ) + strlen( filename ) + 2, sizeof( char ) );

在这种情况下,您可以简单地编写

strcpy( string, "/usr/test/files" );
strcat( string, "/" );
strcat( string, filename );

在这种情况下,

string[strlen(filename) + strlen("/usr/test/files")] = '\0';

必须删除。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM