Похожие презентации:
Указатели и массивы. Указатели и параметры функций. Сложные описания с указателями. (Лекция 11)
1. Указатели
Алтайский государственный университетФакультет математики и ИТ
Кафедра информатики
Барнаул 2014
2. Лекция 11
ПланЛекция 11
План
Указатели
Указатели
и массивы
Динамические массивы Указатели на функции
Указатели и
параметры функций
Сложные описания
с указателями
2
3. Несколько заданий для самопроверки
4. Задание 1
Три задания для самопроверкиЗадание 1
Что выведет программа?
#include <stdio.h>
void main() {
int i, M[3]={1};
for(i=0;i<3;i++)
printf(”%d”, M[i]);
}
100
4
5. Задание 2
5Три задания для самопроверки
Задание 2
Какие из следующих описаний массивов являются
корректными?
Да
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}};
Да
6. Задание 3
Три задания для самопроверкиЗадание 3
В каком порядке в памяти располагаются элементы
описанного следующим образом массива?
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]
6
7. Указатели
Адреса переменныхЧто такое указатель?
Значение NULL
Операции над указателями
Нетипизированные указатели
Указатели и const
8. Что такое адрес переменной?
Организация курсаЧто такое адрес переменной?
Память:
Адрес:
0x2c4b1 0x2c4b2 0x2c4b3 0x2c4b4 0x2c4b5 0x2c4b6 0x2c4b7
Оперативная память организована как последовательность ячеек
(байт)
Каждая ячейка имеет собственный адрес
(порядковый номер)
Адрес – целое число, чаще записываемое в шестнадцатеричной
системе счисления
8
9. Что такое адрес переменной?
9Организация курса
Что такое адрес переменной?
x
y
a
Память:
Адрес:
0x2c4b1 0x2c4b2 0x2c4b3 0x2c4b4 0x2c4b5 0x2c4b6 0x2c4b7
Каждая переменная размещается в последовательных ячейках
(количество ячеек зависит от типа переменной)
Адрес переменной – адрес первой из этих ячеек
10. Как получить адрес переменной?
10Организация курса
Как получить адрес переменной?
x
Память:
Адрес:
10
y
127
a
20031
0x2c4b1 0x2c4b2 0x2c4b3 0x2c4b4 0x2c4b5 0x2c4b6 0x2c4b7
Адрес переменной можно получить с помощью операции &
Например, &x даст адрес x:
...
printf(“x=%d, &x=%p”, x, &x);
...
x=10, &x=2c4b1
11. Что такое указатель?
11Организация курса
Что такое указатель?
x
Память:
Адрес:
10
0x2c4b1 0x2c4b2
p
…
…
Указатель – переменная,
хранящая адрес
0x2c4b1
0x2c4b8 0x2c4b9 0x2c4ba 0x2c4bb
Операция разадресации * –
обратная к операции &
int x;
/*целая переменная*/
int *px; /*указатель*/
int x=10, y;
int *px;
px = &x; /*присвоить адрес*/
px = &x; /*взять адрес*/
y = *px; /*взять значение по
адресу px, y=10*/
*px = 20; /* <=> x=20 */
12. Значение NULL
Организация курсаЗначение NULL
Помимо адресов, указатель может принимать
специальное значение NULL, обозначающее
недействительный адрес
int *px; /*указатель*/
px = NULL; /*присвоить NULL*/
NULL – макроконстанта
NULL чаще всего (но не всегда!) равен 0
Разадресовывать указатель со значением NULL
небезопасно!
12
13. Операции над указателями
Организация курсаОперации над указателями
Указатель может быть инициализирован
int y, *px=NULL, *py=&y, *pz=py; /* инициализация */
Указателю можно присваивать значение
int x=10, y=20, *px, *py;
px=&x;
py=px;
Указатель можно сравнивать: < > <= >= == !=
(т.е. вычислять отношения адресов)
int x=10, y=20, *px=&x, *py=&y;
if( px == py ) ...
13
14. Операции над указателями
14Организация курса
Операции над указателями
Указатель может складываться с целым числом N. Результат
сложения – адрес, смещенный на N компонент соответствующего
типа относительно исходного
short x=10, *px=&x; /* инициализация */
px
0x2c4b3
x
0
…
10
345
… 0x2c4b1 0x2c4b2 0x2c4b3 0x2c4b4 0x2c4b5 0x2c4b6 …
15. Операции над указателями
15Организация курса
Операции над указателями
Указатель может складываться с целым числом N. Результат
сложения – адрес, смещенный на N компонент соответствующего
типа относительно исходного
short x=10, *px=&x; /* инициализация */
px=px+1;
px
0x2c4b5
x
0
…
10
345
… 0x2c4b1 0x2c4b2 0x2c4b3 0x2c4b4 0x2c4b5 0x2c4b6 …
16. Операции над указателями
16Организация курса
Операции над указателями
Указатель может складываться с целым числом N. Результат
сложения – адрес, смещенный на N компонент соответствующего
типа относительно исходного
short x=10, *px=&x; /* инициализация */
px=px+1;
px=px-2;
px
0x2c4b1
x
0
…
10
345
… 0x2c4b1 0x2c4b2 0x2c4b3 0x2c4b4 0x2c4b5 0x2c4b6 …
17. Операции над указателями
17Организация курса
Операции над указателями
Указатель может складываться с целым числом N. Результат
сложения – адрес, смещенный на N компонент соответствующего
типа относительно исходного
short x=10, *px=&x; /* инициализация */
px=px+1;
px=px-2;
px++;
px
0x2c4b3
x
0
…
10
345
… 0x2c4b1 0x2c4b2 0x2c4b3 0x2c4b4 0x2c4b5 0x2c4b6 …
18. Операции над указателями
18Организация курса
Операции над указателями
Указатель может складываться с целым числом N. Результат
сложения – адрес, смещенный на N компонент соответствующего
типа относительно исходного
short x=10, *px=&x; /* инициализация */
px=px+1;
px=px-2;
px++; *(px+1)+=1;
px
0x2c4b3
x
0
…
10
346
… 0x2c4b1 0x2c4b2 0x2c4b3 0x2c4b4 0x2c4b5 0x2c4b6 …
19. Операции над указателями
19Организация курса
Операции над указателями
Можно вычислять разность однотипных указателей, которая
равна относительному смещению с учетом типа указателя
short *px=0x2c4b1, *py=0x2c4b5, d;
d = py-px; /* 2 */
px
py
…
0x2c4b1
0x2c4b5
d
0
…
10
346
… 0x2c4b1 0x2c4b2 0x2c4b3 0x2c4b4 0x2c4b5 0x2c4b6 …
20. Нетипизированный указатель
Организация курсаНетипизированный указатель
Типизированные указатели (int *, char *, double *, …)
неявно задают длину фрагмента памяти (4,1,8, …),
начинающегося с адреса, хранимого указателем
Длина важна при разадресации и адресной арифметике
Однако иногда приходится использовать указатели, не
подразумевая длины адресуемого фрагмента памяти – void *
Разадресация указателя void * невозможна!
Указатель void * совместим по типу со всеми типизированными
указателями
int i=10, *pi=&i;
double d=3.14, *pd=&d;
void *p;
p=pi; /* Ok */
p=pd; /* Ok */
*p=*p+1; /* Ошибка! */
20
21. Указатели и const
Организация курсаУказатели и const
Два способа описания константного указателя
Неизменяемый указатель
Синтаксис: TYPE * const ptrName = &aTYPEVar;
Переменная-указатель – константа (не может изменяться)
Данные, адресуемые указателем – изменяемые
int a=42, b=42;
int* const ptr=&a;
*ptr=1; /* Ok */
ptr=&b /* Ошибка! */
21
22. Указатели и const
Организация курсаУказатели и const
Два способа описания константного указателя
Указатель на неизменяемые данные
Синтаксис: const TYPE * ptrName = &aTYPEVar;
Переменная-указатель – может изменяться
Данные, адресуемые указателем – неизменяемые
int a=42, b=42;
const int *ptr=&a;
*ptr=1; /* Ошибка! */
ptr=&b /* Оk */
22
23. Указатели и массивы
Указатели и массивыМассивы как параметры функций
Указатели на многомерные массивы
24. Указатели и массивы
24Указатели и массивы
Указатели и массивы
Указатели и массивы очень тесно связаны в языке Си
Имя массива – константный указатель на 0-й элемент массива
short a[100];
short *ps;
<=>
ps = &a[0];
short a[100];
short *ps;
ps = a;
a[i] == *(a+i)
ps
a+1
a
*(a+1)
*a
*(a+2)
=
=
=
33
a+2
a[0]
a[1]
a[2]
…
36
15
… 0x2c4b1 0x2c4b2 0x2c4b3 0x2c4b4 0x2c4b5 0x2c4b6 …
25. Указатели и массивы
25Указатели и массивы
Указатели и массивы
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);
26. Указатели и массивы
26Указатели и массивы
Указатели и массивы
Синонимичные выражения
Передача массива в функцию как параметра
int a[10];
f(a);
/* или */
f(&a[0]);
void f(int *array){
...
}
/*или*/
void f(int array[]){
...
}
27. Указатели на многомерные массивы
Указатели и массивыУказатели на многомерные массивы
Для вычисления адреса элемента двумерного массива
компилятору нужно «знать» количество столбцов в матрице (т.е.
мало знать начальный адрес масива)
Пусть нужно передать в функцию массив int array[3][15],
чтобы ее вызов выглядел так: f(array)
Возможны следующие идентичные варианты описания
функции f:
f(int x[3][15]) { … }
f(int x[][15]) { … }
f(int (*x)[15]) { … }
Важно: в последнем случае нельзя опустить скобки!
f(int *x[15]) { … } – передается массив из 15 указателей
на int, а не указатель на массив из 15 int-ов
27
28. Динамические массивы
Динамические массивыВыделение памяти, malloc()
Освобождение памяти, free()
29. Динамические массивы
29Динамические массивы
Динамические массивы
Часто размер массива заранее не известен, а известен лишь в
момент исполнения
Требуется динамически распределять массив в памяти
Стандартная функция malloc() позволяет запросить память у
ОС
Для использования malloc() нужно подключать stdlib.h
Полный прототип функции:
void *malloc(size_t size);
Указатель на первый байт массива или NULL,
если выделить память не удалось
Требуемое
количество байт
malloc() возвращает нетипизированный указатель на
начальный байт выделенного массива. Для дальнейшего
использования обычно указатель преобразуют в
типизированный
30. Динамические массивы
Динамические массивыШаблон программы, использующей динамический массив
#include <stdio.h>
#include <stdlib.h>
void main(){
int *a;
/* Выделение 4 Мб памяти = 1Мб int-ов */
a = (int *)malloc(1024*1024*sizeof(int));
if(a == NULL) {
printf(“Ошибка выделения памяти.\n”);
return;
}
... /* Работа с элементами a[i] */
/* Освобождение памяти */
free(a);
}
30
31. Динамические массивы
31Динамические массивы
Динамические массивы
Выделенную память необходимо освобождать
Стандартная функция free() позволяет освободить память ,
выделенную malloc()
Блоки памяти освобождаются целиком, т.е. невозможно
частичное освобождение (см. также функцию realloc())
Полный прототип функции:
void free(void *ptr);
Адрес начала
освобождаемого
фрагмента памяти
32. Указатели на функции
Указатели на функцииПример
33. Указатели на функции
33Указатели на функции
Указатели на функции
Укaзатель на функцию содержит адрес тела функции
Как описывается указатель на функцию?
Тип возвращаемого
значения функции
Указатель на
функцию
float myfun(int a, float b)
{
return a+b;
}
...
float (*fptr)(int,float);
fptr = myfun;
...
x=fptr(42,3.14f);
...
Тип
параметра
функции
Тип
параметра
функции
Указатель на функцию,
воспринимающую параметры
типов int и float и
возвращающую float
Вызов функции по указателю
34. Указатели на функции: пример
34Указатели на функции
Указатели на функции: пример
int
int
int
int
add(int
sub(int
mul(int
div(int
x,
x,
x,
x,
int
int
int
int
y)
y)
y)
y)
{
{
{
{
return
return
return
return
x+y;
x-y;
x*y;
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;
}
Массив из указателей
на функции вида
int f(int,int)
return eval[op](x, y);
}
void main() {
printf(“%d\n”, evaluate(3, 42, 3));
}
Вызов подходящей
функции
35. Указатели и параметры функций
Указатели в параметрах функций36. Как передаются параметры через указатель?
36Указатели и параметры фугкций
Как передаются параметры
через указатель?
В функцию передается не значение, а адрес переменной
Для доступа
к значению
переменной
используется
операция
разадресаци
и
#include <stdio.h>
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=%d\n”, a, b);
}
При описании
параметров функции
используются
указатели
При вызове
функции как
параметр
передается адрес
переменной
37. Как изменить переменную в вызывающей функции?
37Указатели и параметры фугкций
Как изменить переменную в
вызывающей функции?
a
b
5
x
y
t
10
#include <stdio.h>
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=%d\n”, a, b);
}
x = &a;
y = &b;
t = *x;
*X
=
*y
=
/*в х – адрес a*/
/*в y – адрес a*/
/*в t поместить значение,
хранящееся по адресу x*/
*y; /*по адресу x записать значение,
хранящееся по адресу y*/
t; /*по адресу y записать значение,
хранящееся в t*/
38. Сложные описания с указателями
Сложные объявленияПравила чтения сложных объявлений
Класс памяти typedef
39. Сложные описания с указателями
Сложные описания с указателямиchar **argv
argv: указатель на указатель на char
int (*x)[13]
x: указатель на массив из 13 int-ов
int *x[13]
x: массив из 13 указателей на int
void *comp()
comp: функция, возвращающая указатель на void
void (*comp)()
comp: указатель на функцию, возвращающую void
char (*(*x())())[5]
x: функция, возвращающая указатель на массив из 5 указателей
на функцию, возвращающую char
char (*(*x[3])())[5]
x: массив из 3 указателей на функцию, возвращающую
указатель на массив из 5 char-ов
39
40. Сложные описания с указателями
Сложные описания с указателямиdouble **d[8] /* хмм... */
char *(*(**foo [][8])())[] /* упс! что такое foo? */
Чтобы понять подобные сложные объявления используйте
следующие три правила:
Начинайте с имени переменной (d или foo в примерах выше)
Заканчивайте на имени типа (double или char выше)
Идите вправо пока можно, затем влево (влево необходимо идти
при обнаружении закрывающейся скобки)
Например
40
41. Сложные описания с указателями
Сложные описания с указателямиdouble **d[8] /* хмм... */
char *(*(**foo [][8])())[] /* упс! что такое foo? */
Еще пример
41
42. Сложные описания с указателями
42Сложные описания с указателями
Сложные описания с указателями
double **d[8] /* хмм... */
char *(*(**foo [][8])())[] /* упс! что такое foo? */
Как можно упростить понимание сложных объявлений?
Ответ: использовать оператор typedef
typedef
typedef
typedef
typedef
float real;
unsigned char byte;
int *INTPTR;
void (*FUNCPTR)();
real r=0.0;
byte b=0;
INTPTR p;
FUNCPTR pf;
FUNCPTR paf[10];
/*
/*
/*
/*
/*
то же,
то же,
то же,
то же,
массив
/*
/*
/*
/*
/*
real – синоним float
byte – синоним unsigned char
INTPTR – синоним int*
FUNCPTR – указатель на функцию
с прототипом void f()
*/
*/
*/
*/
*/
что и float r=0.0
что и unsigned char b=0
что и int *p
что и void (*pf)()
из указателей на функции void (*pf)()
*/
*/
*/
*/
*/
43. Вопросы?
43Вопросы и ответы
Вопросы?
Указатели
Указатели и массивы
Динамические массивы
Указатели на функции
Указатели и
параметры функций
Сложные описания
с указателями
Н.Копейкин Металлурги и компьютер