Как ввести char c
Перейти к содержимому

Как ввести char c

  • автор:

Символы и строки

Символьная константа — это один символ, заключенный в апострофы. Его типом является тип char . Объявить символ можно так:

const char my_symbol='a';

Строковая константа — это последовательность символов, заключенная в кавычки. Объявляем ее так:

const char str[5] ="abcd";

Вы можете задать вопрос:»Почему размер массива символов задан равным пяти, а букв в строке мы написали четыре?». Дело все в том, что строковая константа всегда имеет на 1 символ больше, чем используется при записи, она ВСЕГДА заканчивается символом конца строки ‘\0’ , или, как его еще называют, ноль символом. Он никак не отображается при выводе строки на экран или в файл.

Соглашение об указателях char*

Сообщество программистов C и C++ договорились считать тип char* формой строкового типа. Соглашение заключается в том, что строки заканчиваются символом ‘\0’, и только для таких строк можно использовать функции библиотеки &ltcstring&gt. Язык C++ частично поддерживает тип char*, устанавливая, что строковая константа заканчивается ноль символом.

Существует важное отличие char* от char[]. Если вы объявили, например, строку char str1[5]; , то в дальнейшем вы не сможете написать str1=»abcd»; , компилятор просто выдаст ошибку. Если же вы объявили строку char* str1; , то вы со спокойной совестью можете дальше написать str1=»The solar system»;. Причем размер массива символов во втором случае может быть любым, он определится автоматически.

char str1[5]; str1="abcd"; //НЕЛЬЗЯ
char* str1; str1="The solar system" //Можно

Если вы все же хотите объявит строку первым способом, то нужно сразу ее заинициализировать:

char str[5] ="abcd";

Ввод строк с клавиатуры

Чтобы ввести строку с клавиатуры, использовать поток cin, который мы всегда используем для ввода чисел или символов, нельзя. Дело в том, что поток cin прекращает ввод строки после ввода пробела. К тому же cin может продолжать ввод элементов за пределами массива, если под строку отводится меньше места, чем вводится символов.

Вместо потока cin нужно использовать функцию getline . Она позволяет вводить заданное количество символов, включаю пробелы. Эта функция останавливает ввод, когда достигает числового предела или, когда читает символ новой строки (Enter).

Длина вводимой строки может быть меньше заданного количества символов. В общем виде обращение к функции записывается так:

имя входного потока.getline(строковая переменная, максимальное число символов+1);

Рассмотрим пример:
#include &ltiostream&gt using namespace std; void main() //Объявили строку длиной 40 символов cout//Вводим с клавиатуры нашу строку cout//Выводим для проверки строку на монитор cout

Примечание:

Разработчик сайта: Филатов Максим

Как ввести char c

При запуске программы на Си автоматически открываются ряд потоков, основными из которых являются следующие:

  • Стандартный поток ввода stdin
  • Стандартный поток вывода stdout
  • Стандартный поток вывода сообщений об ошибках stderr

Стандартный поток ввода stdin по умолчанию соответствует клавиатуре, а потоки stdout и stderr — экрану монитора.

Для управления вводом-выводом с помощью этих потоков используются ряд функций:

  • getchar() : ввод с клавиатуры одного символа
  • putchar() : вывод на консоль одного символа
  • fgets() : ввод одной строки
  • puts() / fputs() : вывод одной строки на консоль
  • scanf() : ввод с консоли с форматированием данных
  • sscanf() : ввод с из строки с форматированием данных
  • printf() : вывод с форматированием данных

Функции printf и scanf уже рассматривались ранее, поэтому посмотрим, как применять остальные функции.

Ввод и вывод символов

Для ввода и вывода символа применяются функции getchar() и putchar() . Но следует сказать, что на самом деле они полноценными функциями не являются, а определены как макросы в заголовочном файле stdio.h :

#define getchar() getc(stdin) #define putchar(c) putc((c), stdout)
Вывод символа

Для вывода отдельного символа на консоль предназначена функция putchar() со следующим прототипом:

int putchar(int c);

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

#include int main(void) < char c = 'A'; putchar(c); // Выводим символ A >
Ввод символа

Для ввода одного символа с клавиатуры применяется функция getchar() , которая имеет следующий прототип:

int getchar(void);

В качестве результата функция возвращает числовой код введенного символа.

При использовании функции getchar следует учитывать, что при печати текста посредством клавиатуры в буфер операционной системы заносятся коды печатаемых символов, а сами символы отображаются на экране. Поучение программой введенного символа из буфера производится с помощью нажатия клавиши Enter.

И если буфер операционной системы не пуст, то при вызове функции getc() она получает очередной символ из буфера. Если же буфер пуст, то происходит чтение байта из потока ввода с помощью системной функции, название которой зависит от операционной системы.

При этом при нажатии клавиши Enter, в буфер также помещается код этой клавиши. То есть если мы введем один символ и нажмем на Enter, в буфере окажутся два числовых кода — введенного символа и клавиши Enter. И это надо учитывать при работе с функцией getchar. В частости, рассмотрим простой, но показательный пример:

#include int main(void) < printf("1"); getchar(); // ожидание ввода символа printf("2"); getchar(); // ожидание ввода символа printf("3"); return 0; >

Сначала на экран выводится цифра 1, после чего функция getchar ожидает ввода символа. Если после ввода символа мы нажмем Enter, то в буфер будет помещены два числовых кода — введеного символа и клавиши Enter. Поэтому при втором вызове getchar эта функция считывает байт из буфера — то есть числовой код клавиши Enter.

Например, введем при первом вызове функции getchar символ «a», а затем Enter:

1a 23

Но если при каждом вызове getchar мы будем только нажимать клавишу Enter, тогда в буфер будет заноситься только код этой клавиши, и соответственно программа будет работать, как и ожидалось:

1 2 3

Применим функции getchar и putchar для ввода и вывода символов с клавиатуры:

#include int main(void) < int c; while((c=getchar())!=EOF) < putchar(c); >return 0; >

Функция getchar() считывает числовой код символа, который потом выводится в функции putchar() . Для вывода из программы необходимо ввести комбинацию клавиш Ctrl+C.

Ввод и вывод строк

Вывод строк и puts

Для вывода одной строки на консоль предназначена функция puts() со следующим прототипом:

int putchar(char *s);

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

При этом функция puts() будет выводить символы переданной строки, пока не дойдет до нулевого символа ‘\0’. Если же выводимый массив символов не содержит этого символа, то результат программы неопределен. Например:

#include int main(void) < puts("Hello World"); // выводим строковый литерал char* name = "Hello Metanit.com"; puts(name); // выводим значение переменной return 0; >
Hello World Hello Metanit.com
Вывод строк и fputs

Функция fputs() также записывает в поток вывода строку, то есть набор символов, который завершается символом ‘\0’. При записи строки нулевой символ ‘\0’ не записывается. Она имеет следующий прототип:

int fputs(const char *s, FILE *stream);

Первый параметр функции — записываемая строка, а второй — указатель на поток вывода. В качестве результата функция возвращает неотрицательное целое число. При ошибках в процессе записи возвращается значение EOF .

Применим функцию для записи в стандартный поток вывода, то есть на консоль. В этом случае в качестве второго параметра надо передать значение stdout :

#include int main(void)

Ввод строк и fgets

Для ввода строки с клавиатуры применяется функция fgets() , которая имеет следующий прототип:

char *fgets(char *str, int count, FILE *stream);
  • char *str : строка, в которую производится считывание.
  • int count : сколько символов необходимо считывать.
  • FILE *stream : файловый поток, из которого производится считывание. В качестве потока ввода может выступать и консольный ввод.

Функция fgets() прекращает считывание, когда пользователь нажимает клавишу ENTER, то есть когда в поток добавляется символ перевода строки.

Рассмотрим считывание строки с консоли. Для этого в качестве третьего параметра в функцию передается значение stdin :

#include #define MAX 15 int main(void)

Здесь функция fgets считывает не более 15 символов в строку name, а В реальности функция предложит ввести 14 символов, так как последний символ зарезервирован для нулевого символа ‘\0’. Если будет введено больше символов, то fgets все равно считает не более 15 символов. Таким образом функция позволяет проверить количество считываемых символов и поэтому считается безопасной.

Пример работы программы:

Enter name: Tom Smith Your name: Tom Smith

Стоит отметить, что функция fgets() возвращает указатель char * — указатель на буфер, в который считаны данные. В реальности это тот же самый буфер, который передавался в качестве первого параметра, то есть в примере выше — это массив name. Однако этот результат может нам пригодится для проверки успешности выполнения функции — если считывание прошло неудачно, то функция возвращает NULL :

#include #define MAX 15 int main(void) < char name[MAX]; printf("Enter name: "); if(fgets(name, MAX, stdin) != NULL) // if(fgets(name, MAX, stdin)) - можно сократить < printf("Your name: %s\n", name); >else < printf("Critical Error. "); >return 0; >

Для эмуляции ошибки можно передать в функцию вторым параметром число 0.

fgets и scanf

При использовании функции fgets() после функции scanf() мы можем столкнуться с некорректным вводом:

#include #define N 32 int main(void) < int age; char name[N]; // считываем возраст в переменную age printf("Input age: "); scanf("%d", &age); // считываем строку в переменну. name printf("Input name: "); fgets(name, N, stdin); // проверяем ввод printf("Age: %d\n", age); printf("Name: %s\n", name); >

В данном случае сначала с помощью функции scanf() считываем число в переменную age. После этого считываем имя — строку с помощью функции fgets() в переменную name. Но посмотрим, какой будет результат работы программы:

Input age: 39 Input name: Age: 39Name:

В данном случае мы видим, что ввод имени с помощью fgets вроде как пропускается. По крайней мере мы не можем ввести имя, а программа сразу же выводит результат.

Все дело в том, что функция scanf() считывает именно то, что ей предписано — число в виде переменной типа int. Все остальные символы остаются в буфере, в который предварительно попадают введенные с клавиатуры символы. Так, после ввода возраста мы нажимаем на клавишу Enter, и в буфер попадает символ «\n», то есть перевод строки. И fgets считывает этот символ из буфера, после чего ввод имени завершается. Очевидно, это не то поведение, на которое мы рассчитывали.

Чтобы исправить ситуацию, мы можем использовать различные хаки. Рассмотрим пару из них. Все они сводятся к тому, чтобы вынуть из буфера этот символ перевода строки.

Первый способ — считывание символа с помощью вызова scanf(«%*c») :

#include #define N 32 int main(void) < int age; char name[N]; // считываем возраст в переменную age printf("Input age: "); scanf("%d", &age); scanf("%*c"); // вытаскиваем символ из буфера // считываем строку в переменну. name printf("Input name: "); fgets(name, N, stdin); // проверяем ввод printf("Age: %d\n", age); printf("Name: %s\n", name); >

Второй способ — мы можем считать символ с помощью getchar() :

#include #define N 32 int main(void) < int age; char name[N]; // считываем возраст в переменную age printf("Input age: "); scanf("%d", &age); getchar(); // вытаскиваем символ из буфера // считываем строку в переменну. name printf("Input name: "); fgets(name, N, stdin); // проверяем ввод printf("Age: %d\n", age); printf("Name: %s\n", name); >

Результат работы программы:

Input age: 39 Input name: Tom Age: 39 Name: Tom

Чтение и запись символов

Простейшей из стандартных функций ввода/вывода на консоль является getchar(), читающая символ с клавиатуры, и putchar() печатающая символ на экран в текущей позиции курсора. Тем не неменее getchar() имеет некоторые существенные ограничения, описываемые ниже. Поэтому большую часть времени мы будем использовать getche(), когда будет потребность в чтении символа. Функцию getche() определила фирма Borland (в стандарте ANSI С ее нет). Хотя это довольно, типичное расширение, функция «может не поддерживаться в других средах. getche() ожидает нажатия клавиши, а затем возвращает значение. Нажатие клавиши также приводит к выводу символа на экран. Ниже показаны прототипы функций getche() и putchar():

int putchar(int cb);

Функция getche() возвращает нажатый символ. Функция putchar() возвращает cb в случае успеха или EOF — в случае ошибки. (EOF — это макроопределение, находящееся в stdio.h, означающее конец файла.) Хотя cb объявлена как целое, на экран выводится только младший байт. Аналогично, хотя getche() возвращает целое, только младший байт будет содержать символ, введенный с клавиатуры. Функция getche() требует заголовочный файл conio.h.

Следующая программа вводит символы с клавиатуры и выводит их в противоположном регистре. То есть прописные буквы будут выведены строчными, а строчные — прописными. Программа останавливается при обнаружении точки.

/* переключатель регистра */
#include
#include
#include
int main(void) char ch;
do ch = getche();
if(islower(ch)) putchar(toupper(ch));
else putchar (tolower(ch));
> while (ch!=’.’); /* использование точки для остановки */
return 0;
>

Существуют две важные альтернативы getche(). Первая — это getchar(), упомянутая ранее, являющаяся функцией ввода символов, определенная в ANSI С. Проблема, связанная с getchar(), заключается том, что она буферизирует ввод, пока не встретится возврат каретки. Причина этого заключается в системе ввода, реализованной в UNIX. В ней требуется ввести символ возврат каретки перед набором чего угодно, что требуется послать на компьютер. Для совместимости с UNIX многие компиляторы С включая Borland, имеют getchar() для такого ввода. Можно немного помучить данную функцию для лучшего понимания эффекта.

Следующей, более полезной вариацией getche() является getch(), которая действует подобно getche(), за тем исключением, что она не выводит символ на экран. Можно использовать этот факт для создания программ-розыгрышей ничего не подозревающих пользователей. Программа показанная ниже, выводит стандартную подсказку операционной системы и ожидает ввода. Каждый символ, вводимый пользователем, отображается следующей буквой алфавита. То есть «А» станет «В» и так далее. Для остановки программы нажмите CTRL-A.

/* данная программа выглядит так же, как подсказка командной строки. Она выводит подсказку, но каждый введенный пользователем символ заменяется на следующий символ алфавита*/

#include
#include
int main(void)
char ch;
do printf(«С:\»);
for(;;)
ch = getch(); /* чтение символов без эха */
if(ch==’\r’ || ch==1)
printf(«\n»);
break;
>
putchar(ch+1);
>
> while(ch!=1); /* выход no control-A */
return 0;
>

Хотя эта программа не имеет никаких применений, кроме шуток, функция getch() имеет достаточно широкое применение. Например, ее можно использовать для ввода пароля без вывода символов на экран.

Ввод и вывод символьных строк в Си

Итак, строки в языке Си. Для них не предусмотрено отдельного типа данных, как это сделано во многих других языках программирования. В языке Си строка – это массив символов. Чтобы обозначить конец строки, используется символ ‘\0’ , о котором мы говорили в прошлой части этого урока. На экране он никак не отображается, поэтому посмотреть на него не получится.

Создание и инициализация строки

Так как строка – это массив символов, то объявление и инициализация строки аналогичны подобным операциям с одномерными массивами.

Следующий код иллюстрирует различные способы инициализации строк.

char str[10]; char str1[10] = ; char str2[10] = "Hello!"; char str3[] = "Hello!";

Объявление и инициализация строк

Рис.1 Объявление и инициализация строк

В первой строке мы просто объявляем массив из десяти символов. Это даже не совсем строка, т.к. в ней отсутствует нуль-символ \0 , пока это просто набор символов.

Вторая строка. Простейший способ инициализации в лоб. Объявляем каждый символ по отдельности. Тут главное не забыть добавить нуль-символ \0 .

Третья строка – аналог второй строки. Обратите внимание на картинку. Т.к. символов в строке справа меньше, чем элементов в массиве, остальные элементы заполнятся \0 .

Четвёртая строка. Как видите, тут не задан размер. Программа его вычислит автоматически и создаст массив символов нужный длины. При этом последним будет вставлен нуль-символ \0 .

Как вывести строку

Дополним код выше до полноценной программы, которая будет выводить созданные строки на экран.

#include int main(void) < char str[10]; char str1[10] = ; char str2[10] = "Hello!"; char str3[] = "Hello!"; for(int i = 0; i

Различные способы вывода строки на экран

Рис.2 Различные способы вывода строки на экран

Как видите, есть несколько основных способов вывести строку на экран.

  • использовать функцию printf со спецификатором %s
  • использовать функцию puts
  • использовать функцию fputs , указав в качестве второго параметра стандартный поток для вывода stdout .

Единственный нюанс у функций puts и fputs . Обратите внимание, что функция puts переносит вывод на следующую строку, а функция fputs не переносит.

Как видите, с выводом всё достаточно просто.

Ввод строк

С вводом строк всё немного сложнее, чем с выводом. Простейшим способом будет являться следующее:

#include int main(void)

Функция gets приостанавливает работу программы, читает строку символов, введенных с клавиатуры, и помещает в символьный массив, имя которого передаётся функции в качестве параметра.
Завершением работы функции gets будет являться символ, соответствующий клавише ввод и записываемый в строку как нулевой символ.
Заметили опасность? Если нет, то о ней вас любезно предупредит компилятор. Дело в том, что функция gets завершает работу только тогда, когда пользователь нажимает клавишу ввод. Это чревато тем, что мы можем выйти за рамки массива, в нашем случае — если введено более 20 символов.
К слову, ранее ошибки переполнения буфера считались самым распространенным типом уязвимости. Они встречаются и сейчас, но использовать их для взлома программ стало гораздо сложнее.

Итак, что мы имеем. У нас есть задача: записать строку в массив ограниченного размера. То есть, мы должны как-то контролировать количество символов, вводимых пользователем. И тут нам на помощь приходит функция fgets :

#include int main(void)

Функция fgets принимает на вход три аргумента: переменную для записи строки, размер записываемой строки и имя потока, откуда взять данные для записи в строку, в данном случае — stdin . Как вы уже знаете из 3 урока, stdin – это стандартный поток ввода данных, обычно связанный с клавиатурой. Совсем необязательно данные должны поступать именно из потока stdin , в дальнейшем эту функцию мы также будем использовать для чтения данных из файлов.

Если в ходе выполнения этой программы мы введем строку длиннее, чем 10 символов, в массив все равно будут записаны только 9 символов с начала и символ переноса строки, fgets «обрежет» строку под необходимую длину.

Обратите внимание, функция fgets считывает не 10 символов, а 9 ! Как мы помним, в строках последний символ зарезервирован для нуль-символа.

Давайте это проверим. Запустим программу из последнего листинга. И введём строку 1234567890 . На экран выведется строка 123456789 .

Пример работы функции fgets

Рис.3 Пример работы функции fgets

Возникает вопрос. А куда делся десятый символ? А я отвечу. Он никуда не делся, он остался в потоке ввода. Выполните следующую программу.

#include int main(void)

Вот результат её работы.

Непустой буфер stdin

Рис.4 Непустой буфер stdin

Поясню произошедшее. Мы вызвали функцию fgets . Она открыла поток ввода и дождалась пока мы введём данные. Мы ввели с клавиатуры 1234567890\n ( \n я обозначаю нажатие клавиша Enter ). Это отправилось в поток ввода stdin . Функция fgets , как и полагается, взяла из потока ввода первые 9 символов 123456789 , добавила к ним нуль-символ \0 и записала это в строку str . В потоке ввода осталось ещё 0\n .

Далее мы объявляем переменную h . Выводим её значение на экран. После чего вызываем функцию scanf . Тут-то ожидается, что мы можем что-то ввести, но т.к. в потоке ввода висит 0\n , то функция scanf воспринимает это как наш ввод, и записывается 0 в переменную h . Далее мы выводим её на экран.

Это, конечно, не совсем такое поведение, которое мы ожидаем. Чтобы справиться с этой проблемой, необходимо очистить буфер ввода после того, как мы считали из него строку, введённую пользователем. Для этого используется специальная функция fflush . У неё всего один параметр – поток, который нужно очистить.

Исправим последний пример так, чтобы его работа была предсказуемой.

#include int main(void) < char str[10]; fgets(str, 10, stdin); fflush(stdin); // очищаем поток ввода puts(str); int h = 99; printf("do %d\n", h); scanf("%d",&h); printf("posle %d\n", h); return 0; >

Теперь программа будет работать так, как надо.

Сброс буфера stdin функцией fflush

Рис.4 Сброс буфера stdin функцией fflush

Подводя итог, можно отметить два факта. Первый. На данный момент использование функции gets является небезопасным, поэтому рекомендуется везде использовать функцию fgets .

Второй. Не забывайте очищать буфер ввода, если используете функцию fgets .

На этом разговор о вводе строк закончен. Идём дальше.

Сохрани в закладки или поддержи проект.

Практика

Решите предложенные задачи:

Для удобства работы сразу переходите в полноэкранный режим

Исследовательские задачи для хакеров

  1. Проверьте как ведет себя ваш компилятор в случае переполнения буфера.

Дополнительные материалы

  1. пока нет

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *