为何对赋值为字符串字面量的malloc指针调用strtok会触发总线错误
问题原因分析
- 指针指向错误,触发非法写操作
你最初通过malloc给str申请了16字节的可写堆内存,但后续执行str = "This - is - foo";时,并没有把字符串内容写入这块堆内存,而是直接修改了str指针的指向,让它指向了双引号包裹的字符串常量。C语言中的字符串常量存储在进程的只读数据段,该区域内存没有写权限。 strtok的运行逻辑需要修改原字符串strtok做字符串分割时,会直接在原字符串的分隔符位置写入\0来截断字符串,当传入的指针指向只读内存时,这个写操作就会触发总线错误/段错误。- 额外问题:内存泄漏
修改str的指向后,原本malloc申请的16字节内存再也没有指针可以访问,会造成内存泄漏。
修复方案
有两种常用的修复方式:
方案1:将字符串内容拷贝到可写堆内存
把直接赋值的str = "This - is - foo";替换为strcpy(str, "This - is - foo");,将字符串常量的内容拷贝到之前malloc申请的可写堆空间中即可。
修复后的完整代码:
#include <string.h> #include <stdio.h> #include <stdlib.h> int main () { char *str = malloc(16); memset(str, '\0', 16); // 用strcpy拷贝内容,而非修改指针指向 strcpy(str, "This - is - foo"); const char s[2] = "-"; char *token; /* 获取第一个分割片段 */ token = strtok(str, s); /* 遍历剩余分割片段 */ while( token != NULL ) { printf( " %s\n", token ); token = strtok(NULL, s); } // 手动释放堆内存避免泄漏 free(str); return(0); }
方案2:直接用栈数组存储字符串
如果不需要动态申请内存,可以直接定义栈上的字符数组存储字符串,栈内存默认可写,也可以正常运行:
#include <string.h> #include <stdio.h> int main () { // 数组存储的字符串是可写的 char str[] = "This - is - foo"; const char s[2] = "-"; char *token; token = strtok(str, s); while( token != NULL ) { printf( " %s\n", token ); token = strtok(NULL, s); } return 0; }
内容的提问来源于stack exchange,提问作者Lucky
相关产品推荐
相关产品推荐

