use*_*137 3 c string pointers segmentation-fault
int i = 0;
while(fgets(lineStr, sizeof(lineStr), pFile)!=NULL){
puts(lineStr);
pch = strtok (lineStr, delim);
while(pch != NULL){
printf("%s\n",pch);
pch = strtok(NULL,delim);
}
}
Run Code Online (Sandbox Code Playgroud)
概述:我正在尝试编写grep的缩小版本(也就是查找文本文件中单词的出现次数).整个代码http://pastebin.com/VzTJkLK3
问题:我正在尝试使用strtok来标记表示一行文本的字符数组.我注意到使用gdb,我得到了一个分段错误
程序接收信号SIGSEGV,分段故障.__strlen_sse2()at ../sysdeps/x86_64/multiarch/../strlen.S:31 31 ../sysdeps/x86_64/multiarch/../strlen.S:没有这样的文件或目录.
任何有关更多文档的提示或链接都表示赞赏.
PS:我被告知使用strtok不是一个好的编程习惯 - 我是C btw的菜鸟.你会推荐什么选择?
Who*_*aig 11
您的代码不包括string.h用于包括双方的原型strlen()和strtok().由此产生的行为是为遗留C编译提供的一个有趣的"特性"; 在隐式声明.
在C中,如果在转换单元中使用之前没有声明正确的原型(或实际函数未实现),编译器将尽职地为您生成一个,默认返回值类型为int.这通常是一个巨大的问题,任何体面的编译器都会给它一个警告,至少会给你一个警告,这就是"警告隐式声明函数"foo"返回int"的效果
那么为什么这么无聊呢?好吧,不包括string.h,编译器假定你正在使用的两个函数,strlen()并且strtok()看起来像这样:
int strlen();
int strtok();
Run Code Online (Sandbox Code Playgroud)
这声明了两个函数原型,它们都返回int并接受零或多个参数.C调用此类函数的另一个"有用"功能是允许您将所需的任何内容作为参数传递给它们.编译器很乐意将它们按堆值推送到堆栈:
int n = strlen(str); // pushes char* on the stack, then makes the call.
Run Code Online (Sandbox Code Playgroud)
和类似的,但不完全相同:
char *p = strtok(str, delim); // pushes two char* on the stack
Run Code Online (Sandbox Code Playgroud)
那么为什么strlen似乎有效,但是出了问题strtok呢?好吧,因为在你的平台上,int(未声明strtok()函数的隐含返回类型)与char*你存储所述返回值的地方的字节大小不同.很可能你是在64位平台上,int是32位,但指针是64位.
因此,只有一半的指针被保存,另一半(32位)不被保留.因此返回的指针无效,因此kerboom.
原因strlen似乎只是因为返回的值作为int'"适合"到您的结果变量中.即函数实际返回(在其return语句中)一个64位的int,但调用者端(您的代码)只保存了"底部"一半.下半部分的值足以准确反映长度(上半部分0).如果字符串很大并且需要超过32位来表示其长度,则会出现同样的问题.(并注意,那一点你会遇到其他问题,比如你如何在进程地址空间中获得一个连续的4gB字符串).
注:与此密切相关的是主你的理由从来没有投的结果malloc()在C程序.硬铸造会隐藏将从中发出的警告.最好的证据是始终保持迂腐警告级别并打开警告 - 错误,这是一种好的做法.这样做的事情不会通过编译,很快就会被发现.