Прочитать целое число после чтения строки из файла с помощью fscanf

Я сделал программу, в которой есть файл test.txt, содержащий следующие

24 Рохит Сони 1997

Это мой код:

#include <stdio.h>

void main()
{
    FILE *f;
    int no,i;
    char *name;
    f=fopen("test.txt","r");
    fscanf(f,"%d %[^[0-9]]s %d ",&no, name, &i);
    printf("%d %s %d",no, name,i);
    fclose(f);
}

Но он не показывает правильный результат. Выход:

24 Рохит Сони 12804

Подскажите пожалуйста, что делать. Почему не принимает целое число после взятия строки из fscanf с использованием спецификатора формата %[.


person Rohit Soni    schedule 17.12.2016    source источник
comment
Не оставляйте конечный пробел в строке формата, если вы можете использовать его в интерактивном режиме (при вводе текста на клавиатуре).   -  person Jonathan Leffler    schedule 18.12.2016
comment
Правило 1 о f / scanf: всегда проверяйте возвращаемое значение. Правило 2 о f / scanf: не пытайтесь использовать их для чего-нибудь сложного. Правило 3 о f / scanf: как только вы освоитесь с C, научитесь читать строки с помощью fgets и каким-то другим способом разбирать строки на токены, чтобы вам больше никогда не пришлось использовать f / scanf. , потому что: Правило 4 о f / scanf: они действительно не годятся для многого.   -  person Steve Summit    schedule 18.12.2016


Ответы (1)


Вы должны проверить код возврата от fscanf(); он сообщит вам, что преобразованы 2 значения вместо 3, которые вы ожидали. Вы всегда должны проверять код возврата из fscanf(), обычно для ожидаемого количества преобразований, и только очень редко вы будете проверять EOF или 0.

Проблема в том, что набор сканирования %[^…] не является модификатором для %s, а также набор сканирования останавливается на первом ], если только он не следует сразу за [ для обычного набора сканирования или [^ для отрицательного набора сканирования. Итак, ваша строка формата ищет последовательность символов «не цифра или [», за которой следуют ] и s - и она не находит ] и s во входных данных.

Тебе нужно:

#include <stdio.h>

int main(void)
{
    const char *filename = "test.txt";
    FILE *f = fopen(filename, "r");
    if (f == 0)
    {
        fprintf(stderr, "Failed to open '%s' for reading\n", filename);
        return 1;
    }
    int no,i;
    char name[128];

    if (fscanf(f, "%d %127[^0-9] %d", &no, name, &i) != 3)
    {
        fprintf(stderr, "Failed to read three values\n");
        return 1;
    }
    printf("%d [%s] %d\n", no, name, i);
    fclose(f);
    return 0;
}

Вам нужно проверить, что fopen() сработало. Сообщение об ошибке должно включать имя файла, который вам не удалось открыть. (Если вы обратили внимание на аргументы командной строки - используя int main(int argc, char **argv) - вы также укажете имя программы из argv[0] в сообщениях об ошибках.) Вам нужно выделить место для name, а не использовать неинициализированный указатель. правильный тип возврата для main() - int, хотя Microsoft разрешает void. Обратите внимание, что формат ввода гарантирует отсутствие переполнения буфера < / а>.

Я заключил имя в […] в выводе, чтобы вы могли видеть, что имя включает конечный пробел. Результат, который я получаю:

24 [Rohit Soni ] 1997
person Jonathan Leffler    schedule 17.12.2016
comment
if (f == 0), вау, я не знал, что ты можешь это сделать. Классный, приятный ответ. - person RoadRunner; 18.12.2016
comment
Большое спасибо, Джонатан, но у меня есть небольшие сомнения относительно% 127 [^ 0-9], почему вы написали здесь 127 и даже не написали 's' (поскольку мы принимаем строку)? - person Rohit Soni; 18.12.2016
comment
См. Ссылку в разделе «Переполнение буфера», чтобы узнать, почему 127 подходит. Как я сказал в ответе, %[…] сам по себе является спецификатором преобразования; это не модификатор для %s. - person Jonathan Leffler; 18.12.2016