【问题标题】:Why does fseek from SEEK_CUR use random character for space?为什么 SEEK_CUR 中的 fseek 使用随机字符作为空格?
【发布时间】:2020-09-18 00:44:51
【问题描述】:

有这个:

int main (void) {

    FILE *fp = fopen("txt2", "r+");

    rewind(fp); 
    fprintf(fp, "ab");
    fseek(fp,1L,SEEK_CUR); //trying to change offset to 1,2,3,...
    fprintf(fp, "cd");
    rewind(fp);

    for(int c;(c=getc(fp))!=EOF;)
        putchar(c);

    fclose(fp);

    return 0;
}

我想知道,如果fseek 从当前位置向前偏移了空格或一些垃圾。我会在应该是空格的地方给出^ 的输出。

fseek(fp,0L,SEEK_CUR)
->  abcd //yes, that is what I expect

fseek(fp,1L,SEEK_CUR)
-> abccd //not space -> 'c' char instead
     ^

fseek(fp,2L,SEEK_CUR)
-> abcdcd //'cd' are in addition (random chars?)
     ^^

fseek(fp,3L,SEEK_CUR)
-> abcdccd //'cdc' no it is probably not "random", they repeat
     ^^^

fseek(fp,100000000000L,SEEK_CUR)
-> abcdcdcdcdcdcdcdcdcd

fseek(fp,1000000000000000000000000L,SEEK_CUR0
->warning: integer constant is too large for its type
fseek(fp,1000000000000000000000000L,SEEK_CUR);

fseek 移动是怎么回事?它们是制作“移动字符”的图案?在这种情况下根据下一个printf 字符? (cd)。我不太了解这种行为以及如何使用 fseek 移动空格?我只知道在每次写入之前和之后使用 rewind 以执行正确的读取(在 for 循环中),但这并不能解释这种行为。谁能给个提示?

【问题讨论】:

  • 您正在寻找文件末尾,这会留下一个“洞”,并且您希望库使用空格字符来填充该洞:是什么让您认为应该这样做?我从未将其视为图书馆合同的一部分,因此它可能会获取您刚刚寻找过去的缓冲区中的任何垃圾。我几乎可以肯定这里没有明确的行为。
  • r+ 开头和fprintf() 调用表明您要读写txt2; 2 fprintf() 解释 abcd 字节。如果不是有意的,请切换到使用r 打开并且不要输出到fp。要了解有关空间的问题,发布输入文件会有所帮助。
  • @SteveFriedl 那么如何在文件末尾创建“空间”,以便我可以在文件末尾移动并写入? (这是帖子的意图)
  • @autistic456 我不确定我是否完全明白这个问题 - 如果你想移动到文件的末尾,那么你可以使用偏移量为 0 的SEEK_END 标记。

标签: c io fseek


【解决方案1】:

这是实际发生的事情:

FILE *fp = fopen("txt2", "r+");   
// need to check (!=NULL) to assure `fopen()` was successful

rewind(fp);      
// `fopen()` places current position in file at beginning, so this call not needed

fprintf(fp, "ab");     
// current position now ==2 (starts at 0)

fseek(fp,1L,SEEK_CUR); //trying to change offset to 1,2,3,...
// current position now at 3 I.E. "ab?"

fprintf(fp, "cd");     
// current position now == 5 I.E. "ab?cd"

the value, at the '?' is what ever happened to be on the disk at (current position =2) position in the file

【讨论】:

    【解决方案2】:

    啊哈,我明白发生了什么事。它不是使用空格,而是使用 NUL 字节,这更符合预期,但不会出现在您的输出中。

    在显示输出的示例代码中,将其更改为:

        for(int c; (c = getc(fp)) != EOF;)
        {
            if (c == 0) c = '.';  // ADD ME
            putchar(c);
        }
    

    现在它会在每次有 NUL 字节时显示一个点,代表你过去寻找的洞。

    从一个空的 txt2 文件开始,并且搜索偏移量为 2,它显示:

    ab..cd
    

    因为您没有在终端上看到 NUL 字节,所以看起来一切都在发生变化,这让我摸不着头脑。

    编辑:如果您前后显示txt2 文件的内容,您的帖子会更加清晰,因为这些更改是累积的,并且在 NUL 字节时无法遵循进入游戏。

    这应该可以解决问题:

    #include <stdio.h>
    
    static void showfile(FILE *fp, const char *which)
    {
        // using | characters to show the start and end of the buffer
        // in case there are trailing blanks involved.
        printf("File %s: |");
        for (int c; (c = getc(fp)) !=EOF;)
        {
            if (c == 0) c = '.';
            putchar(c);
        }
        printf("|\n");
    }
    
    
    int main (void) {
    
        FILE *fp = fopen("txt2", "r+");
    
        long offset = 3L;  //trying to change offset to 1,2,3,...
        printf("Running with offset = %ld\n", offset);
    
        showfile(fp, "before");
    
        rewind(fp);
        fprintf(fp, "ab");
        fseek(fp, offset, SEEK_CUR);
        fprintf(fp, "cd");
        rewind(fp);
    
        showfile(fp, "after ");
    
        fclose(fp);
    
        return 0;
    }
    

    然后运行它:

    Running with offset = 2
    File before: ||
    File after : |ab..cd|
    
    // rerun with previous file
    Running with offset = 3
    File before: |ab..cd|
    File after : |ab..ccd|
    

    【讨论】:

      猜你喜欢
      • 2021-03-16
      • 2018-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多