Не правильное применение функции scanf приводит к проблемам с безопасностью. Ниже приведён код, в котором произойдет переполнение буфера при введении 10 и более символов:
char str[10];
scanf("%s", str);
Чтобы избежать переполнения можно указать ширину поля:
char str[10];
scanf("%9s", str);
В этом случае будет прочитано не более 9 символов, но если было введено больше символов, то в буфере stdin остаются лишние символы и перед следующим чтением буфер нужно очистить. Для избежания переполнения буфера, при использовании функции scanf, библиотека GNU C поддерживает не стандартное расширение, которое автоматически выделять достаточно память под вводимые данные. Для использования этого расширения нужно указать модификатор a как модификатор длинный %as:
char *str;
if ( scanf("%as", &str) == 1 )
// указатель на char* указатель для адреса буфера
{
printf("%s\n", str);
free(str);
}
При успешном выполнении функции scanf вызывающий код должен освободить выделенную память функцией free. Модификатор a не доступен если программа компилируется с флагом -std=c99 или -D_ISOC99_SOURCE. Начиная с версии 2.7 библиотека поддерживает модификатор m, который действует как a, но доступен при -std=c99.
Вместо функции scanf рекомендуется пользоваться другим расширением библиотека GNU C, функцией getline, которая позволяет надёжно читать строку произвольной длинны и самостоятельно выделяет необходимый объёма памяти:
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
lineptr — указатель на char* указатель для адреса динамически выделенного буфера.
Если инициализирован NULL, getline сам выделит память иначе должен
указывать на буфер выделенный с помощью функции malloc.
n — указатель на размер буфера. Если буфер выделен с помощью malloc, *n должно
содержать размер буфера, иначе 0.
stream — поток, откуда читаются данные.
Пример использования:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
char* pUserName = NULL;
size_t bytes_read, nbytes = 0;
bytes_read = getline(&pUserName, &nbytes, stdin);
if ( bytes_read != -1 )
{
printf("%s", pUserName);
}
if ( pUserName )
free(pUserName);
При достижении конца файла или ошибке функция возвращает -1. В случае успешного завершения функция возвращает число прочитанных символов (включая символ перевода строки, но не, включая пустой символ завершения) и может обновлять значения *lineptr и *n, если буфер изменялся.
Комментариев нет:
Отправить комментарий