
- •Указатели: Определение и использование (примеры)
- •Операции над указателями и адресами.
- •Методы доступа к элементам массивов.
- •Двойные указатели. Назначение и использование (примеры).
- •Типовая структура программы на языке Си.
- •Методы передачи параметров в функцию.
- •Рекурсивные функции. Пример использования.
- •Организация работы с файлами. Открытие, закрытие и режимы доступа.
- •Динамические массивы.
- •Динамические структуры.
- •Списки. Линейные и связанные списки.
- •Стеки и очереди. Организация хранения в стеке.
- •Линейная сортировка, метод пузырька.
- •Сортировка вставкой, посредством выбора.
- •Сортировка списков путем слияния.
- •Быстрая сортировка.
- •Алгоритмы поиска.
- •Классы памяти, время жизни объектов
- •Правила инициализации переменных с различным временем жизни.
- •Модели памяти компьютера при работе с программами.
- •Управление экраном и курсором в текстовом режиме,
- •Организация видеопамяти в текстовом режиме. Управление цветом.
- •Понятие Объектно-ориентированного программирования.
- •Методология объектно-ориентированного программирования.
- •37. Проектирование по. Стиль оформления программ.
- •Эффективность и технологичность программ
- •Программирование «с защитой от ошибок». Сквозной структурный контроль.
- •Виды контроля качества разрабатываемого по
- •Понятие структурного тестирования программ
- •Функциональное тестирование программ.
- •Отладка программного обеспечения, виды ошибок.
- •Методы отладки программного обеспечения.
- •45.Правила составления документации программного продукта
Какую работу нужно написать?
Динамические массивы.
Динамическим называется массив, размер которого может меняться во время исполнения программы. Для изменения размера динамического массива язык программирования, поддерживающий такие массивы, должен предоставлять встроенную функцию или оператор. Динамические массивы дают возможность более гибкой работы с данными, так как позволяют не прогнозировать хранимые объёмы данных, а регулировать размер массива в соответствии с реально необходимыми объёмами. Обычные, не динамические массивы называют ещё статическими.
классическое задание - создать динамический массив. Кто не сталкивался с этим в начале изучени языка? Поехали... Как должно быть уже известно, имя масива фактически является указателем на первый элемент. Т.е. если имеем
1 |
int *ptrArr; |
2 |
int Arr[10]; |
то можем записать следующее
1 |
ptrArr = &Arr[0]; |
теперь ptrArr содержит адрес первого элемента массива Arr И если теперь записать
1 |
x = &ptr |
то в x запишется значение первого элемента массива К элементу массива мы можем обращаться как с помощью индекса Arr[i],так и с помощью указателя *(Arr+i), либо в нашем случае еще и *(ptrArr+i). Выражение Arr[i] автоматически преобразуется к *(Arr+i). После такого вступления мы уже можем создать динамический массив. Для этого будем использовать функцию выделения памяти calloc(), которая имеет следующий прототип
1 |
void *calloc (size_t num, size_t size) |
Функция выделяеи num*size байтов и возвращает указатель на первый элемент выделенной области либо null, если выделит память невозможно. Для использования необходимо подключить заголовок
1 |
#include <cstdlib> |
Создадим динамический массив на 10 элементов:
1 |
int *p; |
|
2 |
p = (int*)calloc(10,sizeof(int)); // Выделяем память |
3 |
//... // какой-либо код |
|
4 |
free (p); // удалим массив, если он нам больше не нужен |
Как видно из примеры, мы взяли указатель и выделили под него память на 10 int-значений. Вот так просто создаются одномерные массивы. Теперь перейдем к двумерным. Пусть нам требуется создать массив 3*4 (3 строки, 4 столбца). Двумерный массив мы можем представить как "массив одномерных массивов", т.е. как одномерный массив, элементами которого являеются так же одномерные массивы. Далее, следует, если у нас будет несколько массивов (элементов), стало быть для каждого из них должен быть свой указатель, а это уже получается, что мы должны иметь массив указателей. Этот массив указателей очевидно одномерный и надо его создать, а создавать одномерные динамические массивы мы уже умеем. Но тут есть дно "но"! В предыдущем примере мы заводили массив int-элементов и указатель int* на первый элемент, а здесь у нас элементами являются указатели на int - int*, и тогда указатель на первый элемент у нас будет уже указателем на ... указатель! т.е. будет иметь тип int**. Стало быть под него надо выделить память
1 |
int **m; // указатель на указатель на int |
|
2 |
m = (int**)calloc(3,sizeof(int*)); |
|
Итак, массив указателей создан и он где-то в памяти. Теперь надо под каждый из этих указателей выделить память, соответствующую второй размерность. Это мы делать умеем.
1 |
for (int i=0; i<3; i++) |
|
2 |
*(m+i) = (int*)calloc(4,sizeof(int)); |
Обратите внимание на запись *(m+i). Как говорилось выше, мы используем доступ к элементу массива с помощью указателя. Получив доступ к этому элементу массива указателей, мы можем выделить память и после этого перейти к следующему элементу. Можно бы было написать и так
1 |
m[i] = (int*)calloc(4,sizeof(int)); |
но в профессиональном плане чаще всего встречается именно первая запись. Для удаления массива нужно проделать обратные действия: удалить массив под каждый указатель
1 |
for (int i=0; i<3; i++) |
|
2 |
free(*(m+i)); затем нужно удалить сам массив указателей |
3 |
free(m); |
Теперь мы можем создавать двумерные динамические массивы. В заключении хотелось бы отметить, что таким образом мы можем создавать динамические массивы, размерность которых больше двух. Допустим трехмерный массив можно представить как одномерный массив двумерных массивов, ну а с двумерныи массивами мы уже разобрались! Теперь всё!