- •1. Краткие теоретические сведения
- •1.1. Понятие указателя
- •1.2. Объявление указателя
- •1.3. Операции над указателями
- •1.4. Передача параметра по ссылке
- •1.5. Динамическое выделение памяти
- •1.5.1. Динамическое размещение одномерного массива
- •1.5.2. Динамическое размещение двухмерного массива
- •1.5.3. Динамические массивы
- •1.5.4. Формирование динамических массивов с использованием библиотечных функций
- •1.5.5. Формирование динамических массивов с использованием операций new и delete
- •1.5.6. Динамические массивы
- •1.5.7. Динамические массивы
- •1.5.8. Динамические массивы
- •1.5.9. Освобождение выделенной динамической памяти.
- •1.5.10. Описание динамической строки
- •1.5.11. Объявление динамического массива
- •1.6. Связь указателей и массивов
- •1.7. Массивы указателей
- •1.8. Массивы и функции
- •1.9. Указатель на символьную строку
- •Второй пример
- •Увеличение указателя на символьную строку
- •Уменьшение количества операторов
- •Сканирование символьной строки
- •1.10. Заполнение массивов случайными числами
- •1.12. Примеры программирования задач
- •2. Задание
- •2.4. Задания для выполнения на занятиях
- •2.4.1. Задание 1. Динамические одномерные массивы
- •2.4.1.1. Варианты заданий
- •2.4.1.2. Пример обработки динамического массива для варианта 30
- •2.4.1.3. Программа
- •Int *a, *b; // указатели исходных одномерных массивов a и b
- •2.4.1.4. Тестирование
- •2.4.2. Задание 2. Динамические двумерных массивы
- •2.4.2.1. Варианты заданий
- •2.4.2.2. Пример для варианта 30
- •2.4.2.3. Программа
- •2.4.2.4. Тестирование
- •2.4.3. Задание 3. Динамические одномерные массивы Викентьева
- •2.4.3.1. Варианты заданий
- •2.4.4.1. Варианты заданий
- •4. Требование к отчету
- •4. Краткие теоретические сведения.
- •5. Вопросы для самоконтроля
- •Литература
- •1. Краткие теоретические сведения 2
- •1.1. Понятие указателя 2
1.4. Передача параметра по ссылке
В языке С все аргументы функции передаются по значению. Это значит, что при вызове функции в системный стек помещаются фактические значения аргументов функции. В функции создаются локальные копии аргументов, значения которых считываются из стека. Далее функция использует эти локальные переменные и может изменять их. При выходе из функции локальные переменные уничтожаются, изменённые значения параметров теряются. Таким образом, в языке С вызванная функция не может изменить значения переменных, указанных в качестве фактических параметров при обращении к ней. Например, функция swap(), которая должна менять значения параметров местами, не будет этого делать:
void swap(int a, int b)
{
int tmp=a; a=b; b=tmp;
} //.
Но тем не менее функцию можно приспособить для изменения аргументов. Для этого необходимо в качестве параметра передавать адрес переменной, которую надо изменять, т. е. передавать указатель на переменную. Такой приём в языке С называется передачей параметра через указатель. Вызванная функция должна описывать аргумент как указатель и обращаться к фактической переменной косвенно, через разыменование указателя. Теперь функцию swap() мож-
но описать следующим образом:
void swap(int *a, int *b)
{
int tmp=*a; *a = *b; *b=tmp;
} //.
Тогда для обмена местами значений переменных x и y необходимо использовать функцию swap(&x,&y).
Ещё одним способом косвенной передачи параметра функции является передача по ссылке. Тогда аргументами функции swap() будут «ссылки» на другие переменные
void swap(int &a, int &b)
{
int tmp=a; a = b; b=tmp;
} //.
При обращении к функции в качестве фактических параметров необходимо указывать имена переменных x и y: swap(x,y). Подробнее о ссылках можно почитать в [2].
1.5. Динамическое выделение памяти
Помимо рассмотренных элементарных действий с указателями с их помощью можно также создавать новые переменные и выделять память динамически в ходе работы программы. Для этого предназначен оператор new:
указатель = new тип;
например,
int *p; // указатель на целое
p = new int; // выделяем память.
После операции new указывается тип данных, которые будут храниться в выделяемой области памяти, адрес начала выделенной области присваивается указателю. После этого можно пользоваться выделенными ячейками, например
*p = 155; // присвоили значение.
Когда динамически выделенная память больше не нужна её можно освободить с помощью оператора delete:
delete указатель;
например,
delete p; // освободили память.
Удаления указателя при этом не происходит, память, адрес которой находится в указателе, объявляется свободной.
Для создания массивов с переменной размерностью используется динамическое размещение данных, декларируемых указателями.
Для работы с динамической памятью используются стандартные функции библиотеки alloc.h:
void *malloc(size) и void *calloc(n, size) – выделяют блок памяти размером size и nsize байт соответственно; возвращают указатель на выделенную область, при ошибке – значение NULL;
void free(bf); – освобождает ранее выделенную память с адресом bf.
Другим, более предпочтительным подходом к динамическому распределению памяти является использование операций языка С++ new и delete.
Операция new возвращает адрес ОП, отведенной под динамически размещенный объект, при ошибке – NULL, а операция delete освобождает память.