русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

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


Дата добавления: 2013-12-23; просмотров: 1396; Нарушение авторских прав


Пример 2.

Пример 1.

int (*fun) (double, double);

задает указатель с именем fun на функцию, возвращающую значение типа int и имеющую два аргумента типа double.

void f (int x) { ... }  
void (*pf)(int); // Указатель на функцию. Скобки обязательны!
void g(){  
pf = &f; // pf указывает на функцию f
pf(0); // Вызов функции f через указатель pf
}  

Компилятор распознаёт, что pf является указателем и вызывает функцию, на которую он указывает. То есть, разыменование указателя на функцию при помощи операции * необязательно. Аналогично, необязательно пользоваться операцией & для получения адреса функции.

Параметры указателей на функцию объявляются точно так же, как и параметры самих функций. При присваивании типы функций должны в точности совпадать.

typedef void (*PF)(int); // Для объявления типа «указатель на функцию» можно использовать объявление typedef
PF pf; // Объявляем сам указатель на функцию, используя предварительно определённый тип
void f1(int x) { ... } int f2(int x) { ... } void f3(char x) { ... }  
void f (){  
pf = &f1; // Правильно
pf = &f2; // Ошибка - не тот возвращаемый тип
pf = &f3; // Ошибка - не тот тип параметра
}  

Правила передачи параметров при вызове функций через указатель те же самые, что и при непосредственном вызове функций.

С указателями можно выполнять следующие операции: разадресация (*), присваивание, сложение с константой, вычитание, инкремент (++), декремент (––), сравнение, приведение типов. При работе с указателями часто используется операция получения адреса (&).

 

Существуют две операции, которые имеют отношение к работе с указателями. Этими операциями являются:



· операция взятия адреса (адресация) &;

· операция взятия значения по адресу (косвенная адресация или разыменование) *.

int a, *p;  
p = &a; // Переменной p присваивается адрес переменной a
*p = 0; // Значение по адресу, находящемуся в переменной p (т.е. значение переменной а), становится равным 0

Ссылка является альтернативным именем объекта. Ссылка – это объект, который синтаксически выглядит как переменная, а по семантике является адресом. Объявление ссылки, кроме случаев, когда ссылка является параметром функции, возвращаемым функцией значением или членом класса, должно содержать инициализатор. Далее все операции производятся не над самой ссылкой, а над тем объектом, на который она указывает.

int a = 10;  
int &r = a; // Объявляем и инициализируем ссылку
r++; // Значение переменной а становится 11
void f(double &a) { a += 3.14; }  
double d = 0;  
f(d); // d = 3.14
int v[20];  
int& f(int i) { return v[i]; }  
f(3) = 7; // Элементу массива v[3] присваивается 7

На первый взгляд, ссылка является удобной заменой указателю, но она затрудняет понимание программы из-за несовпадения синтаксиса и семантики ссылки. Однако ссылки могут быть полезны для того, чтобы не передавать по значению (и не копировать) параметр функции, который имеет большой размер. В том случае, если мы не собираемся менять этот параметр внутри функции, можно объявить ссылку с модификатором const. В этом случае мы будем гарантированы, что параметр не изменится, вместо большого объекта будет передаваться его адрес, а для пользователя всё будет выглядеть как передача параметра по значению.

class X { ... }; // Описание большого класса
int f (const X& x) { ... }  

Операция разадресации, или разыменования, предназначена для доступа к величине, адрес которой хранится в указателе. Эту операцию можно использовать как для получения, так и для изменения значения величины (если она не объявлена как константа):

char a; //переменная типа charchar * p = new char; //выделение памяти под указатель и под динамическую переменную типа char*p = 'Ю'; a = *p; //присваивание значения обеим переменным

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

#include <stdio.h> int main() { unsigned long int A = 0Xсс77ffaa; unsigned int* pint = (unsigned int *) &A; unsigned char* pchar = (unsigned char *) &A; printf(" | %x | %x |", *pint, *pchar); return 0;}

на IBM PC выведет на экран строку:

| ffaa | aa |

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

При смешивании в выражении указателей разных типов явное преобразование типов требуется для всех указателей, кроме void*. Указатель может неявно преобразовываться в значение типа bool.

Присваивание без явного приведения типов допускается только указателям типа void* или если тип указателей справа и слева от операции присваивания один и тот же.

Присваивание указателей данных указателям функций (и наоборот) недопустимо.

Арифметические операции с указателями (сложение, вычитание, инкремент и декремент) автоматически учитывают размер типа величин, адресуемых указателями. Эти операции применимы только к указателям одного типа и имеют смысл в основном при работе со структурами данных, последовательно размещенными в памяти, например, с массивами.

Инкремент перемещает указатель к следующему элементу массива, декремент — к предыдущему.

Фактически значение указателя изменяется на величину sizeof(тип).

Разность двух указателей — это разность их значений, деленная на размер типа в байтах. Суммирование двух указателей не допускается.

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

*p++ = 10;

То же самое можно записать подробнее:

*p = 10; p++;

Выражение (*p)++, напротив, инкрементирует значение, на которое ссылается указатель.

Унарная операция получения адреса & применима к величинам, имеющим имя и размещенным в оперативной памяти. Нельзя получить адрес скалярного выражения, неименованной константы или регистровой переменной.



<== предыдущая лекция | следующая лекция ==>
Указатели и константы | Тема № 8. Указатели и массивы в языке С.


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.004 сек.