Присваивание указателей

Дополнительные сведения о разыменовании указателей

Операции с указателями

Недействительный указатель

Недействительный указатель (invalid pointer) – это ненулевой указатель, содержимое которого не является адресом переменной или функции. Любое использование недействительного указателя (разыменование такого указателя, сравнение его со значением NULL, передача его в качестве параметра в функцию) в стандарте языка Си приводит к неопределенному поведению программы. Рассмотрим возможные причины появления недействительных указателей.

Имеется ряд причин появления недействительных указателей:

· Отсутствие инициализации указателей,

· Ошибки, допущенные при преобразовании целочисленных значений к указательному типу.

· Освобождение динамической памяти.

· Ошибки, допущенные при использовании адресной арифметики.

Здесь ограничимся рассмотрением только первой из перечисленных выше причин. Одна из наиболее распространенных причин появление недействительных указателей связана с отсутствием инициализации указателей. Ниже приводится типичный пример программного кода, в котором используется неинициализированный указатель.

 

/* Ошибка в программном коде*/

double x;
double* pn;
x = modf(10.2, pn); // Использование неинициализированного
// указателя
/* .............................*/

В языке Си указатели наделены большими возможностями. Об этом свидетельствует размер перечня тех операций, которые можно выполнять с указателями:

· Разыменование,

· Взятие адреса,

· Присваивание,

· Индексирование указателей

· Арифметические действия с указателями,

· Сравнение указателей.

Как отмечалось выше, разыменование – операция позволяющая получить доступ к объекту, на который установлен указатель. Однако эта операция допустима не ко всем указателям. Остановимся на тех категориях указателей, к которым нельзя применять разыменование:

· Недействительный указатель.

· Нетипизированный указатель.

· Нулевой указатель

Приведем примеры недопустимых разыменований.

 

/* Примеры недопустимых разыменований указателей */

int* p = NULL;

*p = 10; /* Недопустимо разыменовывать нулевой указатель*/

int n = 5;
void* p3 = &n;
*p3 = 10; /* Недопустимо разыменовывать нетипизированный
указатель p3*/

char* p4;

*p4 = ’A’; /* Недопустимо разыменовывать
неинициализированный указатель p4 */
/* . . . . . . . . . . . . . . . . . . . . . . . . . . . */

 

Заметим, что к категории операторов разыменования относятся еще два оператора:

· Оператор [], который используется при работе с массивами.

· Оператор ->, который используется при работе со структурами.

Одному указателю можно присвоить значение другого указателя. Однако некоторые присваивания, которые допускает язык Си, могут привести к некорректной работе программы. Остановимся на этом вопросе подробнее. Рассмотрим ряд частных случаев. Начнем с присваивания типизированных указателей. Корректность такой операции не вызывает сомнений только в том случае, когда совпадают базовые типы обоих указателей. В противном случае такую операцию следует считать недопустимой. Приведем пример программного кода, в котором будут встречаться оба вида присваиваний.

 

/* Корректные и некорректные присваивания типизированных
указателей */
int n = 10;
double x = 20.3;
int *p1, p2;
double* p3;


p1 = &n; /* допустимое присваивание */
p2 = p1; /* допустимое присваивание */
p3 = p2; /* недопустимое присваивание, т. к. не
совпадают базовые типы указателей */
/* конец программного кода примера */

Отметим, что, несмотря на семантическую недопустимость присваивания p3 = p1 в приведенном выше примере компилятор языка Си ограничивается выводом предупреждения (Компилятор языка С++ в этой ситуации выводит сообщение об ошибке). Работа языка Си с указателями свидетельствует о его пониженной типизации. Это обстоятельство следует рассматривать как крайне опасным последствиям. Одна из рекомендаций по преодолению этих неприятностей заключается в предварительной компиляции программного кода компилятором языка С++.

Одному указателю можно присвоить значение другого указателя. Однако некоторые присваивания, которые допускает язык Си, могут привести к некорректной работе программы. Остановимся на этом вопросе подробнее. Рассмотрим ряд частных случаев. Начнем с присваивания типизированных указателей. Корректность такой операции не вызывает сомнений только в том случае, когда совпадают базовые типы обоих указателей. В противном случае такую операцию следует считать недопустимой. Приведем пример программного кода, в котором будут встречаться оба вида присваиваний.

 

/* Корректные и некорректные присваивания типизированных
указателей */
int n = 10;
double x = 20.3;
int *p1, p2;
double* p3;


p1 = &n; /* допустимое присваивание */
p2 = p1; /* допустимое присваивание */
p3 = p2; /* недопустимое присваивание, т. к. не совпадают
базовые типы указателей */
/* конец программного кода примера */

Отметим, что, несмотря на недопустимость присваивания p3 = p1 в приведенном выше примере компилятор языка Си ограничивается выводом предупреждения (Компилятор языка С++ в этой ситуации выводит сообщение об ошибке).