- •Министерство образования Республики Беларусь
- •1. Что такое программа на языке программирования
- •2. Общее знакомство с языком с
- •3. Структура простой программы на языке с
- •4. Что такое программа на языке с
- •5. Представление информации и типы данных в языке с
- •6. Константы
- •7. Переменные
- •8. Элементарный вВод и вывод информации
- •9. Выражения и операции
- •9.1. Арифметические операции
- •9.2. Операция изменения знака
- •9.3. Операции инкремента и декремента
- •9.4. Операция присваивания
- •9.6. Поразрядные логические операции
- •9.8. Логические операции и операции отношения
- •9.9. Условная операция «? :»
- •9.10. Операция последовательного вычисления
- •9.11. Операция определения требуемой памяти в байтах sizeof
- •9.12. Операция приведения типа (type)
- •10. Операторы управления вычислительным процессом
- •10.1. Операторы ветвления if и else
- •10.2. Оператор switch
- •10.3. Оператор цикла while
- •10.4. Оператор цикла do…while
- •10.5. Оператор цикла for
- •10.6. Бесконечные циклы
- •10.7. Другие управляющие средства языка с
- •10.8. Стандартные математические функции
- •11. Вычисление выражений и побочные эффекты
- •11.1. Преобразования типов при вычислении выражений
- •11.2. Побочные эффекты при вычислении выражений
- •12. Массивы
- •12.1. Описание массива
- •12.2. Инициализация массива
- •12.3. Ввод-вывод массива
- •12.4. Двумерные массивы (массивы массивов)
- •13. Указатели
- •14. Адресная арифметика
- •15. Массивы и указатели
- •15.1. Указатели и одномерные массивы
- •15.2. Указатели и двумерные массивы
- •16. Строки
- •17. Массивы строк
- •18. Функции
- •18.1. Определение функции в языке с
- •18.2. Возвращение значений из функции
- •18.3. Формальные и фактические параметры функции
- •18.4. Вызов функции
- •18.5. Объявление и определение функции: прототип функции
- •19. Передача параметров в функции
- •19.1. Способы передачи параметров в функции
- •19.2. Передача параметров в функции в языке с
- •19.3. Передача указателей в функции
- •20. Классы хранения и видимость переменных
- •20.1. Общие положения
- •20.2. Спецификаторы класса памяти
- •20.3. Область видимости функций
- •20.4. Глобальные переменные
- •20.5. Глобальные статические переменные
- •20.6. Локальные переменные
- •20.7. Статические локальные переменные
- •20.8. Регистровые переменные
- •20.9. Выводы
- •21. Организация памяти программы
- •22. Многофайловая компиляция (проекты)
- •23. Передача в функции массивОв
- •23.1. Передача одномерных массивов в функции
- •23.2. Передача двумерных массивов в функции
- •23.3. Передача в функции символьных строк
- •23.4. Возвращение указателей из функций
- •24. Функции с переменным количеством аргументов
- •24.1. Соглашения о вызовах: модификаторы функций
- •24.2. Объявление списка параметров переменной длины
- •25. Передача параметров в функцию main()
- •26. Указатели на функцию
- •27. Стандартные функцИи языка с
- •27.1. Функции для работы со строками
- •27.2. Функции для проверки символов и преобразования данных
- •27.3. Функция быстрой сортировки – gsort()
- •27.4. Функция двоичного поиска – bsearch()
- •28. Работа с файлами
- •28.1. Основные понятия
- •28.2. Основные функции для работы с файлами
- •28.3. Открытие и закрытие файлов
- •28.4. Ввод/вывод символов
- •28.5. Ввод/вывод строк
- •28.6. Форматированный ввод/вывод
- •28.7. Ввод/вывод блоков данных
- •28.8. Другие средства для работы с файлами
- •28.9. Ввод/вывод низкого уровня (префиксный доступ к файлам)
- •29. Типы, определяемые пользователем: Перечисления, структуры и объединения
- •29.1. Переименование типов – оператор typedef
- •29.2. Перечисления (enum)
- •29.3. Основные сведения о структурах
- •29.4. Структурные переменные в памяти компьютера
- •29.5. Доступ к полям структуры
- •29.6. Массивы структур
- •29.7. Структуры и функции
- •29.8. Объединения (union)
- •30. Динамическая память
- •30.1. Понятие динамического объекта
- •30.2 Создание и уничтожение динамических объектов
- •30.3 Динамическое размещение одномерных массивов и строк
- •30.4 Динамическое размещение двумерных массивов
- •30.5. Функции для работы с блоками памяти
- •31. Динамические структуры данных
- •31.1. Понятие структуры данных
- •31.2. Структуры, ссылающиеся на себя
- •31.3. Связанные списки
- •31.5. Очереди
- •Ниже приводятся примеры функций для очереди (структура элемента очереди совпадает со структурой элемента стека в примере выше):
- •32. Препроцессор языка с
- •32.1 Директива включения файлов
- •32.2. Директива определения макрокоманд (макросов)
- •32.3 Директива условной компиляции
- •32.4 Дополнительные директивы препроцессора
22. Многофайловая компиляция (проекты)
Любую программу, текст которой занимает даже сотни строк, можно хранить в одном файле. Но это очень не удобно. Даже если допустить, что размер файла с программой может быть любого размера, как модифицировать и отлаживать программу, размер которой 1000 строк, а на экране видно только 20 строк? Кроме этого, при увеличении длины программы значительно увеличивается и время ее компиляции. Когда размер программы достигает некоторого предела, приходится разбивать ее на части, каждая из которых хранится отдельно – в отдельном файле.
При работе с большими программами намного удобнее размещать части программы не в одном, а в нескольких файлах. Это же можно сказать и про случай, когда одну программу разрабатывают несколько человек. Каждый файл должен включать целиком одну или несколько функций.
Преимущества такого подхода:
разработку и отладку разных частей программы можно поручить разным людям;
программу проще и удобнее отлаживать и модифицировать;
ускорение в работе, ведь при запуске программы можно компилировать только те файлы, которые изменялись, для остальных можно использовать уже существующие obj-файлы (т.к. файлов может быть много, а процесс компиляции в С достаточно длинный, то это дает значительный выигрыш по времени в процессе работы). Эта последовательность действий (создание сначала объектных файлов, а затем самой программы) типична для многих компиляторов и сильно экономит время при разработке больших программ, потому что обрабатываются только измененные исходные тексты. Затем объектные файлы поступают редактору связей, и на выходе получается готовая программа.
Есть два подхода к многофайловой разработке программ на языке С.
Первый подход: нужные cpp-файлы подключать по #include ”*.cpp” к главному cpp-файлу. Но это плохой подход, т.к. он не дает третьго преимущества – просто препроцессор создает один большой файл, который весь компилируется.
Второй подход: для объединений нескольких cpp-файлов в одну программу использовать проекты. Такой подход используется во многих интегрированных средах разработки (IDE Integrated development environment – система программных средств, используемая программистами для разработки программ. Обычно среда разработки включает в себя: текстовый редактор, компилятор и/или интерпретатор, средства автоматизации сборки, отладчик). Это подход, который позволяет использовать все преимущества многофайловой разработки программ.
Проект – это специальный файл, в который записываются имена файлов (в нашем случае cpp-файлов), которые IDE (в нашем случае BC++) следует объединять в один исполняемый exe-файл. Имя исполняемого файла совпадает в таком случае с именем проекта, а не с именем cpp-файла, как получается при однофайловой программе.
Все необходимые для работы с файлами проектов команды включены в меню Project.
Для организации файла проекта необходимо открыть файл проекта. Для этого выполняются команды Project→Open Project…. ВС++ активизирует специальное окно «Project» в нижней части экрана и открывает окно диалога, позволяющее загрузить нужный файл проекта или создать новый с заданным именем.
Если создается новый файл проекта, окно «Project» первоначально будет пустым. Включение файлов в проект и их удаление выполняются либо через команды Project→Add item… и Project→Delete item, либо нажатием клавиш Ins и Del, в случае если курсор размещен в окне «Project». При добавлении файлов в проект открывается окно диалога, позволяющее выбрать нужный файл.
В проект можно включать не только cpp-файлы, но и obj-файлы и библиотеки (.lib). Не включаются в проект заголовочные h-файлы.
Сохранение файла проекта: Options→Save…. Надо убрать два верхних крестика, оставить только сохранение проекта.
Открыть существующий файл проекта можно и так: bc имя[.prj].
Окно «Project» упрощает переход от одного файла, включенного в проект, к другому при их редактировании. Для этого надо выделить строку с нужным именем файла в окне «Project» и нажать клавишу ENTER.
При работе с проектом возникает необходимость взаимодействия отдельных файлов. Другими словами, функция из одного файла, должна иметь доступ к переменной или функции из другого файла.
// === файл func.cpp ================
extern int k; // в другом файле определена эта переменнная
int sumk(int a, int b) { return k*(a+b); }
int min(int a, int b) { return a<b ? a : b; }
// === файл task.cpp ================
int k; // глобальная переменная
int min(int, int); // прототипы функций, определенных
int sum(int, int); // в другом файле
void main() { int x, y, z;
scanf(“%d %d”, &x, &y);
scanf(“%d”, &k);
printf(“min = %d”, min(x,y));
c = sum(x,y);
printf(“sum * %d = %d”, k, c);
}
В файле func.cpp надо использовать глобальную переменную, которая определена в файле task.cpp. Т.к. каждый файл проекта компилируется по отдельности, то при компиляции func.cpp будет ошибка компиляции «Переменная k не определена». При компиляции же файла task.cpp выдаст ошибку, что функции min() и sum() не имеют прототипов. Причина ошибок понятна: в одном файле ничего не известно про глобальную переменную k, в другом файле – про функции min() и sum().
В файле func.cpp нужно как-то указать, что переменная k существует и определена в другом файле программы. Делается это с помощью указания extern. Строка extern int k; говорит компилятору, работающему с файлом func.cpp: «Переменная k определена в другом файле. В каком – не важно. Достаточно знать, что она – типа int». Увидев слово extern, компилятор создает объектный файл, в котором сказано, что переменная k – внешняя, определена в каком-то другом файле, и ее поисками займется уже редактор связей при внешнем связывании.
Нужно четко понимать, что жизнь дается переменной один раз. В нашем случае это делается в файле task.cpp, где объявление int k; велит компилятору выделить участок памяти для целочисленной переменной и заслать туда ее начальное значение 0. Слово extern ничего не создает и памяти никакой не выделяет.
Для того, чтобы указать компилятору, что какая-либо функция определена в программе, достаточно в нужном файле просто указать прототип нужной функции: int min(int,int); int sum(int,int);. Т.е. при многофайловой компиляции действуют обычные правила объявления функции, если функция не определена до момента своего использования.
Словом extern необходимо помечать только переменные. Для функций это можно не делать, потому что компилятор и так считает все функции внешними. Но чтобы указать компилятору, что функция определена в другом файле, ее прототип также можно предварить словом extern: extern int min(int,int);