Скачать презентацию Указатели Алтайский государственный университет Математический факультет Кафедра информатики Скачать презентацию Указатели Алтайский государственный университет Математический факультет Кафедра информатики

11_Pointers.ppt

  • Количество слайдов: 44

Указатели Алтайский государственный университет Математический факультет Кафедра информатики Барнаул 2013 Указатели Алтайский государственный университет Математический факультет Кафедра информатики Барнаул 2013

План Лекция 12 n План ¨ Указатели и массивы ¨ Динамические массивы Указатели на План Лекция 12 n План ¨ Указатели и массивы ¨ Динамические массивы Указатели на функции ¨ Указатели и параметры функций ¨ Сложные описания с указателями 2

Несколько заданий для самопроверки Несколько заданий для самопроверки

4 Три задания для самопроверки Задание 1 n Какие из следующих описаний массивов являются 4 Три задания для самопроверки Задание 1 n Какие из следующих описаний массивов являются корректными? int A[3]={1, 3, 5}; int B[3]={11, 22}; int C[3]={0, 1, 2, 3}; Да Да Нет int D[1. . 3]; Нет int M[3]; Да int N[]={10, 20, 30, 40}; Да int P[3, 5]; Нет int Q[2][2]={{0}, {0}}; Да

Три задания для самопроверки Задание 2 n Что выведет программа? #include <stdio. h> void Три задания для самопроверки Задание 2 n Что выведет программа? #include void main() { int i, M[3]={1}; for(i=0; i<3; i++) printf(”%d”, M[i]); } 100 5

Три задания для самопроверки Задание 3 n Что делает программа? Что стоит исправить? #include Три задания для самопроверки Задание 3 n Что делает программа? Что стоит исправить? #include #define N 1000 void main() { int i, M[N], S 1=0, S 2=0; for(i=0; i

Три задания для самопроверки Задание 4 n В каком порядке в памяти располагаются элементы Три задания для самопроверки Задание 4 n В каком порядке в памяти располагаются элементы описанного следующим образом массива? int M[3][2]; a) A[1][1] A[1][2] A[2][1] A[2][2] A[3][1] A[3][2] b) A[0][0] A[1][0] A[2][0] A[0][1] A[1][1] A[2][1] Так c) A[0][0] A[0][1] A[1][0] A[1][1] A[2][0] A[2][1] d) A[0][0] A[0][1] A[1][0] A[0][2] A[2][0] A[2][3] 7

Указатели n n n Адреса переменных Что такое указатель? Значение NULL Операции над указателями Указатели n n n Адреса переменных Что такое указатель? Значение NULL Операции над указателями Нетипизированные указатели Указатели и const

Организация курса Что такое адрес переменной? Память: Адрес: 0 x 2 c 4 b Организация курса Что такое адрес переменной? Память: Адрес: 0 x 2 c 4 b 1 0 x 2 c 4 b 2 0 x 2 c 4 b 3 0 x 2 c 4 b 4 0 x 2 c 4 b 5 0 x 2 c 4 b 6 0 x 2 c 4 b 7 n Оперативная память организована как последовательность ячеек (байт) n Каждая ячейка имеет собственный адрес (порядковый номер) n Адрес – целое число, чаще записываемое в шестнадцатеричной системе счисления 9

10 Организация курса Что такое адрес переменной? x y a Память: Адрес: 0 x 10 Организация курса Что такое адрес переменной? x y a Память: Адрес: 0 x 2 c 4 b 1 0 x 2 c 4 b 2 0 x 2 c 4 b 3 0 x 2 c 4 b 4 0 x 2 c 4 b 5 0 x 2 c 4 b 6 0 x 2 c 4 b 7 n Каждая переменная размещается в последовательных ячейках (количество ячеек зависит от типа переменной) n Адрес переменной – адрес первой из этих ячеек

11 Организация курса Как получить адрес переменной? x Память: Адрес: 10 y 127 a 11 Организация курса Как получить адрес переменной? x Память: Адрес: 10 y 127 a 20031 0 x 2 c 4 b 2 0 x 2 c 4 b 3 0 x 2 c 4 b 4 0 x 2 c 4 b 5 0 x 2 c 4 b 6 0 x 2 c 4 b 7 n Адрес переменной можно получить с помощью операции & n Например, &x даст адрес x: . . . printf(“x=%d, &x=%p”, x, &x); . . . x=10, &x=2 c 4 b 1

12 Организация курса Что такое указатель? x Память: Адрес: n 10 0 x 2 12 Организация курса Что такое указатель? x Память: Адрес: n 10 0 x 2 c 4 b 1 0 x 2 c 4 b 2 p 0 x 2 c 4 b 1 … … Указатель – переменная, хранящая адрес 0 x 2 c 4 b 8 0 x 2 c 4 b 9 0 x 2 c 4 ba 0 x 2 c 4 bb n Операция разадресации * – обратная к операции & int x; /*целая переменная*/ int *px; /*указатель*/ int x=10, y; int *px; px = &x; /*присвоить адрес*/ px = &x; /*взять адрес*/ y = *px; /*взять значение по адресу px, y=10*/ *px = 20; /* <=> x=20 */

Организация курса Значение NULL n Помимо адресов, указатель может принимать специальное значение NULL, обозначающее Организация курса Значение NULL n Помимо адресов, указатель может принимать специальное значение NULL, обозначающее недействительный адрес int *px; /*указатель*/ px = NULL; /*присвоить NULL*/ n NULL – макроконстанта n NULL чаще всего (но не всегда!) равен 0 n Разадресовывать указатель со значением NULL небезопасно! 13

Организация курса Операции над указателями n Указатель может быть инициализирован int y, *px=NULL, *py=&y, Организация курса Операции над указателями n Указатель может быть инициализирован int y, *px=NULL, *py=&y, *pz=py; /* инициализация */ n Указателю можно присваивать значение int x=10, y=20, *px, *py; px=&x; py=px; n Указатель можно сравнивать: < > <= >= == != (т. е. вычислять отношения адресов) int x=10, y=20, *px=&x, *py=&y; if( px == py ). . . 14

15 Организация курса Операции над указателями n Указатель может складываться с целым числом N. 15 Организация курса Операции над указателями n Указатель может складываться с целым числом N. Результат сложения – адрес, смещенный на N компонент соответствующего типа относительно исходного short x=10, *px=&x; /* инициализация */ px 0 x 2 c 4 b 3 x 0 … 10 345 … 0 x 2 c 4 b 1 0 x 2 c 4 b 2 0 x 2 c 4 b 3 0 x 2 c 4 b 4 0 x 2 c 4 b 5 0 x 2 c 4 b 6 …

16 Организация курса Операции над указателями n Указатель может складываться с целым числом N. 16 Организация курса Операции над указателями n Указатель может складываться с целым числом N. Результат сложения – адрес, смещенный на N компонент соответствующего типа относительно исходного short x=10, *px=&x; /* инициализация */ px=px+1; px 0 x 2 c 4 b 5 x 0 … 10 345 … 0 x 2 c 4 b 1 0 x 2 c 4 b 2 0 x 2 c 4 b 3 0 x 2 c 4 b 4 0 x 2 c 4 b 5 0 x 2 c 4 b 6 …

17 Организация курса Операции над указателями n Указатель может складываться с целым числом N. 17 Организация курса Операции над указателями n Указатель может складываться с целым числом N. Результат сложения – адрес, смещенный на N компонент соответствующего типа относительно исходного short x=10, *px=&x; /* инициализация */ px=px+1; px=px-2; px 0 x 2 c 4 b 1 x 0 … 10 345 … 0 x 2 c 4 b 1 0 x 2 c 4 b 2 0 x 2 c 4 b 3 0 x 2 c 4 b 4 0 x 2 c 4 b 5 0 x 2 c 4 b 6 …

18 Организация курса Операции над указателями n Указатель может складываться с целым числом N. 18 Организация курса Операции над указателями n Указатель может складываться с целым числом N. Результат сложения – адрес, смещенный на N компонент соответствующего типа относительно исходного short x=10, *px=&x; /* инициализация */ px=px+1; px=px-2; px++; px 0 x 2 c 4 b 3 x 0 … 10 345 … 0 x 2 c 4 b 1 0 x 2 c 4 b 2 0 x 2 c 4 b 3 0 x 2 c 4 b 4 0 x 2 c 4 b 5 0 x 2 c 4 b 6 …

19 Организация курса Операции над указателями n Указатель может складываться с целым числом N. 19 Организация курса Операции над указателями n Указатель может складываться с целым числом N. Результат сложения – адрес, смещенный на N компонент соответствующего типа относительно исходного short x=10, *px=&x; /* инициализация */ px=px+1; px=px-2; px++; *(px+1)+=1; px 0 x 2 c 4 b 3 x 0 … 10 346 … 0 x 2 c 4 b 1 0 x 2 c 4 b 2 0 x 2 c 4 b 3 0 x 2 c 4 b 4 0 x 2 c 4 b 5 0 x 2 c 4 b 6 …

20 Организация курса Операции над указателями n Можно вычислять разность однотипных указателей, которая равна 20 Организация курса Операции над указателями n Можно вычислять разность однотипных указателей, которая равна относительному смещению с учетом типа указателя short *px=0 x 2 c 4 b 1, *py=0 x 2 c 4 b 5, d; d = py-px; /* 2 */ px py 0 x 2 c 4 b 1 0 x 2 c 4 b 5 … d 0 … 10 346 … 0 x 2 c 4 b 1 0 x 2 c 4 b 2 0 x 2 c 4 b 3 0 x 2 c 4 b 4 0 x 2 c 4 b 5 0 x 2 c 4 b 6 …

Организация курса Нетипизированный указатель n Типизированные указатели (int *, char *, double *, …) Организация курса Нетипизированный указатель n Типизированные указатели (int *, char *, double *, …) неявно задают длину фрагмента памяти (4, 1, 8, …), начинающегося с адреса, хранимого указателем n Длина важна при разадресации и адресной арифметике n Однако иногда приходится использовать указатели, не подразумевая длины адресуемого фрагмента памяти – void * n Разадресация указателя void * невозможна! n Указатель void * совместим по типу со всеми типизированными указателями int i=10, *pi=&i; double d=3. 14, *pd=&d; void *p; p=pi; /* Ok */ p=pd; /* Ok */ *p=*p+1; /* Ошибка! */ 21

Организация курса Указатели и const n Два способа описания константного указателя n Неизменяемый указатель Организация курса Указатели и const n Два способа описания константного указателя n Неизменяемый указатель ¨ Синтаксис: TYPE * const ptr. Name = &a. TYPEVar; ¨ Переменная-указатель – константа (не может изменяться) ¨ Данные, адресуемые указателем – изменяемые int a=42, b=42; int* const ptr=&a; *ptr=1; /* Ok */ ptr=&b /* Ошибка! */ 22

Организация курса Указатели и const n Два способа описания константного указателя n Указатель на Организация курса Указатели и const n Два способа описания константного указателя n Указатель на неизменяемые данные ¨ Синтаксис: const TYPE * ptr. Name = &a. TYPEVar; ¨ Переменная-указатель – может изменяться ¨ Данные, адресуемые указателем – неизменяемые int a=42, b=42; const int *ptr=&a; *ptr=1; /* Ошибка! */ ptr=&b /* Оk */ 23

Указатели и массивы n n n Указатели и массивы Массивы как параметры функций Указатели Указатели и массивы n n n Указатели и массивы Массивы как параметры функций Указатели на многомерные массивы

25 Указатели и массивы n n Указатели и массивы очень тесно связаны в языке 25 Указатели и массивы n n Указатели и массивы очень тесно связаны в языке Си Имя массива – константный указатель на 0 -й элемент массива short a[100]; short *ps; <=> ps = &a[0]; n short a[100]; short *ps; ps = a; a[i] == *(a+i) ps a+1 a a+2 *(a+1) *a … = = = a[1] a[0] 33 *(a+2) 36 a[2] 15 … 0 x 2 c 4 b 1 0 x 2 c 4 b 2 0 x 2 c 4 b 3 0 x 2 c 4 b 4 0 x 2 c 4 b 5 0 x 2 c 4 b 6 …

26 Указатели и массивы n n a[i] == *(a+i) == *(i+a) == i[a] a[2] 26 Указатели и массивы n n a[i] == *(a+i) == *(i+a) == i[a] a[2] == *(a+2) == *(2+a) == 2[a] short a[100]; for (i=0; i<100; i++) scanf(“%h”, &a[i]); <=> short a[100]; short *ps=a; for (i=0; i<100; i++) scanf(“%h”, &ps[i]); short a[100]; <=> <= > for (i=0; i<100; i++) scanf(“%h”, a+i); short a[100]; short *ps; for (ps=a; ps==a+100; ps++) scanf(“%h”, ps);

27 Указатели и массивы n Синонимичные выражения n Передача массива в функцию как параметра 27 Указатели и массивы n Синонимичные выражения n Передача массива в функцию как параметра int a[10]; f(a); /* или */ f(&a[0]); void f(int *array){ . . . } /*или*/ void f(int array[]){ . . . }

Указатели и массивы Указатели на многомерные массивы n n n Для вычисления адреса элемента Указатели и массивы Указатели на многомерные массивы n n n Для вычисления адреса элемента двумерного массива компилятору нужно «знать» количество столбцов в матрице (т. е. мало знать начальный адрес масива) Пусть нужно передать в функцию массив int array[3][15], чтобы ее вызов выглядел так: f(array) Возможны следующие идентичные варианты описания функции f: f(int x[3][15]) { … } ¨ f(int x[][15]) { … } ¨ f(int (*x)[15]) { … } ¨ n Важно: в последнем случае нельзя опустить скобки! ¨ f(int *x[15]) { … } – передается массив из 15 указателей на int, а не указатель на массив из 15 int-ов 28

Динамические массивы n n n Динамические массивы Выделение памяти, malloc() Освобождение памяти, free() Динамические массивы n n n Динамические массивы Выделение памяти, malloc() Освобождение памяти, free()

30 Динамические массивы n n n Часто размер массива заранее не известен, а известен 30 Динамические массивы n n n Часто размер массива заранее не известен, а известен лишь в момент исполнения Требуется динамически распределять массив в памяти Стандартная функция malloc() позволяет запросить память у ОС Для использования malloc() нужно подключать stdlib. h Полный прототип функции: void *malloc(size_t size); Указатель на первый байт массива или NULL, если выделить память не удалось n Требуемое количество байт malloc() возвращает нетипизированный указатель на начальный байт выделенного массива. Для дальнейшего использования обычно указатель преобразуют в типизированный

Динамические массивы n Шаблон программы, использующей динамический массив #include <stdio. h> #include <stdlib. h> Динамические массивы n Шаблон программы, использующей динамический массив #include #include void main(){ int *a; /* Выделение 4 Мб памяти = 1 Мб int-ов */ a = (int *)malloc(1024*sizeof(int)); if(a == NULL) { printf(“Ошибка выделения памяти. n”); return; } . . . /* Работа с элементами a[i] */ /* Освобождение памяти */ free(a); } 31

32 Динамические массивы n n Выделенную память необходимо освобождать Стандартная функция free() позволяет освободить 32 Динамические массивы n n Выделенную память необходимо освобождать Стандартная функция free() позволяет освободить память , выделенную malloc() n Блоки памяти освобождаются целиком, т. е. невозможно частичное освобождение (см. также функцию realloc()) n Полный прототип функции: void free(void *ptr); Адрес начала освобождаемого фрагмента памяти

Указатели на функции n n Указатели на функции Пример Указатели на функции n n Указатели на функции Пример

34 Указатели на функции n n Укaзатель на функцию содержит адрес тела функции Как 34 Указатели на функции n n Укaзатель на функцию содержит адрес тела функции Как описывается указатель на функцию? Тип возвращаемого значения функции Указатель на функцию float myfun(int a, float b) { return a+b; }. . . float (*fptr)(int, float); fptr = myfun; . . . x=fptr(42, 3. 14 f); . . . Тип параметра функции Указатель на функцию, воспринимающую параметры типов int и float и возвращающую float Вызов функции по указателю

35 Указатели на функции: пример int add(int x, int y) { return x+y; } 35 Указатели на функции: пример int add(int x, int y) { return x+y; } int sub(int x, int y) { return x-y; } int mul(int x, int y) { return x*y; } int div(int x, int y) { return x/y; } Операции пронумерованы 0 – add, 1 – sub, 2 – mul, 3 – div int evaluate(unsigned int op, int x, int y) { int (*eval[])(int, int) = { add, sub, mul, div }; if (op>3) { printf(“Недопустимая операция”); return 0; } return eval[op](x, y); } void main() { printf(“%dn”, evaluate(3, 42, 3)); } Массив из указателей на функции вида int f(int, int) Вызов подходящей функции

Указатели и параметры функций n Указатели в параметрах функций Указатели и параметры функций n Указатели в параметрах функций

37 Указатели и параметры фугкций Как передаются параметры через указатель? n В функцию передается 37 Указатели и параметры фугкций Как передаются параметры через указатель? n В функцию передается не значение, а адрес переменной Для доступа к значению переменной используется операция разадресаци и #include void swap(int *x, int *y) { int t; t = *x; *x = *y; *y = t; } void main() { int a=5, b=10; swap(&a, &b); printf(“a=%d, b=%dn”, a, b); } При описании параметров функции используются указатели При вызове функции как параметр передается адрес переменной

38 Указатели и параметры фугкций Как изменить переменную в вызывающей функции? a b 5 38 Указатели и параметры фугкций Как изменить переменную в вызывающей функции? a b 5 x y t 10 #include void swap(int *x, int *y) { int t; t = *x; *x = *y; *y = t; } void main() { int a=5, b=10; swap(&a, &b); printf(“a=%d, b=%dn”, a, b); } x = &a; /*в х – адрес a*/ y = &b; /*в y – адрес a*/ t = *x; /*в t поместить значение, хранящееся по адресу x*/ *X = *y; /*по адресу x записать значение, хранящееся по адресу y*/ *y = t; /*по адресу y записать значение, хранящееся в t*/

Сложные описания с указателями n n n Сложные объявления Правила чтения сложных объявлений Класс Сложные описания с указателями n n n Сложные объявления Правила чтения сложных объявлений Класс памяти typedef

Сложные описания с указателями n char **argv: указатель на char n int (*x)[13] x: Сложные описания с указателями n char **argv: указатель на char n int (*x)[13] x: указатель на массив из 13 int-ов n int *x[13] x: массив из 13 указателей на int n void *comp() comp: функция, возвращающая указатель на void n void (*comp)() comp: указатель на функцию, возвращающую void n char (*(*x())())[5] x: функция, возвращающая указатель на массив из 5 указателей на функцию, возвращающую char n char (*(*x[3])())[5] x: массив из 3 указателей на функцию, возвращающую указатель на массив из 5 char-ов 40

Сложные описания с указателями double **d[8] /* хмм. . . */ char *(*(**foo [][8])())[] Сложные описания с указателями double **d[8] /* хмм. . . */ char *(*(**foo [][8])())[] /* упс! что такое foo? */ n Чтобы понять подобные сложные объявления используйте следующие три правила: Начинайте с имени переменной (d или foo в примерах выше) ¨ Заканчивайте на имени типа (double или char выше) ¨ ¨ n Идите вправо пока можно, затем влево (влево необходимо идти при обнаружении закрывающейся скобки) Например 41

Сложные описания с указателями double **d[8] /* хмм. . . */ char *(*(**foo [][8])())[] Сложные описания с указателями double **d[8] /* хмм. . . */ char *(*(**foo [][8])())[] /* упс! что такое foo? */ n Еще пример 42

Сложные описания с указателями double **d[8] /* хмм. . . */ char *(*(**foo [][8])())[] Сложные описания с указателями double **d[8] /* хмм. . . */ char *(*(**foo [][8])())[] /* упс! что такое foo? */ n n Как можно упростить понимание сложных объявлений? Ответ: использовать оператор typedef float real; /* real – синоним float */ typedef unsigned char byte; /* byte – синоним unsigned char */ typedef int *INTPTR; /* INTPTR – синоним int* */ typedef void (*FUNCPTR)(); /* FUNCPTR – указатель на функцию */ /* с прототипом void f() */ real r=0. 0; /* то же, что и float r=0. 0 */ byte b=0; /* то же, что и unsigned char b=0 */ INTPTR p; /* то же, что и int *p */ FUNCPTR pf; /* то же, что и void (*pf)() */ FUNCPTR paf[10]; /* массив из указателей на функции void (*pf)() */ 43

44 Вопросы и ответы Вопросы? n n n Указатели и массивы Динамические массивы Указатели 44 Вопросы и ответы Вопросы? n n n Указатели и массивы Динамические массивы Указатели на функции Указатели и параметры функций Сложные описания с указателями Н. Копейкин Металлурги и компьютер