
- •Введение в системное программирование Основные понятия и определения Программы и программное обеспечение
- •Системное программирование
- •Этапы подготовки программы
- •Системное программирование
- •Лекция 1
- •1. Язык Си: Общая характеристика, историческая справкаи основные достоинства
- •2. Подготовка к выполнению и выполнение программ
- •3. Элементы языка с
- •Лекция 2
- •1. Понятие типа данных. Переменные и константы. Операция присваивания
- •2.Типы данных в языке си. Описание данных в программе
- •3. Константы в языке Си
- •4. Арифметические операции и арифметические выражения
- •5. Операции отношения, логические операции и логические выражения
- •6. Автоматическое преобразрвание типов и операция приведения
- •7. Простейшие операторы языка си. Составной оператор
- •Лекция 3
- •3. Инициализация переменных и массивов
- •4. Управляющие конструкции языка си
- •Лекция 4
- •1. Адреса и указатели
- •2. Отождествление массивов и указателей.Адресная арифметика
- •3. Указатели на массивы. Массивы указателей и многомерные массивы
- •4. Динамическое выделение памяти под массивы
- •5. Инициализация указателей
- •Лекция 5
- •1. Функции в языке си. Формальные и фактические параметры. Механизм передачи параметров. Возвращаемые значения
- •2. Использование указателей в качестве аргументов функций
- •3. Предварительное описание функций
- •4. Аргументы командной строки
- •Лекция 6
- •1. Ввод и вывод в языке си: Общие концепции
- •2. Файлы данных и каталоги. Внутренняя организация и типы файлов
- •3. Стандартные функции для работы с файлами и каталогами
- •4. Внешние устройства как специальные файлы. Организация обмена со стандартными внешними устройствами
- •5. Операции ввода/вывода через порты микропроцессоров intel 8086/80286
- •Лекция 7
- •1. Общая структура программы на языке си. Время существования и видимость переменных. Блоки
- •2. Классы памяти
- •3. Рекурсивные вызовы функций. Реализация рекурсивных алгоритмов
- •4. Препроцессор языка Си
- •5. Модели памяти, поддерживаемые компилятором ibm c/2
- •Лекция 8
- •1. Структуры в языке си: основные понятия
- •2. Массивы структур
- •3. Указатели на структуры
- •4. Вложение структур
- •5. Структуры и функции
- •6. Объединения
- •7. Перечисления
- •8. Определение и использование новых типов данных
- •9. Классы имен
4. Динамическое выделение памяти под массивы
В двух предыдущих параграфах при обсуждении вопроса об эквивалентности массивов и указателей мы воспользовались стандартными функциями malloc() и alloca() для динамического выделения памяти под хранение элементов массива. Здесь будут рассмотрены некоторые детали затронутой проблемы. Во многих задачах вычислительной математики и при реализации алгоритмов обработки информационных структур возникает потребность работы с массивами, количество элементов которых изменяется от одного прогона программы к другому. Простейшее решение этой проблемы состоит в статическом описании соответствующих массивов с указанием максимально необходимого количества элементов. Однако такой подход приводит, как правило, к неоправданному завышению объема памяти, требуемой для работы программы. Альтернативное решение открывается в связи с использованием указателей для представления массивов переменных. Пусть нам необходимо написать программу скалярного умножения векторов A и B, размерность которых заранее не известна. Для этого поступим следующим образом. Опишем в заголовке программы переменную m, определяющую длину соответствующих массивов, и указатели a, b, c, которые будут определять размещение в памяти векторов-сомножителей и вектора-результата:
int m;
float *a, *b, *c;
После того, как значение m будет определено (оно может быть, например, введено с клавиатуры терминала), необходимо выделить достаточный объем памяти для хранения всех трех векторов. Поскольку речь здесь идет о динамическом размещении массивов в процессе выполнения программы, мы должны воспользоваться одной из трех специальных функций, входящих в состав стандартной библиотеки и сведения о которых приведены ниже.
Имя функции и назначение: alloca - резервирует size байт памяти из ресурса программного стека; выделенная память освобождается по завершении работы текущей программной компоненты (см. Лекцию 7)
Формат и описание аргументов:
void *alloca(size)
int size; /* Требуемое количество байт памяти */
Возвращаемое значение является указателем типа char на первый байт зарезервированной области программного стека и равно NULL при отсутствии возможности выделить память требуемого размера. Для получения указателя на тип данных, отличный от char, необходимо применить к возвращаемому значению операцию явного преобразования типа (см. Лекцию 2, $ 6).
Имя функции и назначение: calloc - резервирует память для размещения n элементов массива, каждый из которых имеет длину size байт, инициализируя все элементы нулями; выделенная память освобождается по завершении работы программы или при помощи функции free() (см. ниже)
Формат и описание аргументов:
void *calloc(n, size)
int n; /* Общее количество элементов в массиве */
int size; /* Длина в байтах каждого элемента */
Возвращаемое значение является указателем неопределенного типа на первый байт зарезервированной области статической памяти и равно NULL при отсутствии возможности разместить требуемое количество элементов заданной длины. Для получения указателя на конкретный тип данных, необходимо применить к возвращаемому значению операцию явного преобразования типа (см. Лекцию 2, $ 6).
Имя функции и назначение: malloc - резервирует блок памяти размером size байт; затребованная память освобождается по завершении работы программы или при помощи функции free (см. ниже)
Формат и описание аргументов:
void *malloc(size)
int size; /* Требуемое количество байт памяти */
Возвращаемое значение является указателем неопределенного типа на первый байт зарезервированной области статической памяти и равно NULL при отсутствии возможности выделить память требуемого размера. Для получения указателя на конкретный тип данных, необходимо применить к возвращаемому значению операцию явного преобразования типа (см. Лекцию 2, $ 6).
Предварительные описания всех этих функций (см. Лекцию 5, $ 3) помещены в файлы stdlib.h и malloc.h и при их использовании один из них должен быть включен в состав исходного текста программы при помощи директивы препроцессора #include (см. Лекцию 7, $ 4 и примеры программ).
Выбрав в нашей задаче для размещения массивов a, b и c какую-либо из этих функций, например calloc(), можно записать:
a = (float*)calloc(m, sizeof(float));
b = (float*)calloc(m, sizeof(float));
c = (float*)calloc(m, sizeof(float));
где операция приведения (float*) преобразует указатель неопределенного типа в указатель типа float. Теперь, после предварительного ввода числовых значений элементов векторов, может быть выполнено их скалярное умножение:
for (i = 0; i < m; i++)
c[i] = a[i]*b[i];
Для динамического размещения двумерного массива необходимо воспользоваться косвенным указателем
int m, n;
float **matr;
и выделять память в два этапа:
matr = (float**)malloc(m*sizeof(float*));
for (i = 0; i < m; i++)
matr[i] = (float*)calloc(n, sizeof(float));
После этого работа с matr может выполняться точно так же, как и с обычным двумерным массивом.
Замечание. Используя функцию alloca(), резервирующую память из ресурса программного стека, необходимо задать достаточный размер последнего на этапе построения готовой к выполнению программы из объектных модулей (см. Лекцию 1, $ 2). В противном случае может возникнуть состояние переполнения стека, что делает невозможным создание блока памяти требуемого размера. Память, затребованная у системы путем использования функций calloc() и malloc(), может быть возвращена назад до полного завершения работы программы при помощи функции free(). Более того, используя функцию realloc(), можно изменить размер ранее зарезервированного этими функциями блока памяти. Предварительные описания функций free() и realloc() также находятся в файлах stdlib() и malloc(), а необходимые сведения о них приведены ниже.
Имя функции и назначение: free - освобождает блок памяти, предварительно зарезервированный одной из функций calloc(), malloc() или
realloc()
Формат и описание аргументов:
void free(ptr)
void *ptr; /* Указатель на освобождаемый блок */
Эта функция в результате своей работы не возвращает никакого значения. Кроме того, она игнорирует указатель ptr, если он равен NULL.
Имя функции и назначение: realloc - изменяет размер блока памяти, предварительно зарезервированного функциями calloc(), malloc() или realloc()
Формат и описание аргументов:
void *realloc(ptr, size)
void *ptr; /* Указатель на предварительно */
/* зарезервированный блок памяти */
int size; /* Новый размер блока в байтах */
Возвращаемое значение является указателем неопределенного типа на первый байт зарезервированной области статической памяти и равно NULL при отсутствии возможности выделить память требуемого размера. В общем случае оно не равно значению указателя ptr, ибо при изменении размера блока может также измениться его размещение в оперативной памяти ЭВМ. Для получения указателя на конкретный тип данных, необходимо применить к возвращаемому значению операцию явного преобразования типа (см. Лекцию 2, $ 6).