Сколько символов сканирует fscanf в моем коде? - PullRequest
0 голосов
/ 17 мая 2019

Я использую цикл for, который я хочу повторять число раз, равное количеству символов, отсканированных scanf. Тем не менее, кажется, работает слишком много раз. Код был изначально написан для печати во фразу «Мы в 2019 году», что он и делает, но теперь мне нужно использовать его для чего-то другого. Я добавил в строке: printf ("% i", i);

чтобы увидеть, сколько раз он проходил через цикл for. Кажется, он запускается 8 раз для каждого запуска цикла while, независимо от того, как долго было отсканировано слово.

#include <stdio.h>
#include <stdlib.h>

int main() {
    char* word = malloc(sizeof(char) * (46)); // create a char array

    FILE* fp;

    fp = fopen("file.txt", "w+");
    fputs("We are in 2019", fp);

    rewind(fp); // sets to start of file

    while(fscanf(fp, "%s", word) != EOF) {
        for(int i = 0; i < sizeof(word) / sizeof(word[0]); i++) {
            printf("%c", word[i]);

            printf("%i", i);
        }
        printf("\n");
    }

    fclose(fp);

    return (0);
}

Вывод:

W0e1234567
a0r1e234567
i0n1234567
200112934567

Итак, я вижу, что он выполняет цикл for 8 раз для каждого запуска для каждого цикла while.

Я неправильно понимаю, как работает fscanf? я думал, что он остановился на пустом месте и сохранил только предыдущие символы ... например сначала он сканирует «Мы», затем сохраняет его как массив из 3 символов в «словах», затем сканирует «находятся» в массиве из 4 символов в «словах» и так далее. Что на самом деле происходит?

Ответы [ 3 ]

0 голосов
/ 17 мая 2019

sizeof(word) не даст вам размер массива.Он дает размер указателя char *word.

Было бы проще избежать выделения памяти, а размер массива на самом деле не имеет значения.

#include <stdio.h>
#include <stdlib.h>

int main() {
    char word[46];                          // local array
    FILE* fp = fopen("file.txt", "w+");
    if(fp == NULL)  {
        return 1;                           // or better error report
    }
    fputs("We are in 2019", fp);
    rewind(fp);

    while(fscanf(fp, "%45s", word) == 1) {  // restrict length, check the scan worked
        for(int i = 0; word[i] != 0; i++) { // finish when the string terminator is found
            printf("%c", word[i]);
        }
        printf("\n");
    }
    fclose(fp);
    return 0;
}

Вывод программы:

We
are
in
2019
0 голосов
/ 17 мая 2019

Несколько замечаний можно сделать по вашему коду

  • по определению sizeof(char) равно 1, поэтому ваш malloc(sizeof(char) * (46)) может быть упрощен до malloc(46). Обратите внимание, что вы также можете использовать массив char word[46];

  • fscanf(fp, "%s", word) очень опасно, если прочитанное слово длиннее 45 символов, которое вы пишете из слово с неопределенным поведением, ограничивает размер, делая fscanf(fp, "%45s", word)

  • Как сказано в комментариях sizeof(word) / sizeof(word[0]) не возвращайте длину своего слова, вы можете просто остановиться, когда word[i] = 0

  • для печати индекса сразу после того, как каждый символ не дает очень читабельного результата, вы уверены, что хотите этого?

  • почему вы не печатаете слово напрямую с помощью (f) ставит или printf в формате % s и не получаете длину строка, использующая strlen (если вы хотите это знать)?

Я хочу повторять количество раз, равное количеству символов, отсканированных scanf.

scanf сканирует больше, чем количество символов в возвращаемых значениях в строке, пробелы молча обходятся. Только одна вещь уверена, когда вы дойдете до конца файла без ошибок количество символов, отсканированных scanf , если размер файла.

0 голосов
/ 17 мая 2019

Он останавливается на пустом месте.

Видимо, у вас есть 64-битные указатели. Слово переменной является указателем, поэтому sizeof(word) равно 8. Поскольку sizeof один символ равен 1, sizeof(word) / sizeof(word[0]) равно 8.

Итак, когда fscanf возвращается в первый раз, он прочитал «Мы» в буфер. Тогда он зацикливается на i от 0 до 7.

i = 0
printf("%c", word[i]); //=> 'W'
printf("%i", i); //=>0

i = 1
printf("%c", word[i]); //=> 'e'
printf("%i", i); //=>1

i = 2
printf("%c", word[i]); //=> '\0' so nothing
printf("%i", i); //=>2

i = 3
printf("%i", i); //=>3

i = 4
printf("%i", i); //=>4

i = 5
printf("%i", i); //=>5

i = 6
printf("%i", i); //=>6

i = 7
printf("%i", i); //=>7

так вот как вы получите:

W0e1234567

Вы бы увидели желаемый результат, если бы ваш цикл выглядел следующим образом:

while(fscanf(fp, "%s", word) != EOF) {
    puts(word);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...