Находится в неопределенном состоянии.
Находится в нулевом состоянии.
Указывает на какой-то адрес.
p
|
|
p
p
|
Над указателями можно совершать ряд арифметических действий. При этом предполагается, что если указатель p относится к типу int*, то p указывает на элемент некоторого массива типа int. Тогда р+1 является указателем на следующий элемент этого массива, а р-1 – указателем на предыдущий элемент. Аналогично определяются выражения р+n, n+p и р-n, а также действия p++, p--, ++p, --p, p+=n, p-=n, где n – целое число. Важно отметить, что арифметические действия с указателями выполняются в единицах того типа, к которому относится указатель. То есть р+n, преобразованное к целому типу, содержит на sizeof(int)*n большее значение, чем p.
Из равенства p+n==p1 следует, что p1-p==n. Именно так вводится оператор разности двух указателей: его значением является целое, равное количеству элементов массива от p до p1. Отметим, что это – единственный случай в языке, когда результат бинарного оператора с операндами одного типа принадлежит к принципиально другому типу.
Сумма двух указателей не имеет смысла и поэтому не определена. Не определены также арифметические действия над нетипизированными указателями void*.
Наконец, все указатели, в том числе и нетипизированные, можно сравнивать, используя операторы отношения >, <, >=, <=, ==, !=.
Следующий листинг суммирует элементы массива:
int a[10],s;
for (int* p=&a[0]; p<=&a[9]; p++)
s+=*p;
Процедуры и функции для работы с динамической памятью:
p=new int– выделяет память и заносит в р.
Delete p – освобождает участок памяти, на который указывает указатель р.
CoreLeft – возвращает размер в байтах общего свободного пространства динамической памяти. Пример: cout << "Cвободной динамической памяти = "<<coreleft()<<" байт";
Sizeof(x) –возвращает длину в байтах переменной х.
Пример: sizeof(integer) = 2б.
void *malloc(size_t p) -возвращает указатель на n байт неинициализированной памяти или NULL, если запрос удовлетворить нельзя.
void *calloc(size_t p, size_t size) -возвращает указатель на область, достаточную для хранения массива из n объектов указанного размера (size), или NULL, если запрос не удается удовлетворить. Выделенная память обнуляется. Здесь р – нетипизированный указатель, size – длина в байтах освобождаемого фрагмента.
free(p) - освобождает область памяти, на которую указывает p, - указатель, первоначально полученный с помощью malloc или calloc.
· Копирование данных
P1 = New int;
P2 = New int;
p1 *p1
*p1 = 2*p1=*p2
p2 *p2*p2 = 1*p1=*p2
p1<>p2
· Присваивание
p1=p2
· Передача адреса
int x;
int *p;
{
p:=&x;
…
}
Пример:Разыменование указателей.
char c1 = 'a';
char* p = &c1 // в p хранится адрес c1
char c2 = *p; // c2 = 'a'
Переменная, на которую указывает p - это c1, а значение, которое хранится в c1, это 'a', поэтому присваиваемое c2 значение *p есть 'a'.
Общие проблемы работы с указателями.
1.Разыменование неинициализированных указателей.
Если разыменовать указатель в неопределенном состоянии, то можно затереть важные данные, так как указатель может содержать случайный адрес.
2.Потеря динамически распределяемой памяти.
Чаще, выделение памяти в больших программах в далеко отстоящих местах.
P = new int;
Delete p;
p=NULL;
if (p==NULL) p = new int;
1.3 Динамические
Списки
Стеки
Очереди
Пирамиды
Деревья
Каждый элемент динамической структуры содержит как минимум два поля, то есть является записью:
1- указатель;
2- данные;
Введем обозначения:
1.
- элемент динамической структуры
Next – указывает на следующий элемент.
2. head – вершина
tail – хвост
queue – очередь
stack - стек
3.
struct pLE{
struct pLE *next;
int Data;
} *phead;
Линейный список – последовательность однородных элементов, линейно связанных между собой указателями.
Допустимые операции:
- добавление
- удаление
- вставка элементов после заданного элемента
- удаление из середины
Стек работает по принципу LIFO, очередь – FIFO.