Почему fseek из SEEK_CUR использует случайный символ для пробела? - PullRequest
1 голос
/ 30 мая 2020

Имея это:

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 до и после каждой записи для правильного чтения (для l oop), но это не объясняет поведение. Может кто подскажет?

Ответы [ 2 ]

0 голосов
/ 30 мая 2020

вот что происходит на самом деле:

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
0 голосов
/ 30 мая 2020

Ага, я вижу в чем дело. Он не использует пробелы, он использует байты 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|
...