Нижегородский государственный университет им. Н.И.Лобачевского
Опубликован: 25.11.2008 | Доступ: свободный | Студентов: 9592 / 1296 | Оценка: 4.06 / 3.66 | Длительность: 21:16:00
Лекция 5:

Системные данные текстового типа

< Лекция 4 || Лекция 5: 12345 || Лекция 6 >

4.3. Ввод текстовых данных во время работы программы

4.3.1. Форматный ввод

Список форматных указателей функции scanf предусматривает возможность ввода значений односимвольных ( %c ) и многосимвольных ( %s ) переменных:

#include <stdio.h>
void main()
{ char ch1,ch2;
  char str1[10];
  scanf("%c %c",&ch1,&ch2);
  scanf("%s",str1);
....................

Обратите внимание на то, что для ввода данных в скалярные переменные ch1 и ch2 в списке ввода необходимо указывать их адреса ( &ch1, &ch2 ), а при вводе в массив str1 – достаточно написать его имя. Дело в том, что имя массива одновременно выполняет роль адреса своего первого элемента. Поэтому str1 и &str1[0] указывают на один и тот же адрес.

Ввод значений символьных переменных ch1 и ch2 можно организовать одним из двух способов. Во-первых, в строке ввода можно набрать два требуемых символа либо слитно, либо разделяя их хотя бы одним пробелом и нажать клавишу Enter. Во-вторых, можно набрать первый символ, предназначенный для переменной ch1, и нажать клавишу Enter. Затем повторить аналогичным образом ввод следующего символа.

Значение, предназначенное для строковой "переменной" str1, не должно содержать более 9 символов (признак конца строки система добавляет автоматически) и среди них не должен присутствовать пробел. Дело в том, что пробел при форматном вводе воспринимается как разделитель данных. Это не означает, что среди символов строки пробел вообще не допустим, просто для организации ввода в строку нескольких слов надо использовать другие средства.

Довольно неожиданно, но с помощью задания ширины поля ввода и одного форматного указателя можно за один прием ввести несколько символов в элементы символьного массива:

char q[20];
............
scanf("%20c",q); //ввод 20 символов в массив q

В отличие от ввода по форматному указателю %s в массив q здесь не записывается признак конца строки – вводятся только запрашиваемые символы, которые набираются в одной строке с последующим нажатием клавиши Enter.

Функция scanf предусматривает еще два интересных форматных указателя, которые обеспечивают ввод либо тех символов, которые указаны в заданном множестве, либо всех символов, которые не принадлежат заданному множеству. Например, для ввода цифр из диапазона от 0 до 9 такой указатель имеет вид %[0-9], а для ввода символов, не являющихся цифрами – %[^0-9]. Рассмотрим следующий пример, который не только демонстрирует ввод по таким форматным указателям, но и содержит непредвиденный пассаж, связанный с использованием "грязного" буфера ввода.

#include <stdio.h>
#include <conio.h>

void main()
{ char str[10];
  int j;
  printf("Enter 123ABC\n");
  scanf("%[0-9]",str);
  printf("str=%s\n",str);
  for(j=0; j<10; j++)
    printf("%3x",str[j]);
  printf("\nEnter DEF123\n");
  scanf("%[^0-9]",str);
  printf("str=%s\n",str);
  for(j=0; j<10; j++)
    printf("%3x",str[j]);
  getch();
}
//=== Результат работы ===
Enter 123ABC
str=123
 31 32 33  0  0  1  0  0  1  0
Enter DEF123
str=ABC 
DEF
 41 42 43  a 44 45 46  0  1  0

После ввода первой строки программе были переданы символы '123', вслед за которыми в массив str был записан нулевой байт – признак конца строки. Однако в буфере ввода остались невостребованными символы 'ABC' и код клавиши Enter (код 0xa ). После набора второй строки к содержимому буфера ввода добавились еще три символа 'DEF' и т.к. все семь первых символов не являются кодами цифр, то все они были переданы в массив str. При выводе первые три отобразились в одной строке, затем сработал управляющий код 0xa и три следующие символа были выведены в следующей строке. Для наглядности содержимое массива после каждого вывода по формату %s отображалось еще и в шестнадцатеричном формате. Значения байтов, начиная с str[4], объясняются тем, что массив str является локальным, и под него выделяется "грязная память". Если его описание вынести за пределы main, то он станет глобальным и будет расписан нулями.

Чтобы не пострадать от непредвиденного ввода символов, задержавшихся в буфере ввода, рекомендуется после обращения к функции scanf чистить буфер ввода с помощью функции fflush(stdin). Если бы мы включили в предыдущий пример обращение к функции fflush, то после ввода второй строки в массиве str оказались бы только символы 'DEF'.

4.3.2. Потоковый ввод

Потоковый ввод в символьные и "строковые" переменные организуется следующим образом:

#include <iostream.h>
void main()
{ char ch1,ch2;
  char str1[10];
  cin >> ch1 >> ch2;
  cin >> str1;
....................

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

4.3.3. Специальные функции ввода текстовых данных

Специальные функции ввода символьных данных getch() и getche() упрощают их набор (не приходится дополнительно нажимать клавишу Enter) и предоставляют дополнительные возможности. Ниже приводится программа и результат ее работы после нажатия на цифровую клавишу 5.

#include <stdio.h>
#include <conio.h>

void main()
{ char ch[4]={'1','2','3'};
  ch[1]=getch();
  printf("ch[0]=%c ch[1]=%c ch[2]=%c",ch[0],ch[1],ch[2]);
  getch();
  return;
}
//=== Результат работы ===
ch[0]=1 ch[1]=2 ch[2]=3

Функция getch (от get character – дай символ) организует ввод кода символа без эхо-сигнала, т.е. без отображения на экране знака, соответствующего нажатой клавише. Такая возможность может оказаться полезной при вводе секретных данных (пароль) или в ситуации, когда отображение символа нажатой клавиши может повредить текущее содержимое экрана. Очень часто эту функцию используют в качестве задержки работы программы до нажатия какой-либо клавиши.

Функция getche обеспечивает ввод символа, соответствующего нажатой клавише с выдачей эхо-сигнала.

Обе функции обращаются к буферу клавиатуры. Если к этому моменту буфер пуст, то происходит ожидание нажатия клавиши. Считанный символ из буфера клавиатуры выталкивается. Однако клавиши на клавиатуре разные. Большая их часть связана с отображаемыми символами – буквами, цифрами, знаками препинания и т.п. После их нажатия обращение к функциям getch/getche приводит к считыванию соответствующего кода ASCII. В частности, к "отображаемым" клавишам относятся клавиши Esc (код 27), Enter (код 13), комбинация Ctrl+Z (код 26 – признак конца файла). Но на клавиатуре присутствует ряд клавиш, с которыми ассоциируются управляющие символы, не представленные в таблице ASCII. К ним, в частности, относятся функциональные клавиши F1, F2, ..., стрелки управления курсором, клавиши Insert и Delete и др. От их нажатия в буфер клавиатуры поступает двухбайтовый код, содержащий в старшем байте 0, а в младшем байте так называемый scan-код (некий порядковый код, приписанный каждой клавише). В этом случае первое обращение к функциям getch/getche приводит к считыванию нулевого кода, а повторное обращение возвращает scan-код ранее нажатой клавиши. Таким образом, для анализа кода нажатой управляющей клавиши к функциям getch/getche приходится обращаться дважды (предварительно следует убедиться в том, что первое обращение возвратило 0).

Функция gets (от get string – дай строку) позволяет ввести в символьный массив текстовое значение, содержащее пробелы:

#include <stdio.h>
#include <conio.h>
void main()
{ char str[80];
  gets(str);
  printf("\nstr=%s",str);
  getch();
}

При потоковом вводе со стандартного устройства stdin можно запросить заданное количество k символов, среди которых может встретиться и пробел:

cin.getline(str,k);

При этом можно ввести не более чем k-1 символ, т.к. нужно помнить о резервном байте для признака окончания строки. Если строка, набираемая пользователем, содержит более чем k-1 символ, то продолжение строки будет проигнорировано. И даже последующий оператор ввода не сможет им воспользоваться. Если строка ввода содержит меньше, чем k-1 символ, то она будет введена целиком. Более того, с помощью еще одного параметра, – символа завершения операции, можно досрочно прекратить ввод:

cin.getline(str,k,'Q');

Если в строке ввода будет досрочно обнаружен символ 'Q', то он уже не вводится.

Следует упомянуть еще одну функцию форматного ввода cscanf, ориентированную на работу с конкретным устройством – клавиатурой. Обращаются к ней точно так же как и к функции scanf, но они не дублируют друг друга. И вот почему. Дело в том, что стандартные устройства ввода ( stdin ) и вывода ( stdout ) могут быть подменены другими носителями информации (например, файлами или принтером). А ввод с клавиатуры и вывод на экран дисплея, образующих в совокупности консоль (пульт) оператора, переназначить нельзя.

< Лекция 4 || Лекция 5: 12345 || Лекция 6 >
Alexey Ku
Alexey Ku

Попробуйте часть кода до слова main заменить на 

#include "stdafx.h" //1

#include <iostream> //2
#include <conio.h>

using namespace std; //3

Александр Талеев
Александр Талеев

#include <iostream.h>
#include <conio.h>
int main(void)
{
int a,b,max;
cout << "a=5";
cin >> a;
cout <<"b=3";
cin >> b;
if(a>b) max=a;
else max=b;
cout <<" max="<<max;
getch();
return 0;
}

при запуске в visual express выдает ошибки 

Ошибка    1    error C1083: Не удается открыть файл включение: iostream.h: No such file or directory    c:\users\саня\documents\visual studio 2012\projects\проект3\проект3\исходный код.cpp    1    1    Проект3

    2    IntelliSense: не удается открыть источник файл "iostream.h"    c:\Users\Саня\Documents\Visual Studio 2012\Projects\Проект3\Проект3\Исходный код.cpp    1    1    Проект3

    3    IntelliSense: идентификатор "cout" не определен    c:\Users\Саня\Documents\Visual Studio 2012\Projects\Проект3\Проект3\Исходный код.cpp    6    1    Проект3

    4    IntelliSense: идентификатор "cin" не определен    c:\Users\Саня\Documents\Visual Studio 2012\Projects\Проект3\Проект3\Исходный код.cpp    7    1    Проект3

при создании файла я выбрал пустой проект. Может нужно было выбрать консольное приложение?