Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка по С Живицкая (Мет пособие).doc
Скачиваний:
112
Добавлен:
15.06.2014
Размер:
2.11 Mб
Скачать

2.4.6. Указатели на указатели многочисленные или перенаправления.

Концепция указателей открыта и проста, так как индексы имеют определенное значение. Однако в случае, когда один указатель указывает на другой, могут возникнуть проблемы, указатель на указатель является формой многочисленного перенаправления или цепочки указателей.

Рисунок: Одиночное перенаправление.

указатель переменная

Рисунок: Многочисленное перенаправление.

Указатель указатель переменная

В случае обычных указателей указатель содержит адрес некоторого участка памяти, содержащего некоторые значение. В случае указателя на указатель, первый указатель содержит адрес второго, который в свою очередь содержит адрес участка памяти, содержащего некоторое значение.

Многочисленное перенаправление может и дальше расширяться, но существует не много случаев, когда необходимо что-то более мощное, чем указатель на указатель, излишнее перенаправление приводит к концептуальным ошибкам, которые трудно исправлять. Переменая является указателем на указатель должна быть описана следующим образом. Это выполняется путем помещения 2-х * * перед именем.

Например, следующее объявление сообщает компелятору, что newbalance это указатель типа float

float* *newbalance;

При этом newbalance – это не указатель на число с плавающей точкой, а указатель на указатель на вещественное число. Для получения доступа к целевому значению косвенно указываемому указатель на указатель следует применить оператор " * " два раза, как показано в следующем примере.

Пример:

# include < stdio.h >

int main (void)

{ intx, *p, * *q;

x= 10;

p= &x;

printf (" % d", * * q); / * вывод значения х * /

return 0;

}

2.4.7. Указателина структуры.

2.4.7.1.Объявление указателей на структуру.

Указатели на структуру объявляются путем помещения * перед именем структуры переменной. Например предположим, что ранее была определена структура addr, следующая строка объявляет addr_pointer, как указатель на данные этого типа.

Пример:

struct_addr * addr_pointer;

2.4.7.2.Использование указателей на структуру.

Для получения адреса структурной переменной следует поместить оператор & перед именем структуры.

Пусть имеется следующий фрагмент программы,

struct bal {

float balance;

char name [80];

} person;

struct bal * p; /* объявление указателя на структуру * /

тогда p = & person, помещает адрес структуры person в указатель p. Для доступа к членам структуры с помощью указателя на структуру следует использовать оператор -> . Оператор -> образован из знака " - " и символа " > ".

Например,для доступа к члену balance c помощью p следует написать

p -> balance

Примечание: Для доступа к членам структуры при работе с самой структурой используется оператор ". ". При обращении к структуре с помощью указателя используется оператор " -> ".

2.4.8. Рекомендации по програмированию.

1) При работе с указателями необходимо внимательно выполнять операции увеличение и уменьшение.

Напримервыражения дают различные результаты.

a) (*p) ++

б) * p++

в) * ++ p

В первом случае увеличивается значение переменной, размещенной по указателю p.

Во втором случае извлекается значение по указателю p, а затем значение указателя p увеличивается.

В третьем случае сначала увеличивается значение указателя, а затем извлекается значение переменной размещенной по новому адресу.

При выполнении операции увеличение и уменьшение на количество байтов, занимаемое переменной, связанной с указателями.

2) Операция увеличение и уменьшение постфексные и префиксные не могут применяться к имени массива, т.к. имя массива является константой указателя.

Применение операции увеличение или уменьшение к константам вызовет ошибку. Чтобы избежать oшибок надо описать указатель, того же типа, что и массив и присвоить ему адрес первого элемента т.е. имя массива.

Пример:

int a [10], * p;

a++; / * ошибка * /

p=a;

p++;

3) Определение int a [ ]; и определение int * a; эквивалентны.Оба определения говорят, что а является указателем на целое.

4) Следует различать выражения

char( *fun) ( );

char*fun( );

В первом случае определяется указатель на функцию.

Второй оператор описывает функцию, возвращающую указатель на символ.

5) Классическим примером ошибки с указателем является неинецилизированный указатель.

Пример:

/ * неправильная программа * /

int main ( void )

{ int x, * p;

x = 10;

* p = x;

return 0;

}

Данная программа присваивает значение 10 некоторому неизвестному участку памяти.

Указатель p не получает адреса памяти, который можно использовать. Следовательно, он содержит неопределенное значение. Такого рода ошибки часто незаметны в небольших программах, но для больших программ велика вероятность зависания. Решение: Следует убедиться, что указатель указывает на некоторую допустимую область. Частая инициализация указателей или некоректная инициализация затрудняет поиск ошибок.