ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 31.03.2021
Просмотров: 6825
Скачиваний: 51
336
exit(l);
}
ch=getc(fp);
/* читать один символ */
while(ch!=EOF)
{
putchar(ch);
/* печать на экран */
ch=getc(fp);
}
fclose(fp) ;
}
Под управлением буферизованной системы ввода-вывода можно выполнять операции чте-
ния и записи с произвольным доступом с помощью функции
fseek()
, которая устанавливает фай-
ловую позицию.
Например, для чтения 234-го байта в файле с именем test можно использовать следующую
функцию:
funcl()
{
FILE *fp;
if((fp=fopen("test" ,"r"))==NULL)
{
printf("He могу открыть фаил\n");
exit(l);
}
fseek(fp,234L,0);
return getc(fp); /*читать один символ в 234-й позиции*/
}
В дополнение к рассмотренным до сих пор основным функциям ввода-вывода буферизо-
ванная система ввода-вывода включает функции
fprintf()
и
fscanf()
. Эти функции ведут себя точно
так же, как функции printf() и scanf(), за исключением того, что они работают с дисковыми файла-
ми. Обращения к функциям fprintf() и fscanf() имеют следующий вид:
fprintf(1р,<формат>,<список аргументов>);
fscanf(1р,<формат>,<список аргументов>);
где fp является файловым указателем, который возвращается вызовом функции fopen().
6.8. ДИРЕКТИВЫ ПРЕПРОЦЕССОРА
Препроцессор - это программа, которая производит некоторые, иногда весьма значитель-
ные, манипуляции с первоначальным текстом программы перед тем, как он подвергается трансля-
ции.
Оператор препроцессора - это одна строка исходного текста, начинающаяся с символа #, за
которым следуют название оператора и операнды.
Операторы препроцессора могут появляться в любом месте программы
и их действие рас-
пространяется на весь исходный файл.
Весьма часто используют следующие операторы
препроцессора:
#include
#define
Более специфичными являются директивы #pragma, #if, #error и др.
Важная возможность препроцессора - включение в исходный текст содержимого других
файлов. Эта возможность, в основном, используется для того, чтобы снабжать программы какими-
337
то общими для всех данными, определениями.
Например, чрезвычайно часто в начале программы на языке Си встречается препроцессор-
ная конструкция
#include <stdio.h>
Когда исходный текст программы обрабатывается препроцессором, на место этой инструк-
ции ставится содержимое расположенного в некоем стандартном месте файла stdio.h, содержащего
макроопределения и объявления данных, необходимых для работы функций из стандартной биб-
лиотеки ввода-вывода. Для использования различных математических функций необходимо под-
ключать файл описаний math.h. Функции, оперирующие со строками, описаны в файле string.h,
функции общего назначения - в stdlib.h, функции даты и времени - в time.h, диагностика - в assert,
h и т.д.
Директива #define позволяет дать в программе макроопределения (или задать макросы).
Оператор макроопределения имеет вид
#define <макроимя> <строка лексем> или
#define <макроимя(<список параметров>)> <строка лексем>
Макроимя - это идентификатор. Строка лексем - это последовательность лексем от Макро-
имени до конца строки. Точка с запятой в конце макроопределения не ставится.
Препроцессорная обработка макроопределения сводится к тому, что любое появление Мак-
роимени (макровызов) в качестве отдельной лексемы в тексте программы, расположенном после
макроопределения, ведет к замене этого Макроимени на указанную Строку лексем.
Например, прочитав определения
#defmePI3.14159
#defineE2.711828
препроцессор заменит в программе все имена PI и Е на соответствующие числовые константы.
Препроцессор языка Си позволяет переопределять не только константы, но и целые про-
граммные конструкции. Например, можно написать определение
#define forever for(;;)
и затем всюду писать бесконечные циклы в виде forever
Определение макроимени с параметрами имеет некоторую специфику. Список параметров
макроимени - это список идентификаторов, разделенных запятыми. Следующая после списка па-
раметров строка лексем также может содержать эти параметры, которые при макровызове будут
заменены на соответствующие аргументы.
Макровызов должен быть отдельной лексемой и состоять из макроимени и заключенного в
круглые скобки списка аргументов. При обработке макровызова препроцессор заменяет каждый
параметр в строке лексем на соответствующий аргумент макровызова.
В следующих программах иллюстрируются некоторые применения операторов препроцес-
сора.
Пример 1:
найти большее из двух чисел.
Программа 110
#include<stdio.h>
#define MAX(X,Y) ((X)>(Y) ? (X) : (Y))
main()
{
int x,y;
scanf ("%d %d", &x, &y); printf ("%d", MAX(x, y) );
)
338
Результат работы программы:
3
5
5
Пример 2.
Программа 111
#include<stdio.h>
#define S (x) x*x
#define P(x) printf("x равен %d.\n",x)
main()
{
int x=4;
int z ;
z = S(x); P(z); z = 3(2);
P(z);
P(S(x));
P(S(x+2));
P(100/S(2));
P(S(++x)) ;
}
Результат работы программы:
x равен
16.
x равен 4.
x равен 16.
x равен 14.
x равен 100.
x равен 30.
Оператор препроцессора #pragma позволяет записывать самые различные указания компи-
лятору (зависящие от конкретного компилятора). Например, следующие два предложения препро-
цессора
#pragma recursive
#pragma nonrec
устанавливают режим всех функций программы по умолчанию рекурсивным или нерекурсивным.
Указание препроцессора
#pragma optimize time
воспринимается компилятором таким образом, что он старается сгенерировать объектный код, от-
личающийся более высокой скоростью выполнения, чем в случае, когда он должен быть более
компактным.
6.9. СИ И ПАСКАЛЬ
При знакомстве с языком Си, особенно после изучения Паскаля и Бейсика, погружение в
детали его изобразительных средств может затушевать важную мысль: хотя на Си можно написать
практически любую прикладную программу, он изначально для этого не предназначен. Си являет-
ся результатом эволюционного развития языков создания системных программных средств. Если в
прикладном программировании эволюция шла от Фортрана к Алголу, Коболу, Паскалю и т.д., то в
системном - от Ассемблеров, привязанных к архитектуре ЭВМ, к Си, для которого созданы транс-
339
ляторы, делающие его хоть и независимым от архитектуры, но не меняющим основного предна-
значения.
С помощью Си можно сделать то, что на Паскале сделать невозможно (или почти невоз-
можно) - например, написать фрагмент операционной системы (или новую операционную систе-
му), утилиты и т.п. Так, ряд трансляторов с Паскаля написаны на Си; обратное невозможно пред-
ставить. В то же время, не раз отмечалось, что прикладные программы, написанные на Паскале,
отличаются большей надежностью, чем написанные на Си; их легче читать, передавать от одного
программиста другому для совершенствования и сопровождения. Это связано с тем, что Паскаль
содержит существенно больше ограничений и является языком более высокого уровня с сильной
типизацией данных. Для языка же. который предназначен для разработки системного программно-
го обеспечения, чем меньше ограничений, тем лучше; так, в Си возможны неявные преобразова-
ния всех базовых типов данных и указателей друг в друга, что крайне желательно при создании
системных средств, но при невнимательности программиста приводит к ошибкам, не улавливае-
мым транслятором с Си (Паскаль же подобные недопустимые операции пресекает немедленно).
Разумеется, сказанное выше не следует абсолютизировать. Программисты, привыкшие к
Си, успешно пишут на нем программы различных классов. Это касается не только Си - вспомните
об экспертных системах, написанных на Бейсике. В то же время, при массовом программировании
придерживаться «разделения труда» между языками представляется более естественным.
Контрольные вопросы и задания
1. Охарактеризуйте назначение и особенности языка Си.
2. Какие символы образуют алфавит языка Си?
3. Что называется лексемами, идентификаторами, литералами? Приведите примеры.
4. Какие типы данных используются в Си? Приведите примеры описания переменных.
5. Охарактеризуйте арифметические, логические и битовые операции Си.
6. Какие разновидности оператора присваивания имеются в Си?
7. Как на языке Си можно описать ветвление?
8. Охарактеризуйте возможности цикла for. Приведите примеры.
9. Какие логические циклы имеются в Си? Приведите примеры их использования.
10. Какие операторы управления имеются в Си?
11. Какова структура программы на Си? Что такое функция?
12. Приведите примеры использования функций (с аргументами и без, возвращающих и не
возвращающих значения).
13. Для чего в качестве аргументов функций используются указатели? Приведите примеры.
14. Для чего в Си существуют классы памяти?
15. Что такое потоки и файлы в Си?
16. Охарактеризуйте стандартные функции ввода и вывода в Си.
17. Что такое препроцессор Си? Приведите примеры директив препроцессора.
§ 7. ОСНОВЫ ЛОГИЧЕСКОГО ПРОГРАММИРОВАНИЯ НА ЯЗЫКЕ ПРОЛОГ
7.1. ОБЩИЕ СВЕДЕНИЯ
Язык Пролог является представителем семейства языков логического программирования и
в сравнении с традиционными языками программирования, предназначенными для записи алго-
ритмов, такими как Бейсик, Фортран, Паскаль, Си, обладает существенными особенностями:
• программа на Прологе не является алгоритмом, а представляет собой запись условия за-
дачи на языке формальной логики (т.е. это дескриптивный, описательный язык программирова-
ния);
• язык Пролог предназначен не для решения вычислительных или графических задач, а для
решения логических задач, для моделирования процесса логического умозаключения человека;
вычисления же и графические построения выполняются в Прологе как побочный продукт логиче-
ского вывода;
• Пролог требует особого стиля мышления программиста,
что затрудняет изучение его те-
340
ми, кто уже привык к процедурному программированию, поэтому, так называемые, практические
программисты не стремятся переходить на этот язык, что мешает росту популярности Пролога;
однако во многих странах (Японии, Англии, Франции, Германии, Израиле и т.д.) расширяется
практика применения Пролога в образовании как первого изучаемого языка программирования;
переход к процедурным языкам типа Паскаля в этом случае трудностей не вызывает.
Все это позволяет отнести Пролог в существующем делении языков программирования на
языки низкого и высокого уровня к языкам сверхвысокого уровня. В японском проекте создания в
90-х годах XX века компьютеров 5-го поколения (обладающих искусственным интеллектом) Про-
лог положен в основу аппаратной организации и разработки программного обеспечения. Нынеш-
ний Пролог, безусловно, не является окончательным вариантом языка программирования ЭВМ 5-
го поколения и в ближайшие годы получит существенное развитие. По-видимому, он сыграет роль
Бейсика дескриптивного программирования: его значение и возможности в популяризации и рас-
пространении идей логического программирования чрезвычайно велики.
Изучению языка Пролог очень способствует предшествующее изучение математической
логики, понятийной системой которой он пользуется.
Программирование на Прологе включает в себя следующие
этапы:
1) объявление фактов об объектах и отношениях между ними;
2) определение правил взаимосвязи объектов и отношений между ними;
3) формулировка вопроса об объектах и отношениях между ними.
Имена - это последовательности букв и цифр, начинающиеся с буквы (строчной !). Систе-
мы программирования на Прологе для компьютеров допускают использование лишь латинских
строчных и прописных букв: а .. z, A .. Z. Использование русских строчных и прописных букв: а ..
я, А .. Я не допускается. При практической работе с интерпретатором рекомендуется, чтобы смысл
имен оставался понятным, использовать в качестве имен запись русских слов латинскими буква-
ми. В данном параграфе мы будем записывать все имена
русскими буквами, чтобы сделать смысл
программ наиболее понятным. При запуске этих программ в «англо-язычных» системах програм-
мирования нужно заменять русские буквы в именах на латинские.
Типы данных включают переменные, атомарные значения и структуры (рис. 3.15).
Рис.3.1 5.
Классификация типов данных Пролога
Примеры
специальных атомов
:
: - (
обозначающая импликацию),
? (вопрос, обозначающий отрицание),
! (предикат отсечения, рассматривается далее).
Переменные
обозначаются последовательностью буквой и цифр, начинающейся
с заглав-
ной буквы. Особый вид переменной -
анонимная переменная _ ,
используемая в качестве аргумен-
та предиката, когда конкретное значение переменной несущественно.
Структура
-
это конструкция, состоящая из имени структуры и заключенного в скобки
списка ее аргументов, разделенных запятыми. Элементами структур могут быть числа, атомы, пе-
ременные, другие структуры и списки. Примеры структур: str(A,B,C), носит(юрий,пиджак).
Списки
представляют собой объединение элементов произвольных видов, разделенных за-
пятыми и заключенных в квадратные скобки. Списки отличаются от структур тем, что количество
элементов может меняться при выполнении программы. Примеры списков: [1,3,5,7], [крас-
ный,желтый,зеленый].
Основная операция, выполняемая в языке Пролог, - это операция сопоставления (называе-