Как прочитать строку с клавиатуры

Обновлено: 17.05.2024

Я хочу прочитать строку, введенную пользователем. Я не знаю длины веревки. Поскольку в C нет строк, я объявил указатель:

и использовать scanf для чтения ввода с клавиатуры:

но у меня ошибка сегментации.

как я могу прочитать ввод с клавиатуры в C, когда длина неизвестна ?

у вас нет хранилища, выделенного для word - это просто оборванных указатель.

обратите внимание, что 256-произвольный выбор здесь-размер этого буфера должен быть больше, чем максимально возможная строка, с которой вы можете столкнуться.

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

Я не понимаю, почему есть рекомендация использовать scanf() здесь. scanf() безопасно только при добавлении параметров ограничения в строку формата-например, %64s или так.

гораздо лучший способ-использовать char * fgets ( char * str, int num, FILE * stream ); .

при чтении ввода из любого файла (включая stdin) , где вы не знаете длину, часто лучше использовать getline , а не scanf или fgets , потому что getline будет обрабатывать выделение памяти для вашей строки автоматически, пока вы предоставляете нулевой указатель для получения введенной строки. Этот пример иллюстрирует:

задание line to NULL заставляет getline выделять память автоматически. Пример вывода:

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

input: прочитайте строку
ouput: печать строки

этот код выводит строку с пробелами, как показано выше.

вам нужно иметь указатель, чтобы указать где-то, чтобы использовать его.

попробуйте этот код:

это создает массив символов lenth 64 и считывает входные данные. Обратите внимание, что если входные данные длиннее 64 байт, массив слов переполняется, и ваша программа становится ненадежной.

Как указал Йенс, было бы лучше не использовать scanf для чтения строк. Это было бы безопасным решением.

В программе строки могут определяться следующим образом:

  • как строковые константы;
  • как массивы символов;
  • через указатель на символьный тип;
  • как массивы строк.

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

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

Строковые константы размещаются в статической памяти. Начальный адрес последовательности символов в двойных кавычках трактуется как адрес строки. Строковые константы часто используются для осуществления диалога с пользователем в таких функциях, как printf() .

При определении массива символов необходимо сообщить компилятору требуемый размер памяти.

Компилятор также может самостоятельно определить размер массива символов, если инициализация массива задана при объявлении строковой константой:

char m2[]= "Горные вершины спят во тьме ночной." ;
char m3[]=< 'Т','и','х','и','е',' ','д','о','л','и','н','ы',' ','п','о','л','н','ы',' ','с','в','е','ж','е','й',' ','м','г','л','о','й','\0' >;

В этом случае имена m2 и m3 являются указателями на первые элементы массивов:


При объявлении массива символов и инициализации его строковой константой можно явно указать размер массива, но указанный размер массива должен быть больше, чем размер инициализирующей строковой константы:

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

В этом случае объявление массива переменной m4 может быть присвоен адрес массива:

m4 = m3;
*m4 эквивалентно m3[0]= 'Т'
*(m4+1) эквивалентно m3[1]= 'и'

Здесь m3 является константой-указателем. Нельзя изменить m3 , так как это означало бы изменение положения (адреса) массива в памяти, в отличие от m4 .

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

Массивы символьных строк

Иногда в программах возникает необходимость описание массива символьных строк . В этом случае можно использовать индекс строки для доступа к нескольким разным строкам.

Инициализация выполняется по правилам, определенным для массивов.
Тексты в кавычках эквивалентны инициализации каждой строки в массиве. Запятая разделяет соседние
последовательности.
Кроме того, можно явно задавать размер строк символов, используя описание, подобное такому:

Разница заключается в том, что такая форма задает «прямоугольный» массив, в котором все строки имеют одинаковую длину.

Массив строк

Свободный массив


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

Операции со строками

Большинство операций языка Си, имеющих дело со строками, работает с указателями. Для размещения в оперативной памяти строки символов необходимо:

  • выделить блок оперативной памяти под массив;
  • проинициализировать строку.

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

Функции ввода строк

Для ввода строки может использоваться функция scanf() . Однако функция scanf() предназначена скорее для получения слова, а не строки. Если применять формат "%s" для ввода, строка вводится до (но не включая) следующего пустого символа, которым может быть пробел, табуляция или перевод строки.

Для ввода строки, включая пробелы, используется функция

В качестве аргумента функции передается указатель на строку, в которую осуществляется ввод. Функция просит пользователя ввести строку, которую она помещает в массив, пока пользователь не нажмет Enter.

Функции вывода строк

Для вывода строк можно воспользоваться рассмотренной ранее функцией

или в сокращенном формате

Для вывода строк также может использоваться функция

которая печатает строку s и переводит курсор на новую строку (в отличие от printf() ). Функция puts() также может использоваться для вывода строковых констант, заключенных в кавычки.

Функция ввода символов

Для ввода символов может использоваться функция

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

Функция вывода символов

Для вывода символов может использоваться функция

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

Пример Посчитать количество введенных символов во введенной строке.

Количество введенных символов в строке

Результат выполнения

Ввод строки в консольном приложении для пользователя не представляет особых сложностей - он просто печатает необходимое количество знаков и нажимает ENTER.

А вот для начинающего программиста на С++ всё может оказаться не так просто и привести к потере времени и сил на решение простой задачи. Зачем эта заморочка существует в С++, лично мне вообще непонятно. Но она существует. И заключается она в следующем.

Строка с пробелами не читается

Точнее, не читается она привычным для С++ способом. Например, если у вас есть переменная str , то вы можете попытаться прочитать в эту переменную строку, введённую пользователем:

И всё будет прекрасно работать, если пользователь введёт строку БЕЗ пробелов. Однако вас ждёт неприятность, если во вводимой строке будут пробелы. Например, если пользователь введёт:

100 200 300

то в переменной str после выполнения инструкции cin >> str; будет только 100 . То есть строка будет прочитана ТОЛЬКО до первого пробела.

Строка читается только до пробела

ЛИРИЧЕСКОЕ ОТСТУПЛЕНИЕ
Вот за это я и не люблю С++. Ну зачем, спрашивается, так было делать?

Но отбросим лирику в сторону, и разберёмся, что же нам в этом случае делать?

А надо просто использовать другой способ. Например, такой:

В этом случае всё будет работать как надо:

Как прочитать строку полностью

Однако если вы думаете, что на этом ваши неприятности закончились, то зря. Это же С++. А не какой-нибудь Паскаль для лохов. У меня вообще иногда возникает подозрение, что создатель С++ преследовал цель не придумать мощный язык, а сделать так, чтобы программировать на нём могли только избранные. Иначе нафига в этом языке столько заморочек?

Итак, вот вам следующий нежданчик:

Здесь мы используем getline() , которая может читать целую строку (в том числе и с пробелами). Но, как вы думаете, сможем ли мы прочитать эту строку в этой программе?

Наверняка вы уже почувствовали подвох. И заключается он в том, что в этой программе вы не сможете прочитать строку str .

Но что же произойдёт? А то, что в переменную str запишется недочитанный буфер ввода, то есть строка " 200 300" , и мы не сможем ввести новую строку.

Почему так? Потому что первый раз строка была прочитана не полностью, а только до первого пробела. Оставшиеся же символы остались в буфере, и новая строка не может быть введена, пока буфер полностью не прочитан.

Поэтому перед тем, как вводить новую строку, нам надо либо прочитать буфер до конца, либо очистить его.

Пробежаться до конца буфера можно, например, так:

Очистить буфер ввода cin можно, например, так:

то есть программа может быть примерно такой:

Ну что же, теперь, надеюсь, вы представляете, как пользователю ввести строку с пробелами в С++, и эта задачка не поставит вас в тупик.

Как ввести строку с пробелами через cin

Строку с пробелами можно ввести и привычным способом через cin , но для этого потребуется несколько переменных:

В этом случае вывод будет таким:

Как ввести строку с пробелами через cin

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

На этом пока всё. Изучайте С++. Конечно, это далеко не самый простой язык. Но, с другой стороны, его изучение доставит вам много радости от неожиданных открытий, которых вы никогда не найдёте в более простых языках.

Так что я, например, использую Паскаль для работы (когда требуется сделать быстро и без лишних заморочек), а С++ для удовольствия, когда хочется немного помучиться, а результат и сроки не висят над тобой как Дамоклов меч…


В предыдущих лекциях мы познакомились с командами вывода на экран. Для этого мы использовали объект System.out , и его методы print() и println() . Просто и удобно.

Но, как вы уже наверное догадываетесь, одного вывода на экран недостаточно. Цель большинства программ — сделать что-то полезное для пользователя. Поэтому очень часто нужно, чтобы пользователь мог вводить данные с клавиатуры.

Как и для вывода, для ввода данных тоже есть специальный объект — System.in . Но, к сожалению для нас, он не настолько удобен, как нам бы хотелось. Этот объект позволяет считывать данные с клавиатуры по одному символу за раз.

Поэтому мы воспользуемся еще одним классом, который в паре с объектом System.in даст нам все, что нужно. В Java уже давно есть классы на все случаи жизни. С одним из них мы сейчас и познакомимся.

2. Класс Scanner

Считывание с клавиатуры с помощью объекта типа Scanner будет выглядеть примерно так:

Код Пояснение
Создаем объект класса Scanner .
Читаем с клавиатуры строку текста .
Читаем с клавиатуры число .

Выглядит вроде несложно, но так ли все просто на самом деле?

Думаю, у вас появилась куча вопросов, и сейчас мы на них ответим.

Но для начала продемонстрируем пример полной программы, где используется класс Scanner :

3. Создание объекта Scanner

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

Вспомним, как мы обычно создаем переменную с текстом:

Сначала мы пишем тип переменной ( String ), затем ее имя ( str ) и, наконец, после знака равно пишем значение.

В нашей странной строке на самом деле все то же самое:

Объявление и инициализация переменной типа Scanner

Все, что находится слева от знака равно — это объявление переменной типа Scanner по имени console . Можно было назвать ее, например, s или scanner , или даже keyboard . Тогда код выглядел бы так:

Думаю, теперь все стало гораздо понятнее.

А код, что находится справа от знака равно , немного сложнее. Имеется в виду new Scanner(System.in); Но тут тоже ничего космического.

В этом коде мы говорим Java-машине: создай новый объект (слово new ) типа Scanner и передай в него в качестве параметра то, из чего новосозданный объект Scanner будет брать данные — объект System.in .

После выполнения всей этой строки у нас появится переменная по имени console типа Scanner , с помощью которой наша программа сможет считывать данные с клавиатуры.

4. Вызов методов

В приведенном выше примере наша переменная console типа Scanner хранила у себя внутри ссылку на объект типа Scanner .

Чтобы вызвать методы объекта, на который ссылается переменная, нужно после имени переменной написать точку, а затем имя метода и параметры. Общий вид этой команды такой:

Вызов метода объекта, на который ссылается переменная

Если вы не планируете передавать в функцию параметры, нужно писать просто пустые скобки:

5. Ввод данных с консоли

Вводить данные с клавиатуры, когда у нас есть объект типа Scanner , очень легко.

Чтобы считать с клавиатуры строку , нужна команда:

Когда программа дойдет до выполнения этой строки, она приостановится и будет ждать, пока пользователь введет данные и нажмет клавишу enter. После этого все, что ввел пользователь, будет сохранено в переменную str .

Чтобы считать с клавиатуры число , нужна команда:

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

Если пользователь ввел данные, которые невозможно преобразовать в целое число, в программе возникнет ошибка, и она завершится.

Чтобы считать с клавиатуры дробное число , нужна команда:

Эта команда полностью аналогична команде nextInt() , только она проверяет, что введенные данные можно преобразовать в число double .

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

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

Считай с клавиатуры три строки. А затем: 1. Выведи на экран третью строку в неизменном виде. 2. Выведи на экран вторую строку, предварительно преобразовав ее к верхнему регистру. 3. Выведи на экран первую строку, предварительно преобразовав ее к нижнему регистру. Пример ввода: Строка Номер РАЗ Втор Считай с клавиатуры три целых числа. Выведи на экран их среднее арифметическое. Пример ввода: 50 101 201 Пример вывода: 117 Среднее арифметическое - это число, равное сумме всех чисел, деленной на их количество. Используй деление без остатка.

6. Другие методы класса Scanner

Это, кстати, были не все методы класса Scanner . Полный список будет выглядеть примерно так:

Метод Описание
Считывает данные и преобразует их в тип byte
Считывает данные и преобразует их в тип short
Считывает данные и преобразует их в тип int
Считывает данные и преобразует их в тип long
Считывает данные и преобразует их в тип float
Считывает данные и преобразует их в тип double
Считывает данные и преобразует их в тип boolean
Считывает одно «слово». Слова разделяются пробелами или enter
Считывает целую строку

Есть еще методы, которые позволяют проверить тип еще не считанных данных (чтобы знать, каким методом их считывать).

Метод Описание
Там тип byte ? Его можно будет преобразовать к byte ?
Там тип short ? Его можно будет преобразовать к short ?
Там тип int ? Его можно будет преобразовать к int ?
Там тип long ? Его можно будет преобразовать к long ?
Там тип float ? Его можно будет преобразовать к float ?
Там тип double ? Его можно будет преобразовать к double ?
Там тип boolean ? Его можно будет преобразовать к boolean ?
Там есть еще одно слово?
Там есть еще одна строка?

7. Ввод данных из строки

Мы уже говорили выше, что класс Scanner умеет считывать данные из разных источников. И один из этих источников — строка текста .

Читайте также: