Transcript efimenko_Lec_3_Адресація та вказівники в С
Slide 1
Адресація та вказівники в С/С++
Вказівник (або покажчик, інколи – посилання) – це
змінна, яка може містити адресу деякого іншого об’єкта.
Ним може бути в найпростішому випадку інша змінна
або масив, структура, функція, клас (в С++) тощо.
Синтаксис визначення вказівника:
<тип> * <ідентифікатор_вказівника>;
Приклади.
int * p_i; // p_i – вказівник на тип int
char * p_c;// p_c – вказівник на тип char
В цих прикладах вказівники поки що не вказують ні на
які об’єкти – вони не проініціалізовані.
Slide 2
В мові С для ініціалізації вказівника можна
використати один з двох способів:
• ініціалізація вказівника адресою існуючої змінної;
• ініціалізація вказівника адресою динамічно виділеної
пам’яті (з допомогою функції malloc(), calloc()).
Приклади.
int i;
int *p_i = &i; // вказівник p_i вказує на i
// унарна операція & - взяття адреси
*p_i = 10; // змінній i присвоєно
// значення 10
++*p_i;
// змінна i збільшена на 1
cout << *p_i; // виводимо значення i
Зауваження. У виразі (*pi)++; дужки обов'язкові на
відміну від виразу ++*p_i; із-зі порядку виконання
операцій.
Slide 3
Динамічний розподіл пам'яті.
Динамічним розподілом пам'яті керують функції із файлу
( у просторі імен std):
void*
malloc
(size_t size);
– виділяє size байтів пам'яті в області Heap і повертає
вказівник на початок цієї області або вказівник NULL, якщо пам’ять не
виділена.
void*
calloc
(size_t n, size_t size);
– повертає вказівник на початок області пам'яті, достатньої для
збереження n об'єктів розміру size або вказівник NULL, якщо
пам’ять не виділена.
void*
realloc
(void* p, size_t size);
– змінює розмір пам’яті, на яку вказує вказівник p, на size та
повертає вказівник на нову область, або вказівник NULL, якщо
зміна неможлива. Для частини пам'яті розміру, рівному найменшому
із старого та нового значень, зміст не зміниться.
void
free (void* p);
– звільняє область пам'яті, на яку вказує вказівник p.
Slide 4
Приклад.
int *p; // визначили вказівник
// виділили пам’ять – необхідно привести
// вказівник до відповідного типу:
p = (int*) malloc (sizeof (int));
printf ("\nВведіть ціле число: ");
scanf ("%i", p);
// ввели ціле значення
// вивели його на екран
printf ("\nЧисло = %i\n", *p);
free (p);
// звільнили пам’ять
Slide 5
Масиви в С/С++
Синтаксис визначення масиву:
<тип> <ідентифікатор_масиву> [кількість_елементів];
Тут <тип> визначає тип елементів масиву, які індексуються від 0 до
кількість_елементів-1 .
Приклади:
int iArray [10]; //визначили масив із 10 елементів
for (int i = 0; i < 10; i++)
//елементам iArray [0] .. iArray [9] присвоїли значення
iArray [i] = i*i;
Увага: ідентифікатор масиву – вказівник на його нульовий елемент,
таким чином, iArray [i] – це елемент масиву *(iArray + i),
а &iArray [i] – вказівник на елемент з індексом iArray + i.
Масив можна проініціалізувати в момент визначення:
int iArray [5] = {1, 2, 3, 4, 5};
char text [] = {'H','e','l','l','o','\0'};
Slide 6
Адресна арифметика
Для будь-яких вказівників на один тип допустимі перевірки на
рівність та нерівність їх між собою та присвоєння, а також
присвоєння та порівняння з вказівником NULL.
Якщо p1 та p2 – вказівники и на один і той самий масив, то
допустимими операціями з ними додатково є такі:
p1 < p2
перевірка: "p1 вказує на елемент масиву з меншим
індексом, ніж той, на який вказує p2";
p1 <= p2
перевірка: "p1 вказує на елемент масиву з індексом
не більшим, ніж той, на який вказує p2";
p1 > p2
перевірка: "p1 вказує на елемент масиву з більшим
індексом, ніж той, на який вказує p2";
p1 >= p2
перевірка: "p1 вказує на елемент масиву з індексом
не меншим, ніж той, на який вказує p2";
p2 – p1
кількість елементів масиву між елементами, що
адресуються p2 та p1;
p1 + k
вказівник на k-ий елемент масиву, рахуючи вперед
від елементу, що адресується p1.
p1 – k
вказівник на k-ий елемент масиву, рахуючи назад
від елементу, що адресується p1.
Slide 7
Символьні масиви
Текстовий масив може бути визначеним і в такий спосіб
(підходить лише для текстових масивів):
char* ptext = "Приклад визначення тексту ";
або
char text [20] = "Інший приклад";
(Тут важливо, щоб кількість елементів в масиві не
перевищувала кількість символів текстової константи).
Перший приклад дозволяє повторне визначення
вказівника, наприклад:
ptext = text; // так можна
text = ptext; // а так – ні!
Адресація та вказівники в С/С++
Вказівник (або покажчик, інколи – посилання) – це
змінна, яка може містити адресу деякого іншого об’єкта.
Ним може бути в найпростішому випадку інша змінна
або масив, структура, функція, клас (в С++) тощо.
Синтаксис визначення вказівника:
<тип> * <ідентифікатор_вказівника>;
Приклади.
int * p_i; // p_i – вказівник на тип int
char * p_c;// p_c – вказівник на тип char
В цих прикладах вказівники поки що не вказують ні на
які об’єкти – вони не проініціалізовані.
Slide 2
В мові С для ініціалізації вказівника можна
використати один з двох способів:
• ініціалізація вказівника адресою існуючої змінної;
• ініціалізація вказівника адресою динамічно виділеної
пам’яті (з допомогою функції malloc(), calloc()).
Приклади.
int i;
int *p_i = &i; // вказівник p_i вказує на i
// унарна операція & - взяття адреси
*p_i = 10; // змінній i присвоєно
// значення 10
++*p_i;
// змінна i збільшена на 1
cout << *p_i; // виводимо значення i
Зауваження. У виразі (*pi)++; дужки обов'язкові на
відміну від виразу ++*p_i; із-зі порядку виконання
операцій.
Slide 3
Динамічний розподіл пам'яті.
Динамічним розподілом пам'яті керують функції із файлу
(
void*
malloc
(size_t size);
– виділяє size байтів пам'яті в області Heap і повертає
вказівник на початок цієї області або вказівник NULL, якщо пам’ять не
виділена.
void*
calloc
(size_t n, size_t size);
– повертає вказівник на початок області пам'яті, достатньої для
збереження n об'єктів розміру size або вказівник NULL, якщо
пам’ять не виділена.
void*
realloc
(void* p, size_t size);
– змінює розмір пам’яті, на яку вказує вказівник p, на size та
повертає вказівник на нову область, або вказівник NULL, якщо
зміна неможлива. Для частини пам'яті розміру, рівному найменшому
із старого та нового значень, зміст не зміниться.
void
free (void* p);
– звільняє область пам'яті, на яку вказує вказівник p.
Slide 4
Приклад.
int *p; // визначили вказівник
// виділили пам’ять – необхідно привести
// вказівник до відповідного типу:
p = (int*) malloc (sizeof (int));
printf ("\nВведіть ціле число: ");
scanf ("%i", p);
// ввели ціле значення
// вивели його на екран
printf ("\nЧисло = %i\n", *p);
free (p);
// звільнили пам’ять
Slide 5
Масиви в С/С++
Синтаксис визначення масиву:
<тип> <ідентифікатор_масиву> [кількість_елементів];
Тут <тип> визначає тип елементів масиву, які індексуються від 0 до
кількість_елементів-1 .
Приклади:
int iArray [10]; //визначили масив із 10 елементів
for (int i = 0; i < 10; i++)
//елементам iArray [0] .. iArray [9] присвоїли значення
iArray [i] = i*i;
Увага: ідентифікатор масиву – вказівник на його нульовий елемент,
таким чином, iArray [i] – це елемент масиву *(iArray + i),
а &iArray [i] – вказівник на елемент з індексом iArray + i.
Масив можна проініціалізувати в момент визначення:
int iArray [5] = {1, 2, 3, 4, 5};
char text [] = {'H','e','l','l','o','\0'};
Slide 6
Адресна арифметика
Для будь-яких вказівників на один тип допустимі перевірки на
рівність та нерівність їх між собою та присвоєння, а також
присвоєння та порівняння з вказівником NULL.
Якщо p1 та p2 – вказівники и на один і той самий масив, то
допустимими операціями з ними додатково є такі:
p1 < p2
перевірка: "p1 вказує на елемент масиву з меншим
індексом, ніж той, на який вказує p2";
p1 <= p2
перевірка: "p1 вказує на елемент масиву з індексом
не більшим, ніж той, на який вказує p2";
p1 > p2
перевірка: "p1 вказує на елемент масиву з більшим
індексом, ніж той, на який вказує p2";
p1 >= p2
перевірка: "p1 вказує на елемент масиву з індексом
не меншим, ніж той, на який вказує p2";
p2 – p1
кількість елементів масиву між елементами, що
адресуються p2 та p1;
p1 + k
вказівник на k-ий елемент масиву, рахуючи вперед
від елементу, що адресується p1.
p1 – k
вказівник на k-ий елемент масиву, рахуючи назад
від елементу, що адресується p1.
Slide 7
Символьні масиви
Текстовий масив може бути визначеним і в такий спосіб
(підходить лише для текстових масивів):
char* ptext = "Приклад визначення тексту ";
або
char text [20] = "Інший приклад";
(Тут важливо, щоб кількість елементів в масиві не
перевищувала кількість символів текстової константи).
Перший приклад дозволяє повторне визначення
вказівника, наприклад:
ptext = text; // так можна
text = ptext; // а так – ні!