- •Синтаксис языка c. Структура программы. Характеристика функции main.
- •Директивы препроцессора (основные).
- •Базовые типы данных.
- •Декларация объектов программы на языке c, атрибуты: тип, класс памяти и область действия.
- •Константы в программах на языке c.
- •Функции вывода информации. Использование модификаторов и управляющих последовательностей.
- •Функции ввода информации.
- •Ввод/вывод потоками (cin, cout).
- •Синтаксис операторов языка c, операторы-выражения, управляющие операторы в языке с.
- •Арифметические операции, преобразование типов операндов арифметических операций. Средство "typedef".
- •Сокращенная запись операции присваивания
- •X##; - постфиксную.
- •Операции отношений (сравнения) и логические операции. Операции сравнения
- •Логические операции
- •Побитовые логические операции, операции над битами
- •Операторы передачи управления goto, continue, break, return.
- •Ветвящийся алгоритм. Условный оператор if, условная операция «? :».
- •If (условие ) оператор1;
- •If (условие1) оператор1;
- •Оператор выбора альтернатив (переключатель) switch.
- •Операция ",".
- •Циклический алгоритм. Оператор с предусловием while.
- •Оператор цикла с постусловием do - while.
- •Оператор цикла с предусловием и коррекцией for.
- •Функции в с. Способы описания функции, операция вызова функции.
- •Указатели как тип данных. Операции * и &. Операции над указателями.
- •Одномерные массивы и связь с указателями.
- •Cтроковые данные в с. Библиотечные функции для их обработки.
- •Указатель на указатель, многомерные массивы.
- •Динамическая память, функции и операции работы с памятью.
- •Указатели на функцию
- •Тип данных «структура», общая характеристика.
- •Файлы в с. Типы файлов, понятие файловой переменной и увязка ее с физическим файлом.
- •Текстовые файлы.
- •Основные режимы работы с бинарными файлами, последовательный и прямой доступ.
Указатель на указатель, многомерные массивы.
Связь указателей и массивов с одним измерением справедливо и для массивов с большим числом измерений. Например, рассмотрим двумерный массив
float m[5][10];
Если рассматривать его как массив пяти массивов размерностью по десять элементов каждый, то очевидна схема его размещения в памяти - последовательное размещение «строк» элементов. Обращению к элементам m[i][j] соответствует эквивалентное выражение *(*(m+i)+j), а объявление этого массива указателем будет:
float **m;
Таким образом, имя двумерного массива - имя указателя на указатель.
Например, двухмерный массив m(3х4) компилятор рассматривает как массив трех указателей, каждый из которых указывает на начало массива со значениями размером по четыре элемента каждый (рис. 1).
|
m |
|
значения |
|
|||
Ука- |
m[0] |
→ |
m[0][0] |
m[0][1] |
m[0][2] |
m[0][3] |
*(*(m+i)+j) |
за- |
m[1] |
|
m[1][0] |
m[1][1] |
m[1][2] |
m[1][3] |
|
тели |
m[2] |
|
m[2][0] |
m[2][1] |
m[2][2] |
m[2][3] |
|
|
A |
|
B |
|
|||
рис. 1
Cхема размещения такого массива в памяти - последовательное (друг за другом) размещение строк - одномерных массивов со значениями.
Аналогичным образом можно установить соответствие между указателями и массивами с произвольным числом измерений. Количество символов «*» определяет уровень вложенности указателей друг в друга. При объявлении указателей на указатели возможна их одновременная инициализация. Например:
int a=5; int *p1=&a;
int **pp1=&p1;
int ***ppp1=&pp1;
Теперь присвоим целочисленной переменной а новое значение, например 10. Одинаковое присваивание произведут следующие операции:
a=10;
*p1=10;
**pp1=10;
***ppp1=10;
Для доступа к области памяти, отведенной под переменную а можно использовать и индексы. Справедливы следующие аналоги:
*p1 равносильно p1[0]
**pp1 равносильно pp1[0][0]
***ppp1 равносильно ppp1[0][0][0]
Таким образом, указатели на указатели – это имена многомерных массивов.
Очевидна эквивалентность выражений:
&name[0][0] <-> &(**name) <-> name // адрес нулевого элемента матрицы
**name <-> name[0][0] // значение нулевого элемента матрицы
Динамическая память, функции и операции работы с памятью.
Если в задаче заранее неизвестно количество объектов и объект описан указателем удобно использовать динамическое размещение данных.
Прототипы функций работы с памятью находятся в библиотеке alloc.h, рассмотрим основные из них:
void *calloc(unsigned n, unsigned m); - возвращает указатель на начало области памяти для размещения n элементов по m байт каждый, при неудачном завершении возвращает значение NULL;
void *malloc(unsigned n); - возвращает указатель на блок памяти длиной n байт, при неудачном завершении возвращает значение NULL;
void *realloc(void *bf, unsigned n);- изменяет размер ранее выделенной памяти с адресом начала bf на n байт;
void free(void *bf); - освобождает ранее выделенный блок памяти с адресом bf;
coreleft(void); - возвращает значение объема неиспользованной памяти (тип возвращаемого результата unsigned – для моделей памяти tiny, small, medium; unsigned long – для других моделей памяти).
Пример выделения памяти для массива действительных чисел размером n:
float *x; // Указатель объекта типа float – x[0]
int n; // Количество элементов массива
. . .
x=(float*)calloc(n,sizeof(float)); // Захват памяти для n элементов
. . .
free(x); // Освобождение памяти
В С++ введены две операции: захват памяти - new и освобождение захваченной ранее памяти - delete.
Общий формат записи:
указатель = new тип (значение);
. . .
delete указатель;
Например:
int *a;
a = new int (8);
данном случае создана целочисленная динамическая переменная, на которую установлен указатель a и которой присвоено начальное значение 8. После работы с ней освобождаем память:
delete a;
Операции new для массивов:
указатель = new тип [количество] ;
Результат операции – адрес начала области памяти для размещения данных, указанного количества и типа; при нехватке памяти – NULL.
Операция delete для массивов:
delete [ ] указатель;
