Программирование. Принципы и практика использования C++ Исправленное издание, стр. 396

Функция

scanf()
считывает данные с помощью формата точно так же, как и функция
printf()
. Как и функция
printf()
, она может быть очень удобной.

void f()

{

  int i;

  char c;

  double d;

  char* s = (char*)malloc(100);

  /* считываем данные в переменные, передаваемые как указатели: */

  scanf("%i %c %g %s", &i, &c, &d, s);

  /* спецификатор %s пропускает первый пробел и прекращает

     действие на следующем пробеле */

}

 

Программирование. Принципы и практика использования C++ Исправленное издание - _003.png
 Как и функция
printf()
, функция
scanf()
не является безопасной с точки зрения типов. Форматные символы и аргументы (все указатели) должны точно соответствовать друг другу, иначе во время выполнения программы будут происходить странные вещи. Обратите также внимание на то, что считывание данных в строку
s
с помощью спецификатора
%s
может привести к переполнению. Никогда не используйте вызовы
gets()
или
scanf("%s")
!

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 Итак, как же безопасно ввести символы? Мы можем использовать вид формата %s, устанавливающий предел количества считываемых символов. Рассмотрим пример.

char buf[20];

scanf("%19s",buf);

Нам требуется участок памяти, заканчивающийся нулем (содержание которого вводится функцией

scanf()
), поэтому 19 — это максимальное количество символов, которое можно считать в массив
buf
. Однако этот способ не отвечает на вопрос, что делать, если некто введет больше 19 символов. Лишние символы останутся в потоке ввода и будут обнаружены при следующей попытке ввода.

Проблема с функцией

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

while((x=getchar())!=EOF) {

  /* ... */

}

Макрос

EOF
, описанный в библиотеке
stdio
, означает “конец файла”; см. также раздел 27.4.

Альтернативы функций

scanf("%s")
и
gets()
в стандартной библиотеке языка C++ от этих проблем не страдают.

string s;

cin >> s; // считываем слово

getline(cin,s); // считываем строку

27.6.3. Файлы

В языке C (и C++) файлы можно открыть с помощью функции

fopen()
, а закрыть — с помощью функции
fclose()
. Эти функции, вместе с представлением дескриптора файлов
FILE
и макросом
EOF
(конец файла), описаны в заголовочном файле
<stdio.h>
.

FILE *fopen(const char* filename, const char* mode);

int fclose(FILE *stream);

По существу, мы используем файлы примерно так:

void f(const char* fn, const char* fn2)

{

  FILE* fi = fopen(fn, "r");  /* открываем файл fn для чтения */

  FILE* fo = fopen(fn2, "w"); /* открываем файл fn для записи */

  if (fi == 0) error("невозможно открыть файл для ввода");

  if (fo == 0) error("невозможно открыть файл для вывода");

  /* чтение из файла с помощью функций ввода из библиотеки stdio,

     например, getc() */

  /* запись в файл с помощью функций вывода из библиотеки stdio,

     например, fprintf() */

  fclose(fo);

  fclose(fi);

}

Учтите: в языке С нет исключений, потому вы не можете узнать, что при обнаружении ошибок файлы были закрыты.

27.7. Константы и макросы

В языке С константы не являются статическими.

const int max = 30;

const int x; /* неинициализированная константа: OK в C

                (ошибка в C++) */

void f(int v)

{

  int a1[max]; /* ошибка: граница массива не является константой

                  (OK в языке C++) */

               /* (слово max не допускается в константном

                  выражении!) */

  int a2[x];   /* ошибка: граница массива не является константой */

  switch (v) {

  case 1:

    /* ... */

    break;

  case max:    /* ошибка: метка раздела case не является

                  константой
 (OK в языке C++) */

    /* ... */

    break;

  }

}