这是我的问题:我想映射文件" filename.txt",它基本上由每行两对字符串组成:
"string1 string2
string3 string4
string5 string6..."
然后我想用strtok分隔不同的字符串。
所以我像这样映射文件:
// open file
if ((fdsrc = open("filename.txt", O_RDONLY)) < 0) {
fprintf(stderr, "src open error");
exit(1);
}
// get the size of the file
if (fstat(fdsrc, &statbuf) < 0) {
fprintf(stderr, "fstat error");
exit(1);
}
// mmap the file
if ((src = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fdsrc, 0)) == (caddr_t) -1) {
fprintf(stderr, "mmap src");
exit(1);
}
当我运行
时printf("src: %s \n", src);
它正确打印文件的内容!
但是当我试图分开单词
时char* token;
token = strtok(src, " \n");
while (token != NULL) {
token = strtok(NULL, " \n");
}
输出是Segmentation Fault。 为什么我不能使用StrTok呢?
答案 0 :(得分:6)
strtok()
修改其操作的字符串。假设您不想更改文件内容,则需要更改mmap()
选项。
您正在以只读方式打开并映射文件:
if ((fdsrc = open("filename.txt", O_RDONLY)) < 0) {
...
if ((src = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fdsrc, 0)) == (caddr_t) -1) {
...
使用PROT_READ|PROT_WRITE
和MAP_PRIVATE
src = mmap(0, statbuf.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fdsrc, 0);
if (src == (caddr_t) -1) {
您可能需要使用O_RDWR
而不是O_RDONLY
请注意:
如果文件大小与用于映射的页面大小的多个完全匹配,则该文件将不是NUL终止的字符串,当strtok()
尝试读取结束时,您可能会获得SIGSEGV映射。
在这种情况下,您可以在文件映射后紧跟mmap()
零填充页面。
答案 1 :(得分:3)
您的文件只能与PROT_READ
一起映射。但是strtok()
会修改其第一个参数src
,并获得分段错误。您需要在使用strtok
之前制作可写副本,或者切换到仅读取其输入的机制。在我看来,将该缓冲区的保护更改为PROT_RW
似乎很奇怪,特别是如果您打算在程序的其他位置使用该文件的未修改内容。
作为替代方案,我建议使用strstr()
(或不需要nul-byte终止的替代实现)来定位行尾子字符串,然后开始下一次搜索找到最后一次出现,加上子串的长度。请参阅下面有关空字节终止的说明。一个简化的例子:
const char *delim = "\n";
const char *start = src;
const char *end = NULL;
const int srclen = statbuf.st_size;
const int delim_length = strlen(delim);
while (start && start < (src + srclen)) {
end = strstr(start, delim);
if (NULL == end) {
// use of %.* to print at most X chars from string.
printf("Token: %.*s\n", (int) (src + srclen - start), start);
break;
} else {
printf("Token: %.*s\n", (int) (end - start), start);
start = end + delim_length;
}
}
mmap区域可能不会以空字节结尾(如评论所示)
strstr()
适用于以null结尾的字符串。您的mmapped区域可能不以空字节结尾。内核可能会使用\0
擦除最后一个mmapped内存页面的剩余部分(超过文件结尾)以避免进程之间的数据泄漏,但是如果您的文件长度恰好是页面的倍数-size,你在使用strstr()
时会遇到麻烦 - 没有一个空字节可以让你回来。
您可以推出自己的小字符串查找器strnstr()
。或者强制在末尾标记另一个空页。
答案 2 :(得分:2)
strtok()
修改传递指针的char
数组。
您mmap
该文件处于只读模式,因此当strtok
尝试修改内存时,您会收到违规行为。
在读取+写入模式下mmap
文件是个坏主意,该文件将被修改并可能已损坏。
strtok
不适合您的目的,编写自己的匹配函数,不修改其参数数组并返回偏移量和长度。
另请注意,mmap
ped内存不应超出文件大小而被访问,并且不一定'\0'
终止,因此您不应使用字符串函数来搜索它({{ 1}},strchr
,strstr
...)也不从中复制(strlen
)。