Студопедия
Главная страница | Контакты | Случайная страница

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатика
ИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханика
ОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторика
СоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансы
ХимияЧерчениеЭкологияЭкономикаЭлектроника

Ввод-вывод чисел, символов и строк на консоль. Переключение ввода-вывода, работа с файлами.

Читайте также:
  1. A) Плавно или с помощью кнопок- строки заголовка.
  2. D триггеры, работающие по фронту.
  3. I.3. Строки и столбцы
  4. II. Поработать с лекционным материалом по теме занятия, выучить глоссарий.
  5. II. Работа с акварелью, гуашью, восковыми мелками, школьным мелом
  6. III. Работа по теме.
  7. III. Работа с природным материалом
  8. IV. Контрольная работа №1.
  9. IV. Работа с тканью, нитками
  10. IV. Совместное открытие знаний. Работа в парах.

Под функциями ввода-вывода подразумеваются функции, которые выполняют транспортировку данных в программу и из нее. Мы уже использовали две такие функции: printf() и scanf(). Теперь рассмотрим несколько других возможностей, предоставляемых языком Си.

Функции ввода-вывода не входят в определение языка Си. Их разработка возложена на программистов, реализующих компилятор с языка Си. С другой стороны, выгода использования стандартного набора функций ввода-вывода на всех системах очевидна. Это дает возможность писать переносимые программы, которые легко можно применять на разных машинах. В языке Си имеется много функций ввода-вывода такого типа, например printf() и scanf(). Ниже мы рассмотрим функции getchar() и putchar().

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

Функция getchar() получает один символ, поступающий с пульта терминала (и поэтому имеющий название), и передает его выполняющейся в данной момент программе. Функция putchar() получает один символ, поступающий из программы, и пересылает его для вывода на экран. Рассмотрим пример программы, которая принимает один символ с клавиатуры, и выводит его на экран:

/*ввод-вывод*/

#include <stdio.h>

main()

{

char ch;

ch=getchar(); /***1***/

putchar(ch); /***2***/

}

Для большинства систем спецификации функции getchar и putchar содержатся в системном файле stdio.h, поэтому мы указали данный файл в программе. Функция getchar() аргументов не имеет, т.е. при ее вызове в круглые скобки не помещается никакая величина. Она просто получает очередной поступающий символ, и сама возвращает его значение выполняемой программе. Оператор, приведенный в строке 1, присваивает значение функции getchar() переменной ch. Функция putchar() имеет один аргумент. При ее вызове необходимо в скобках указать символ, который требуется вывести на печать. Аргументом может быть одиночный символ (включая знаки, представляемые управляющими последовательностями), переменная или функция, значением которой является одиночный символ. Правильным обращением к функции putchar() является указание любого из этих аргументов при ее вызове:

putchar('D');

putchar('\n');

putchar('\007');

putchar(ch); /* переменная типа char */

putchar(getchar());

Модифицируем нашу программу:

#include <stdio.h>

main()

{

putchar(getchar());

}

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

Буферы

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

Зачем нужны буферы? Во-первых, оказывается, что передачу нескольких символов в виде одного блока можно осуществить гораздо быстрее, чем передавать их последовательно по одному. Во-вторых, если при вводе символов допущена ошибка, мы сможем воспользоваться корректирующими средствами терминала, чтобы ее исправить. И когда мы нажмем клавишу Enter, будет произведена передача откорректированной строки. Однако, для некоторых диалоговых программ небуферизованный ввод может оказаться приемлемым. Например, в программах обработки текстов было бы желательно, чтобы каждая команда вводилась, как только мы нажимаем соответствующую клавишу. Поэтому как буферизованный, так и небуферизованный ввод имеет свои достоинства.

Рассмотрим вывод на печать групп символов. Желательно, чтобы в любой момент можно было остановить работу программы. Для этого напишем программу так, чтобы она прекращала работу при получении какого-нибудь специального символа, например "!":

/* ввод-вывод */

/* ввод и печать символов до поступления

завершающего символа */

#include <stdio.h>

#define STOP '!' /*дает символу '!' символическое имя */

main()

{

char ch;

ch=getchar(); /***9***/

while(ch!= STOP) { /***10***/

putchar(ch); /***11***/

ch=getchar(); /***12***/

}

}

В данном примере при первом прохождении тела цикла функция putchar() получает значение своего аргумента в результате выполнения оператора, расположенного в строке 9. В дальнейшем, вплоть до завершения работы цикла, значением этого аргумента является символ, передаваемый программе функцией getchar, расположенной в строке 12. Цикл while будет осуществлять чтение и печать символов до тех пор, пока не поступит признак STOP.

!

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

/* ввод-вывод */

#include <stdio.h>

#define STOP '!'

main()

{

char ch;

while ((ch=getchar())!= STOP) /***8***/

putchar(ch);

}

Одна строка 8 этой программы заменяет строки 9, 10, 12 предыдущей программы.

 

 

Чтение одной строки

Усложним пример ввода-вывода:

/* подсчет символов */

#include <stdio.h>

#define STOP!

main()

{

char ch;

/*инициализация счетчика символов 0 */

int count = 0;

while ((ch=getchar())!= STOP) {

putchar(ch);

count++; /* прибавить 1 к счетчику */

}

printf("\n Всего было прочитано %d символа.\n",

count);

}

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

Заменим признак окончания ввода данных, используем символ новая строка \n. Для этого нужно переопределить признак STOP:

#define STOP '\n'

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

На экране тридцать четыре символа.[Enter]

В ответ на экране появятся следующие строки:

На экране тридцать четыре символа.

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

Чтение файла

Если нам нужно читать большие порции данных, например из файла, каким должен быть признак STOP? Это должен быть такой символ, который обычно не используется в тексте и, следовательно, не приводит к ситуации, когда он случайно встретится при вводе, и работа программы будет остановлена раньше, чем бы мы хотели. Файлом можно назвать участок памяти, в который помещена некоторая информация. Обычно файл хранится в некоторой долговременной памяти, например на гибких или жестких дисках или на магнитной ленте. Чтобы отмечать, где кончается один файл и начинается другой, полезно иметь специальный символ, указывающий на конец файла, чтобы отмечать конец файла и начинать другой. Это должен быть символ, который не может появиться где- то в середине файла. Решением указанной проблемы служит введение специального признака, называемого "End-of-File", конец файла, или EOF. Выбор конкретного признака EOF зависит от типа системы. Он может состоять даже из нескольких символов. Обычно определение EOF содержится в файле <stdio.h>. Общеупотребительным является определение

#define EOF (-1)

Пример:

/* ввод-вывод_ф */

#include <stdio.h>

main()

{

int ch;

while ((ch = getchar())!= EOF)

putchar(ch);

}

Это надо помнить:

Не нужно самим определять признак EOF. Он описан в файле <stdio.h>.

Мы можем не интересоваться фактическим значением символа EOF, поскольку директива #define, имеющаяся в файле <stdio.h>, позволяет нам использовать его символическое представление.

Мы изменили в нашей программе тип переменной ch с char на int. Это мы сделали, потому что значением переменных типа char является целое без знака в диапазоне от 0 до 255, а признак EOF может иметь числовое значение -1. Эта величина недопустима для переменной типа char. Функция getchar() фактически возвращает значение типа int, поэтому она в состоянии прочесть символ EOF.

Переменная ch целого типа никак не может повлиять на работу функции putchar(). Она просто выводит на печать символьный эквивалент значения аргумента.

При работе с данной программой, когда символы вводятся с клавиатуры, необходимо уметь вводить признак EOF. В большинстве реализаций операционной системы UNIX, например, ввод [CTRL/d] (нажать на клавишу [d], держа нажатой клавишу [CTRL] интерпретируется как признак EOF. Во многих микрокомпьютерах для той же цели используется знак [CTRL/z].

 

Пусть мы ввели фразу с клавиатуры. Приведем результат работы программы "ввод-вывод_ф" в системе, с буферизованным вводом:

Спрос на высокопрофессиональных ИТ-специалистов

Спрос на высокопрофессиональных ИТ-специалистов

растет как со стороны государственных, так и

частных компаний растет как со стороны

государственных, так и частных компаний

[CTRL/z]

Каждый раз при нажатии клавиши Enter производится обработка символов, попавших в буфер, и копия строки выводится на печать. Это продолжается до тех пор, пока мы не введем признак EOF. Программа "ввод-вывод_ф" осуществляет вывод на экран символов независимо от того, откуда они поступают. Наша программа могла бы просматривать содержимое файлов, создавать новые файлы и получать копии файлов. Решение этих проблем - в управлении вводом и выводом.

 

Переключение и работа с файлами

Понятие ввода-вывода включает в себя функции, данные и устройства. Рассмотрим, например, программу "ввод-вывод_ф". В ней используется функция getchar(), осуществляющий ввод, причем устройство ввода - клавиатура (в соответствии с нашими предположениями), а выходные данные - отдельные символы. Изменим источник поступления в программу данных. По умолчанию Си-программа рассматривает стандартный ввод как источник поступления данных. Стандартным вводом называется устройство, принятое в качестве обычного средства ввода данных в машину. Это может быть устройство чтения данных с магнитной ленты телетайпа или терминал. Мы можем сами выбирать устройство данных из любого источника. Ну, например, мы можем написать в программе, что источник входных данных - файл, а не клавиатура.

Существуют два способа написания программ, работающих с файлами. Первый способ заключается в явном использовании специальных функций, которые открывают и закрывают файлы, организуют чтение и запись данных и т.д. Этот вопрос мы будем обсуждать в 15 лекции. Второй способ состоит в том, чтобы использовать программу, спроектированную первоначально в предположении, что данные в нее вводятся с клавиатуры и выводятся на экран, но переключить ввод и вывод на другие информационные каналы, например, из файла в файл. Этот способ в некоторых отношениях обладает меньшими возможностями, чем первый, но зато гораздо проще в использовании. Операция переключения - это средство OC UNIX, а не самого языка Си. Но она оказалась настолько полезной, что при переносе компилятора с языка Си на другие вычислительные системы часто вместе с ним переносится и эта операция. Многие из вновь созданных операционных р_ систем, таких, как MS-DOS 2, включают в себя данное средство. Сначала мы обсудим возможности этой операции в OC UNIX, а за тем и в других системах.

Переключение вывода. Предположим, мы осуществили компиляцию программы "ввод-вывод_ф" и поместили выполняемый объектный код в файл с именем get_put. Затем, чтобы запустить данную программу, мы вводим с терминала только имя файла

get_put

и программа выполняется так, как было описано выше, т.е. получает в качестве входных данных символы, вводимые с клавиатуры. Теперь предположим, что мы хотим посмотреть, как наша программа работает с текстовым файлом с именем words. Текстовый файл - это файл, содержащий некоторый текст, т. е. данные в виде символов. Это может быть, например, рассказ или программа на языке Си. Файл, содержащий команды на машинном языке, не является текстовым. Так как наша программа занимается обработкой символов, то она должна использоваться вместе с текстовым файлом. Для этого надо ввести следующую команду:

get_put < words

Символ < служит обозначением операции переключения, используемой в OC UNIX. Выполнение указанной операции приводит к тому, что содержимое файла words будет направлено в файл с именем get_put. Сама программа "ввод-вывод_ф" не знает, что входные данные поступают из некоторого файла, а не с терминала. На ее вход просто поступает поток символов, она читает их, и последовательно, по одному, выводит на печать до тех пор, пока не встретит признак EOF. Если мы наберем команду

get_put < words

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

Анализ данных, прогнозы, организация связи,

создание программного обеспечения, построение

моделей процессов - вот далеко неполный список

областей применения знаний для компьютерных

специалистов.

если этот текст находится в текстовом файле words.

Переключение ввода

Теперь рассмотрим случай, когда нам нужно ввести текст с клавиатуры в файл с именем my_words. Для этого мы должны ввести команду

get_put > my_words

и начать ввод символов. Символ > служит обозначением операции переключения, используемой в OC UNIX. Ее выполнение приводит к тому, что создается новый файл с именем my_words, а затем результат работы программы "ввод-вывод_ф", представляющий собой копию вводимых символов, направляется в данный файл. Если файл с именем my_words уже существует, он обычно уничтожается, и вместо него создается новый. На экране появляются вводимые слова. Их копии будут направлены в указанный файл. Чтобы закончить работу, мы вводим EOF, в OC UNIX это обычно [CTRL/d].

Комбинированное переключение

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

get_put < my_words > my_words2

и требуемое задание будет выполнено.

Команда

get_put > my_words2 < my_words

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

Операционные системы, отличные от OC UNIX

 

Оператор ветвления, многовариантный выбор.

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

Отличительной особенностью всех этих операторов является то, что в них вычисляется некоторое выражение, называемое условием, и в зависимости от его истинности или ложности выполняются или не выполняются операторы некоторого блока. Это означает, что выражения условия во всех операторах ветвления вычисляются в булевом контексте.

Самая простейшая форма оператора ветвления if представлена следующей синтаксической конструкцией:

if (ВЫРАЖЕНИЕ) БЛОК

Ее семантика такова — если ВЫРАЖЕНИЕ истинно, то выполняются операторы блока БЛОК, в противном случае он просто пропускается, например:

if ($var == "print") {

print "Переменная \$text = $text";

}

ВНИМАНИЕ Еще раз напомним читателю тот факт, что все составные операторы определяются в терминах блоков, задаваемых с помощью фигурных скобок, поэтому даже если в блоке содержится один оператор, он должен быть заключен в фигурные скобки. Такой синтаксис составных операторов Perl может оказаться не совсем привычным для программистов на языке С, в котором фигурные скобки в случае одного оператора в блоке не обязательны.

Обычно выражение условия представляет собой сложное выражение, составленное из операций отношения, связанных логическими операциями. Однако в Perl в качестве выражения-условия операторов if можно использовать любое выражение, а не только булево, возвращающее «истину» или «ложь». Результат вычисления такого «выражения-условия» в этих операторах просто интерпретируется в булевом контексте по следующей схеме: если вычисленное значение равно 0, "0" или пустой строке "", то оно трактуется как «ложь», иначе — «истина».

В связи со сказанным мы можем написать следующий оператор, который напечатает введенную пользователем строку, если только она не является пустой или состоящей из одного нуля (только строка "0" трактуется как «ложь»):

if (substr $var = <>, 0, length($var)-l) {

print "Ввели $var";

}

Интерес здесь представляет выражение-условие. Функция substr() выделяет из первого строкового параметра, начиная с позиции, определяемой вторым параметром, подстроку длины, определяемой третьим параметром. Первым параметром этой функции в нашем случае является введенная пользователем строка. Из нее, начиная с самого первого символа, выделяется подстрока на единицу меньшей длины, чем ввел пользователь. Такие действия необходимы для исключения из переменной $var символа перехода на новую строку, который автоматически включается в нее при вводе со стандартного устройства ввода (операция <>), когда пользователь завершает ввод нажатием клавиши Enter, Результатом выполнения указанной операции будет именно та последовательность символов, которую вводил пользователь, хотя в самой переменной $var символ перехода на новую строку будет сохранен. В этом можно убедиться, добавив в блок еще один оператор печати. Его вывод будет осуществляться уже на новой строке после вывода предыдущего оператора print.

Вторая форма оператора if используется, когда необходимо выполнить одну группу операторов (БЛОК1) в случае истинности некоторого выражения (ВЫРАЖЕНИЕ), а в случае его ложности — другую группу операторов (БЛОК2):

if (ВЫРАЖЕНИЕ) БЛОК1 else БЛОК2

По существу, первая форма оператора if эквивалентна второй форме, если БЛОК2 не содержит ни одного оператора.

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

if (ВЫРАЖЕНИЕ1) БЛОК1 [elsif (ВЫРАЖЕНИЕ2) БЛОК2]... [else БЛОКn]

ПРИМЕЧАНИЕ Квадратные скобки используются исключительно для обозначения необязательности конструкции, а многоточие показывает, что заключенная в квадратные скобки стоящая перед ними конструкция может повторяться многократно. Таким образом, квадратные скобки не являются частью синтаксиса многовариантного оператора if.

Семантика этого оператора такова. Выполняются операторы блока БЛОК1, если истинно ВЫРАЖЕНИЕ1. Если оно ложно, то выполняются операторы блока БЛОК2 в случае истинности выражения ВЫРАЖЕНИЕ2 из конструкции elseif. Если и оно ложно, то проверяется выражение ВЫРАЖЕНИЕЗ из следующей конструкции elseif и т. д. Если ни одно из выражений-условий оператора if не истинно, то в случае наличия конструкции el se выполняются операторы ее блока, иначе выполняется следующий после оператора if оператор программы. Например, при выполнении приводимого ниже оператора многовариантного ветвления if:

if($var < 0) { # ВЫРАЖЕНИЕ1

print "Переменная отрицательна"; # БЛОК1

} elsif ($var == 0) { # ВЫРАЖЕНИЕ2

print "Переменная равна нулю"; # БЛОК2

} else { print "Переменная положительна"; # БЛОКЗ }

сначала проверяется условие отрицательности переменной $var. Если значение переменной строго меньше нуля (ВЫРАЖЕНИЕ1), то печатается сообщение из блока БЛОК1 и оператор завершает свою работу. Если значение переменной не меньше нуля, то далее оно проверяется на равенство (ВЫРАЖЕНИЕ2), и в случае истинности выполняется оператор печати из блока операторов elsif (БЛОК2). Если проверка на равенство нулю дала ложный результат, то выполняется оператор печати из блока else (БЛОКЗ).

ПРИМЕЧАНИЕ Ключевое слово else вместе со своим блоком операторов может быть опущено.

Следует запомнить, что во многовариантном операторе if может быть сколько угодно блоков elseif, но только один или же вообще ни одного блока else.

Относительно многовариантного оператора ветвления if и оператора с блоком else языка Perl следует заметить, что, так как они определяются в терминах блоков, не возникает никакой двусмысленности при определении, какие операторы какой части оператора условия принадлежат. Блоки всегда дают нам однозначное решение.

ВНИМАНИЕ При работе с операторами ветвления важно помнить, что только один блок операторов будет выполнен – тот, для которого истинно соответствующее выражение условия.

В Perl кроме операторов ветвления if также определены операторы ветвления, в которых вместо ключевого слова if используется ключевое слово unless. В этом случае проверка выражения условия осуществляется на его ложность. Например, последний оператор if можно записать и так:

unless ($var >= 0) { # ВЫРАЖЕНИЕ1

print "Переменная отрицательна"; # БЛОК1

} elsif ($var == 0) { # ВЫРАЖЕНИЕ2

print "Переменная равна нулю"; # БЛОК2

} else {

print "Переменная положительна"; # БЛОК3

}

При этом нам пришлось заменить ВЫРАЖЕНИЕ1 на противоположное по смыслу. Подобные «замены» в выражениях условия операторов ветвления характерны при использовании вместо ключевого слова if ключевого слова unless.

ПРИМЕЧАНИЕ Все операторы могут быть вложенными, то есть в любом их блоке можно свободно использовать другие операторы ветвления.

Завершая разговор об операторах ветвления if/unless, следует сказать об использовании в них локальных лексических переменных. Если в выражении-условии объявить лексическую переменную, то она также будет видна во всех блоках оператора ветвления, включая блоки if, все elseif и else. Вне оператора ветвления, естественно, такая переменная недоступна. Например, следующий оператор if проверяет введенную пользователем строку на равенство yes или nо, сохраняя ее в локальной переменной $answer, которая доступна во всех блоках составного оператора:

if ((my $answer = <STDIN>) =~ /^yes$/i) {

chomp $answer

print "'$answer' равно 'yes'";

} elsif ($answer =~ /^no$/i) {

chomp $answer;

print "'$answer' равно 'nо'"; }

else {

die "'$answer' не равно ни 'yes', ни'nо'";

}

ПРИМЕЧАНИЕ Регулярные выражения использованного оператора if определяют, что введенная пользователем строка должна состоять либо из единственного слова yes, либо из единственного слова no, которое должно начинаться с первой позиции, на что указывает метасимвол ^, и «простираться» до конца строки, на что указывает метасимвол $. Флаг i в конце регулярного выражения определяет, что поиск соответствующего слова происходит без учета регистра, то есть заданным регулярным выражениям будут соответствовать слова yes или no, набранные как прописными, так и строчными буквами, а также в смешанном варианте.

 

 

Многовариантное ветвление — оператор switch

 

Конструкция if/else может оказаться неудобной, если вы стоите перед необходимостью сделать выбор из многих вариантов. В языке Java есть оператор switch, эквивалентный оператору switch из языков С и С++.

 




Дата добавления: 2014-12-18; просмотров: 253 | Поможем написать вашу работу | Нарушение авторских прав




lektsii.net - Лекции.Нет - 2014-2025 год. (0.026 сек.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав