Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование на C / C++ / Основы программирования на Си.doc
Скачиваний:
361
Добавлен:
02.05.2014
Размер:
1.3 Mб
Скачать

Явные преобразования типов

Выражения могут быть преобразованы из одного типа в другой явным указанием. Выражение Eможет быть явно преобразовано к типуимя-типас помощью записи вида

(имя - типа) Е

где имя типа представляется в форме

указатель-типа абстрактный-описатель

Абстрактный описатель аналогичен описателю, за исключением того, что он не содержит определяемого или описываемого идентификатора. Смысл слов имя-типа, представляемого в форме

Т абстрактный описатель

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

форма абстрактного описателя - смысл слов "Т абстрактный описатель";

пустой (абстрактный описатель) - абстрактный описатель типа Т;

*(абстрактный описатель) - указатель на тип Т;

абстрактный описатель ( ) - функция, возвращающая значение типа Т;

абстрактный описатель [n] - массив с n элементами типа Т, n - выражение с постоянным значением;

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

int i;

char *pc, *name;

char *calloc( ), *strcpy( );

тогда можно привести следующие примеры явных преобразований типов:

(char) i- преобразует значение типаintв значение типаchar.

pc=(char *) 0777- преобразует восьмеричный литер0777в значение указателя на знак таким образом, что оно может быть присвоено переменной "pc".

(emp *) calloc(1,sizeof(emp))- преобразует значение "знакового" указателя, возвращаемого функциейcalloc, в значение указателяemp.

(void) strcpy(name,"gehani")- опускает значение, возвращенное функциейstrcpy.

Синтаксис типов

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

  • - Трудность создания форматеров.

  • - Большое число ошибок, допускаемых даже опытными программистами.

  • - Трудность создания синтаксических анализаторов для трансляторов с языка Си - не существует двух трансляторов с языка Си, синтаксис входного языка для которых полностью совпадал бы.

Отсутствие формального описания синтаксиса языка Си - даже книга (Kernighan, B.W., and D.M. Ritchie, The C Programming Language, prentice-Hall, Engleewood Cliffs, NJ (1978)) может служить лишь черновым описанием такового. Сказанное касается в полной мере и синтаксиса типов. Имеется три случая, когда необходимо использовать типы:

  1. Описания, связывающие тип с именем, как, например, в случае описания (глобальных) переменных и формальных параметров;

  2. Описания, связывающие значения (и тип) с именем, как, например, описания программ;

  3. Приведения, обеспечивающие, например, возможность трактовки символов как целых.

6. Лекция: функции и переключение ввода-вывода

-Ввод и вывод одного символа.

-Буферы.

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

-Чтение файла.

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

Ввод и вывод одного символа

В данном разделе мы рассмотрим функции, применяемые при вводе и выводе. Кроме того, мы коснемся других аспектов этого понятия. Под функциями ввода-вывода подразумеваются функции, которые выполняют транспортировку данных в программу и из нее. Мы уже использовали две такие функции: 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 предыдущей программы.