sscanf读取一个字符而不是整个字符串(mmap)

时间:2019-01-20 00:20:06

标签: c mmap

当我遇到这种现象时,我正在使用内存映射来“编辑”一个文件并将结果打印到另一个文件。我的理解是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

2 个答案:

答案 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'

可能存在其他问题。