
- •Основы алгоритмизации и программирования, язык Си
- •Введение
- •Блок-схема алгоритма Общие требования к блок-схеме алгоритма
- •Линейные и разветвляющиеся процессы
- •Циклические процессы
- •Итерационные процессы
- •Комментарии
- •Типы данных
- •Данные целого типа
- •Данные вещественного типа
- •Модификатор const
- •Переменные перечисляемого типа
- •Константы
- •Операции и выражения
- •Операция присваивания
- •Арифметические операции
- •Операции поразрядной арифметики
- •Логические операции
- •Операции отношения
- •Инкрементные и декрементные операции
- •Операция sizeof
- •Порядок выполнения операций
- •Приоритет операций
- •Преобразование типов
- •Операция приведения
- •Операция запятая
- •Ввод и вывод информации
- •Директивы препроцессора Директива #include
- •Директива #define
- •Понятие пустого и составного операторов
- •Условные операторы
- •Операторы организации цикла
- •Оператор цикла for
- •Оператор цикла while
- •Оператор цикла do … while
- •Вложенные циклы
- •Операторы перехода (break, continue, return, goto)
- •Примеры программ
- •Массивы Одномерные массивы
- •Примеры программ
- •Многомерные массивы (матрицы)
- •Примеры программ
- •Указатели Понятие указателя
- •Описание указателей
- •Операции с указателями
- •Связь между указателями и массивами
- •Массивы указателей
- •Многоуровневые указатели
- •Примеры программ
- •Символьные строки
- •Ввод/вывод строк.
- •Функции работы со строками.
- •Примеры программ
- •Функции
- •Прототип функции.
- •Определение функции.
- •Параметры функции
- •Параметры по умолчанию
- •Передача массива в функцию
- •Inline функции
- •Класс памяти
- •Автоматические переменные
- •Статические переменные
- •Регистровые переменные
- •Блочная структура
- •Примеры программ
- •Указатели на функции
- •Примеры программ
- •Рекурсия
- •Примеры программ
- •Аргументы в командной строке
- •Функции с переменным числом параметров
- •Примеры программ
- •Сортировка
- •Пузырьковая сортировка.
- •Шейкер сортировка
- •Сортировка вставкой
- •Сортировка выбором
- •Метод Шелла
- •Метод Хора
- •Структуры
- •Доступ к элементам структуры
- •Инициализация структур
- •Указатели на структуры.
- •Структуры и функции
- •Примеры программ
- •Поля бит
- •Объединения
- •Переменные с изменяемой структурой
- •Примеры программ
- •Организация списков и их обработка
- •Операции со списками при связном хранении
- •Построение обратной польской записи
- •Односвязный линейный список, очередь
- •Двусвязный линейный список
- •Циклический список, кольцо
- •Двусвязный циклический список
- •Примеры программ
- •Деревья
- •Потоки и файлы
- •Файлы Основные сведения о файловой системе
- •Организация посимвольного ввода и вывода
- •Определение конца файла feof()
- •Организация ввода и вывода строк
- •Удаление файлов
- •Дозапись потока
- •Позиционирование в файле
- •Текстовые и двоичные файлы
- •Функции fread() и fwrite()
- •Примеры программ
- •Хеширование
- •Схемы хеширования
- •Метод открытой адресации с линейным опробыванием
- •Метод цепочек
- •Машинное представление графов
- •Примеры программ
- •Литература
Массивы указателей
Кроме обычных массивов, в языке С(С++) используются массивы указателей. Они представляют собой массивы, элементами которых являются указатели (например, на элементы другого массива), например описание массива указателей имеет вид:
float *mas[6];
Это соответствует массиву из шести элементов, являющихся адресами объектов типа float.
В массиве указателей последовательность элементов задается последовательностью размещения указателей в массиве. Тогда изменение порядка следования (включение, исключение, упорядочение, перестановка), которое в обычном массиве заключается в перемещении самих элементов, в массиве указателей должно сопровождаться соответствующими операциями над указателями. Очевидные преимущества возникают, когда сами указуемые элементы являются достаточно большими (массивы, строки, структуры и т.д.).
Многоуровневые указатели
Рассмотрим определение переменной:
double **pp;
В соответствии принципом контекстного определения pp нужно интерпретировать как переменную, при косвенном обращении к которой получается указатель на переменную типа double, то есть как указатель на указатель или адрес указателя. Но поскольку любой указатель в Си может ссылаться как на отдельную переменную, так и на область памяти (массив), то в применении к двойному указателю получаются 4 варианта структур данных, а именно:
· указатель на одиночный указатель на переменную типа double;
· указатель на одиночный указатель на массив переменных типа double;
· указатель на массив, содержащий указатели на одиночные переменные типа double;
· указатель на массив, содержащий указатели на массивы переменных типа double.
Третья интерпретация позволяет нам использовать двойной указатель для работы с известными нам массивами указателей следующим образом:
double **pp, *pd[20];
pp = pd; // или pp = &pd[0];
*(pp+i) // или pp[i]
**(pp+i) // или *pp[i]
Здесь повторяется та же самая система эквивалентности обычных массивов и указателей - типов double* и double[], но применительно не к массивам обычных переменных, а к массивам указателей. Иначе, типы double** и double *[] различаются так же, как указатель-переменная и указатель-константа. Массив указателей типа double *[] является статической структурой данных, размерность которой определяется при компиляции. Двойной указатель типа double** может ссылаться и на динамический массив указателей, который создается во время работы программы под заданную размерность:
double **create(int n,int m)
{ double **pp,*q; // создать динамический массив
int i,j; // указателей размерностью sz+1
pp = (double**)malloc(sizeof(double *)*n);
if(pp)
for (i=0; i<n; i+)
{ *(pp+i) = (double*)malloc(sizeof(double)*m);
if(!*(pp+i))
{ for(j=0; j<i; j+ ) free(*(pp+j));
free(pp);
}
}
// работа с динамическим массивом
return(pp); // возврат указателя на динамический массив указателей
}