Файл: Могилев А.В. Информатика.pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 31.03.2021

Просмотров: 6825

Скачиваний: 51

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

 

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 и др.  
Важная  возможность  препроцессора  -  включение  в  исходный  текст  содержимого  других 

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


background image

 

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) ); 


background image

 

338 

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

3

 

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. СИ И ПАСКАЛЬ 

 

При  знакомстве  с  языком  Си,  особенно  после  изучения  Паскаля  и  Бейсика,  погружение  в 

детали его изобразительных средств может затушевать важную мысль: хотя на Си можно написать 
практически любую прикладную программу, он изначально для этого не предназначен. Си являет-
ся результатом эволюционного развития языков создания системных программных средств. Если в 
прикладном программировании эволюция шла от Фортрана к Алголу, Коболу, Паскалю и т.д., то в 
системном - от Ассемблеров, привязанных к архитектуре ЭВМ, к Си, для которого созданы транс-


background image

 

339 

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

С  помощью  Си  можно  сделать  то,  что  на  Паскале  сделать  невозможно  (или  почти  невоз-

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

Разумеется,  сказанное  выше  не  следует  абсолютизировать.  Программисты,  привыкшие  к 

Си, успешно пишут на нем программы различных классов. Это касается не только Си - вспомните 
об экспертных системах, написанных на Бейсике. В то же время, при массовом программировании 
придерживаться «разделения труда» между языками представляется более естественным. 

 

Контрольные вопросы и задания 

 
1. Охарактеризуйте назначение и особенности языка Си. 
2. Какие символы образуют алфавит языка Си? 
3. Что называется лексемами, идентификаторами, литералами? Приведите примеры. 
4. Какие типы данных используются в Си? Приведите примеры описания переменных. 
5. Охарактеризуйте арифметические, логические и битовые операции Си. 
6. Какие разновидности оператора присваивания имеются в Си? 
7. Как на языке Си можно описать ветвление? 
8. Охарактеризуйте возможности цикла for. Приведите примеры. 
9. Какие логические циклы имеются в Си? Приведите примеры их использования. 
10. Какие операторы управления имеются в Си? 
11. Какова структура программы на Си? Что такое функция? 
12. Приведите примеры использования функций (с аргументами и без, возвращающих и не 

возвращающих значения). 

13. Для чего в качестве аргументов функций используются указатели? Приведите примеры. 
14. Для чего в Си существуют классы памяти? 
15. Что такое потоки и файлы в Си? 
16. Охарактеризуйте стандартные функции ввода и вывода в Си. 
17. Что такое препроцессор Си? Приведите примеры директив препроцессора. 
 

§ 7. ОСНОВЫ ЛОГИЧЕСКОГО ПРОГРАММИРОВАНИЯ НА ЯЗЫКЕ ПРОЛОГ 

 

7.1. ОБЩИЕ СВЕДЕНИЯ 

 

Язык Пролог является представителем семейства языков логического программирования и 

в  сравнении  с  традиционными  языками  программирования,  предназначенными  для  записи  алго-
ритмов, такими как Бейсик, Фортран, Паскаль, Си, обладает существенными особенностями: 

• программа на Прологе не является алгоритмом, а представляет собой запись условия за-

дачи  на  языке  формальной  логики  (т.е.  это  дескриптивный,  описательный  язык  программирова-
ния); 

• язык Пролог предназначен не для решения вычислительных или графических задач, а для 

решения  логических  задач,  для  моделирования  процесса  логического  умозаключения  человека; 
вычисления же и графические построения выполняются в Прологе как побочный продукт логиче-
ского вывода; 

• Пролог требует особого стиля мышления программиста,

 

что затрудняет изучение его те-


background image

 

340 

ми, кто уже привык к процедурному программированию, поэтому, так называемые, практические 
программисты  не  стремятся  переходить  на  этот  язык,  что  мешает  росту  популярности  Пролога; 
однако  во  многих  странах  (Японии,  Англии,  Франции,  Германии,  Израиле  и  т.д.)  расширяется 
практика  применения  Пролога  в  образовании  как  первого  изучаемого  языка  программирования; 
переход к процедурным языкам типа Паскаля в этом случае трудностей не вызывает. 

Все это позволяет отнести Пролог в существующем делении языков программирования на 

языки низкого и высокого уровня к языкам сверхвысокого уровня. В японском проекте создания в 
90-х годах XX века компьютеров 5-го поколения (обладающих искусственным интеллектом) Про-
лог положен в основу аппаратной организации и разработки программного обеспечения. Нынеш-
ний Пролог, безусловно, не является окончательным вариантом языка программирования ЭВМ 5-
го поколения и в ближайшие годы получит существенное развитие. По-видимому, он сыграет роль 
Бейсика дескриптивного программирования: его значение и возможности в популяризации и рас-
пространении идей логического программирования чрезвычайно велики. 

Изучению  языка  Пролог  очень  способствует  предшествующее  изучение  математической 

логики, понятийной системой которой он пользуется. 

Программирование на Прологе включает в себя следующие

 

этапы: 

1) объявление фактов об объектах и отношениях между ними; 
2) определение правил взаимосвязи объектов и отношений между ними; 
3) формулировка вопроса об объектах и отношениях между ними.  
Имена - это последовательности букв и цифр, начинающиеся с буквы (строчной !). Систе-

мы  программирования  на  Прологе  для  компьютеров  допускают  использование  лишь  латинских 
строчных и прописных букв: а .. z, A .. Z. Использование русских строчных и прописных букв: а .. 
я, А .. Я не допускается. При практической работе с интерпретатором рекомендуется, чтобы смысл 
имен оставался понятным, использовать в качестве имен запись русских слов латинскими буква-
ми. В данном параграфе мы будем записывать все имена

 

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

программ наиболее понятным. При запуске этих программ в «англо-язычных» системах програм-
мирования нужно заменять русские буквы в именах на латинские.  

Типы данных включают переменные, атомарные значения и структуры (рис. 3.15). 

 

 

Рис.3.1 5.

 Классификация типов данных Пролога 

 

Примеры 

специальных атомов

: - (

 обозначающая импликацию), 

? (вопрос, обозначающий отрицание), 
! (предикат отсечения, рассматривается далее). 

Переменные

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

 

с  заглав-

ной буквы. Особый вид переменной - 

анонимная переменная _ ,

 используемая в качестве аргумен-

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

Структура

  -

  это  конструкция,  состоящая  из  имени  структуры  и  заключенного  в  скобки 

списка ее аргументов, разделенных запятыми. Элементами структур могут быть числа, атомы, пе-
ременные, другие структуры и списки. Примеры структур: str(A,B,C), носит(юрий,пиджак). 

Списки

 представляют собой объединение элементов произвольных видов, разделенных за-

пятыми и заключенных в квадратные скобки. Списки отличаются от структур тем, что количество 
элементов  может  меняться  при  выполнении  программы.  Примеры  списков:  [1,3,5,7],  [крас-
ный,желтый,зеленый]. 

Основная операция, выполняемая в языке Пролог, - это операция сопоставления (называе-