当我遇到这种现象时,我正在使用内存映射来“编辑”一个文件并将结果打印到另一个文件。我的理解是sscanf
(类似于printf)读取字符串,直到遇到空格或换行符为止。当我在mmap
的源文件中使用它来过滤掉注释并将其他所有内容打印到第二个文件时,这正是我的策略。对于注释行如何开始的给定参数(字符串,例如“#”,“ @”,“ //”,“随便什么”),我使用sscanf
检查行是否以该词开头。令我惊讶的是,似乎在使用mmap
时,指向该虚拟内存的指针并不相同。 (请注意while循环之前的测试printf)。
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>
#include <unistd.h>
static void fatalError(char *message);
int main(int argc, char *argv[])
{
int fd1, fd2;
struct stat stats;
char *source, *dest;
assert(argc == 4);
if ((fd1 = open(argv[1], O_RDONLY)) < 0) {
if (errno == ENOENT)
fatalError("First file nonexistent");
else
fatalError("open error");
}
if ((fd2 = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)) < 0) {
if (errno == EACCES)
printf("Creating second file\n");
else
fatalError("open error");
}
if (fstat(fd1, &stats) < 0)
fatalError("fstat error");
if (lseek(fd2, stats.st_size-1, SEEK_SET) < 0)
fatalError("lseek error");
if (write(fd2, "", 1) != 1)
fatalError("write error");
if ((source = mmap(0, stats.st_size, PROT_READ, MAP_SHARED, fd1, 0)) == MAP_FAILED)
fatalError("mmap failed");
if ((dest = mmap(0, stats.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd2, 0)) == MAP_FAILED)
fatalError("mmap failed");
char word[100];
int flag, count;
char *tmp;
tmp = source;
char test[50] = "firstWord will only be read by sscanf";
sscanf(test, "%s", word);
printf("%s\n", word);
while ((count = sscanf(source, "%s", word)) > 0) {
if (!flag) {
// in comment
if (!strcmp(word, argv[3])) {
flag = 1;
source += count;
continue;
}
sprintf(dest, "%s", word);
source += count;
} else {
// not in comment
if (word[strlen(word) - 1] == '\n') {
sprintf(dest, "\n");
source += count;
}
source += count;
}
}
source = tmp;
if (munmap(source, stats.st_size) < 0)
fatalError("munmap error");
if (munmap(dest, stats.st_size) < 0)
fatalError("munmap error");
if (close(fd1) < 0)
fatalError("close return");
if (close(fd2) < 0)
fatalError("close error");
return 0;
}
static void fatalError(char *message) {
perror(message);
exit(EXIT_FAILURE);
}
输入文件(“#”作为注释符号):
npwhitespacea
asdasdasdasd
# asdasdasdasmdaosimda
asdasd
kmflsdkfms
#
oioiasjdoaisd
i
# asoidaosid
答案 0 :(得分:0)
sscanf
读取直到空'\0'
个字符。
答案 1 :(得分:0)
source += count;
是有问题的代码,因为它与source++;
的{{1}}相同,此处为1。
就像在匹配时一样,代码应按字符串的长度而不是转换计数的长度前进。
count
代码从不正确
// in comment
if (!strcmp(word, argv[3])) {
flag = 1;
// source += count;
source += strlen(argv[3]);
continue;
}
从来都不是真的,因为word[strlen(word) - 1] == '\n'
不会将空格放入sscanf(source, "%s", word)
中。
sscanf(类似于printf)读取一个字符串,直到遇到空格或换行符为止。
OP的概括过于广泛。 1)“直到”取决于格式。 2)使用word
格式,"%s"
读取空白并跳过其他空格,然后读取非空白并保存。这一直持续到找到空白(包括sscanf()
)为止。 '\n'
与sscanf()
的区别在于,scanf/fscanf
读取/保存的空字符与所有非空白一样,都被读取/保存。使用scanf/fscanf
时,空字符类似于文件结尾。它不是“读取/保存”的,但是会停止扫描。
OP的整体策略存在弱点。 OP正在寻找注释行。 sscanf()
失去了对"%s"
的所有意识。
代码可以使用以下内容读取行,但是对于空行或超长行则需要做更多的工作。
'\n'
可能存在其他问题。