Fgets в сочетании с Sscanf - PullRequest
       1

Fgets в сочетании с Sscanf

1 голос
/ 18 декабря 2011

Сегодня я просмотрел код C, который анализировал данные из текстового файла. и я наткнулся на эти строки

fgets(line,MAX,fp);
if(line[strlen(line)-1]=='\n'){
    line[strlen(line)-1]='\0');
}else{
    printf("Error on line length\n");
    exit(1);
}
sscanf((line,"%s",records->bday));

с записью в виде структуры

typedef struct {
    char bday[11];
}record;

Итак, мой вопрос здесь касается комбинации fgets-sscanf для создания безопасного чтения потока типа / длины:

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

  • А как насчет \n последовательности проверки-удаления?

1 Ответ

2 голосов
/ 20 декабря 2011

Сочетание fgets() с sscanf() обычно хорошо. Тем не менее, вы, вероятно, должны использовать:

if (fgets(line, sizeof(line), fp) != 0)
{
    ...
}

Проверяет наличие ошибок ввода-вывода и EOF. Это также предполагает, что определение массива является видимым (в противном случае sizeof дает вам размер указателя, а не массива). Если массив не находится в области видимости, вам, вероятно, следует передать размер массива функции, содержащей этот код. Все это говорит о том, что грехи хуже, чем использование MAX вместо sizeof(line).

Вы не проверяли строку дня рождения нулевой длины; тем не менее, вы, вероятно, в конечном итоге проведете довольно много проверок введенной строки (даты непостоянны и трудно поддаются обработке).

Учитывая, что MAX равен 60, но sizeof(records->bday) == 11, вам необходимо защитить себя от переполнения буфера в sscanf(). Один из способов сделать это:

if (sscanf(line, "%10s", records->bday) != 1)
    ...handle error...

Обратите внимание, что 10 - это sizeof(records->bday) - 1, но вы не можете указать длину в качестве аргумента sscanf(); оно должно появляться в строке формата буквально. Здесь вы, вероятно, можете жить с нечетным размером, но если бы вы имели дело с более общим кодом, вы, вероятно, подумали бы о:

sprintf(format, "%%%zus", sizeof(records->bday) - 1);

Первый %% отображается на %; %zu форматирует размер (z - это C99 для size_t); s - для преобразования строки при использовании формата.

Или вы можете использовать strcpy() или memcpy() или memmove(), чтобы скопировать правый подраздел входной строки в структуру - но учтите, что %10s пропускает начальные пробелы, которые strcpy() и др. Не будут. Конечно, перед копированием вы должны знать, какова длина строки, и убедиться, что строка завершена нулем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...