Указатели
Статические данные int x, y = 20; float z, A[10]; char str[80]; • переменная (массив) имеет имя, по которому к ней можно обращаться • размер заранее известен (задается при написании программы) • память выделяется при объявлении • размер нельзя увеличить во время работы программы 2
Динамические данные • размер заранее неизвестен, определяется во время работы программы • память выделяется во время работы программы • нет имени? Проблема: как обращаться к данным, если нет имени? Решение: использовать адрес в памяти Следующая проблема: в каких переменных могут храниться адреса? как работать с адресами? 3
Указатели Указатель – это переменная, значением которой является адрес. (др. словами в которую можно записывать адрес другой переменной или блока памяти). Статическая память Динамическая память Указатель Величина Адрес Значение Адрес величины — это номер первого байта поля памяти, в котором располагается величина. Размер поля однозначно определяется типом. 4
Указатели Объявление: char *p. C; // // int *p. I; // float *p. F; // адрес символа (или элемента массива) адрес целой переменной адрес вещественной переменной Как записать адрес: int m = 5, *p. I; scanf("%d", &m); int A[2] = { 3, 4 }; p. I = & m; // адрес переменной m p. I = & A[1]; // адрес элемента массива A[1] p. I = NULL; // нулевой адрес 5
Обращение к данным Как работать с данными через указатель? int m = 4, n, *p. I; «вытащить» значение по адресу p. I = &m; * printf ("m = %d", * p. I); // вывод значения n = 4*(7 - *p. I); // n = 4*(7 - 4) = 12 *p. I = 4*(n – m); // m = 4*(12 – 4) = 32 printf("&m = %p", p. I); // вывод адреса %p Как работать с массивами? int *p. I, i, A[] = {1, 2, 3, 4, 5, 999}; p. I = A; // адрес A[0] записывается как A while ( *p. I != 999 ) { // while( A[i] != 999 ) *p. I += 2; // A[i] += 2; p. I++; // i++ (переход к следующему) } ! Оператор p. I++ увеличивает адрес на sizeof(int)! 6
Пример
Двойственная природа указателя. Важно: Если указатель указывает на некоторый один адрес памяти, то и работает он со значением из этого адреса. а) Изменяя значение переменной по адресу на который указатель указывает – изменится и значение разыменовываемого указателя б) При присвоении значений разыменованному указателю – изменится значение переменной по указываемому указателем адресу
Вариант а. Изменение значения переменной для указателя
Вариант б. Изменение разыменованного указателя влияет на переменную по адресу указателя
Поиск минимального элемента массива, доступ при помощи указателя
Что надо знать об указателях • указатель – это переменная, в которой можно хранить адрес другой переменной; • при объявлении указателя надо указать тип переменных, на которых он будет указывать, а перед именем поставить знак *; • знак & перед именем переменной обозначает ее адрес; • знак * перед указателем в рабочей части программы (не в объявлении) обозначает значение ячейки, на которую указывает указатель; • для обозначения недействительного указателя используется константа NULL (нулевой указатель); • при изменении значения указателя на n он в самом деле сдвигается к n-ому следующему числу данного типа, то есть для указателей на целые числа на n*sizeof(int) байт; • указатели печатаются по формату %p. Нельзя использовать указатель, который указывает неизвестно куда (будет сбой или зависание)! 12