
- •1 Основні елементи мови с
- •1.1 Алфавіт мови програмування
- •1.2 Лексеми
- •1.3 Ключові слова
- •1.4 Ідентифікатори
- •1.5 Класифікація типів даних
- •1.6 Літерали
- •1.7 Оператори
- •1.8 Коментарі
- •1.9 Директиви препроцесора
- •1.10 Організація програми
- •2 Операції та вирази
- •2.1 Загальні відомості
- •2.2 Арифметичні операції
- •2.3 Операції приведення типів
- •2.4 Операції присвоєння
- •2.5 Операції інкремента і декремента
- •2.6 Операції порівняння
- •2.7 Операції зсуву
- •2.8 Порозрядні операції
- •2.9 Логічні операції
- •2.10 Операція sizeof
- •2.11 Операція послідовного обчислення
- •2.12 Операція умови (?:)
- •2.13 Адресні операції
- •3 Прості типи даних
- •3.1 Оголошення змінних
- •3.2 Час існування та область видимості змінних
- •3.3 Цілі типи даних
- •3.4 Дійсні типи даних
- •4 Оператори керування
- •4.1 Оператор розгалуження if
- •4.2 Оператор розгалуження if-else
- •4.3 Оператор множинного розгалуження switch
- •4.4 Оператор циклу for
- •4.5 Оператор циклу while
- •4.6 Оператор циклу do while
- •4.7 Оператор break
- •4.8 Оператор continue
- •5 Функції
- •5.1 Основні поняття
- •5.2 Види виклику функцій
- •5.3 Область видимості
- •5.4 Порожній тип void
- •5.5 Передача аргументів у функцію
- •5.6 Рекурсивні функції
- •5.7 Прототипи функцій
- •6 Покажчики
- •6.1 Визначення та ініціалізація покажчиків
- •6.2 Визначення покажчиків
- •6.3 Масиви
- •6.4 Операції порівняння
- •6.5 Копіювання рядка
- •6.6 Покажчики на функцію
- •6.7 Покажчики на void
- •6.8 Арифметика покажчиків
- •7 Масиви
- •7.1 Загальні поняття
- •7.2 Одновимірні масиви
- •7.3 Багатовимірні масиви
- •8 Рядки в с
- •8.1 Рядки
- •8.2.Створення рядків
- •8.3 Прототипи
- •8.3 Функції перетворення буферів
- •8.4 Функції перевірки літер
- •8.5 Операції з рядками
- •9 Структури, об’єднання, перерахування
- •9.1 Структури
- •9.2 Бітові поля
- •9.3 Ключове слово typedef
- •9.4 Об’єднання
- •9.5 Перераховуваний тип
- •10 Введення та виведення даних
- •10.1 Функція виведення printf
- •10.2Функція введення scanf
- •10.3 Введення та виведення у файл
- •11 Динамічне виділення пам'яті
6.7 Покажчики на void
Покажчики на void – це покажчики спеціального типу. Він являє собою відсутність типу, тобто вказує на зміну що не має типу (невідома довжина і опції розіменовування).
Це дозволяє їм вказувати на будь-які дані: від char до double. Але на заміну покажчики мають великі обмеження: дані на які він вказує не можуть безпосередньо роіменовуватись (за відсутності типу), з цієї причини ми повинні вказувати тип перед тим як розіменувати дані на які вказує цей покажчик.
Приклад 6.18. Покажчик на void.
void increase (void* data, int psize)
{
if (psize == sizeof(char)) {
char* pchar; pchar=(char*)data; ++(*pchar);
}
else if (psize == sizeof(int)){
int* pint; pint=(int*)data; ++(*pint); }
}
int main ()
{
char a = 'x';
int b = 1602;
increase (&a,sizeof(a));
increase (&b,sizeof(b));
printf("a= %c, b= %i \n", a, b);
}
Результати роботи програми:
В функцію передаються по черзі адреса на зміну а (символьний тип) та на b (тип цілого числа). Функція приймає покажчик на void тому не важливо що було передано з осовної програми. Але для роботи з переданими даними, необхідно розіменувати покажчик * data. Не знаючи тип, що передається, виникає проблема. Це вирішується конструкцією if…else, де за допомого функції sizeof () ми можемо встановити розмір зміної за її покажчиком. Покажчик не залежить від типу! А лише від розрядності ОС, так для 32-х бітних він матиме розмір 4 байти, для 64-х бітних – 8 байтів) на комірку розміщення зміної. Таким чином маючи опції вибору (якщо розмір дорівнює 1 байт, то це char, якщо – 4, то це int) ми встановлюємо тип даних.
В С дозволяється створювати покажчики на покажчики, що вказують на дані чи інші покажчики. Для цього потрібно додавати при оголошені покажчик на покажчик ще один оператор «*»:
Приклад 6.19. Створення покажчика на покажчику (рис. 6.12)
int x =0;
int * y = &x;
int ** z = &y;
x = 'a';
y = &x;
z = &y;
Рисунок 6.12 – Покажчик на покажчику
Приклад 6.20. Різні види представлення.
z має тип символ ** і значення 1000
* z має тип символів * і значення 100
** z має тип символ і значення ‘a’
6.8 Арифметика покажчиків
Виконання арифметичних дій з покажчиками дещо відрізняється від дій з цілочисельними даними, даними з плаваючою точкою чи інших типів. Над ними можна виконувати дії додавання чи віднімання. Але вони мають різну поведінку з покажчиками залежно від розміру типу даних, до яких вони застосовуються.
Приклад 6.21. Представлення операцій з покажчиками та результати їх використання.
#include <stdio.h>
#include <stdlib.h>
int main ()
{
int a[] = { 10, 20, 30, 40, 50 }, b;
int *p = a;
int *p2 = &a[3];
b = p2 – p;
printf(" 1) b = %i\n", b);
printf(" 2) *p = %i", *p);
printf(" *p++ = %d \n", *p++);
printf(" 3) *p = %i", *p);
printf(" *(++p) = %d \n", *(++p));
printf(" 4) *p = %i", *p);
printf(" *p+2 = %d \n", *p+2);
printf(" 5) *p = %i", *p);
printf(" *(p+2) = %d \n", *(p+2));
printf(" 6) *p = %i", *p);
printf(" *(p+8) = %d \n", *(p+8));
system("PAUSE");
return EXIT_SUCCESS;
}
Результат роботи програми:
Результат дії:
1. Різниця між покажчиками р і р2 ― це b. Так як р2 покажчик на третій елемент, а р покажчик на перший, то різниця між ними = 3 (тобто 3*4=12 байт);
2. Виводить на екран значення на яке вказує покажчик р, а також демонструє реакцію покажчика на оператори * і ++ (операція * виконується першою, і лише потім збільшується значення покажчика);
3. Значення р було зміщено на одне значення і тепер воно вказує на другий елемент масиву. В другій дії значення р змінюється до розіменовування тому воно дорівнює наступному значенню в масиві, тобто послідовність дій наступна: спочатку йде інкременування (обов’язково перед р має бути ++, інакше результат буде як в попередньому полі!), а потім розіменовування;
4. Тут лише виводиться значення на 2 більше ніж те, на яке вказує покажчик.
5. В цій стрічці значення самого покажчика не змінюється, відбувається лише зміщення по масиву на 2 елемента від того на яке він вказує.
6. Вказано що вихід за границі масиву ніяк не контролюється, тому потрібно бути обережним при використані покажчиків.
Контрольні запитання
Для чого потрібні покажчики?
Що таке адреса змінної?
Опишіть синтаксис визначення покажчика.
Що таке операція «*»?
Як визначається адреса наступної змінної в масиві?
Що таке оператор &?
Що таке посилання?
Для чого потрібно посилання?
Для чого потрібні покажчики на функцію?
Що таке покажчик на void?
Що таке арифметика покажчиків?
Написати програму, яка перетворює масив таким чином, щоб спочатку розташовувались нульові елементи, а потім всі інші.
Написати програму, яка видаляє всі елементи масиву, модуль яких не перевищує 1, елементи, які звільнилися в кінці масиву заповнювати нулями.