C установка IDE C структура програми C змінні C типи даних С функція printf C константи C арифметичні операції C операції порівняння і логічні операції C порозрядні операції C операції присвоювання C перетворення типів C умовні конструкції C цикли С масиви і рядки С функція scanf C препроцесор. Директива #include C #define директива C макроси C умовна компіляція C функції. Визначення та опис функцій C функції. Передача параметрів в функцію C функції. Повернення результату з функції C функції. Рекурсивні функції C область видимості змінних C зовнішні об'єкти C вказівники C вказівник. Операції з вказівниками C покажчики. Арифметика покажчиків C покажчики. Константи і покажчики C покажчики. Покажчики та масиви C покажчики. Масиви покажчиків, рядки і багаторівнева адресація C покажчики. Покажчики в параметрах функції C покажчики. Динамічна пам'ять C покажчики. Покажчик як результат функції C покажчики. Управління динамічної пам'яттю C покажчики. Покажчики на функцію C покажчики. Покажчики на функції як параметри і результати функцій C покажчики. Функції зі змінною кількістю параметрів C struct. Визначення структур C struct. Структури як елементи структур C struct. Покажчики на структури C struct. Масиви структур C struct. Структури і функції C struct. union об'єднання C struct. Бітові поля С file. Введення-виведення і робота з файлами C file. Читання і запис бінарних файлів C file. Читання і запис структур в файл C file. Читання і запис текстових файлів C file. Форматування вводу-виводу C file. Позиціонування в потоці C file. Консольне введення-виведення

C покажчики. Арифметика покажчиків


До вказівників можуть застосовувати деякі арифметичні операції (додавання, віднімання, інкремент, декремент). Однак самі операції проводяться трохи інакше, ніж з числами. І багато що тут залежить від типу покажчика. До покажчика можна додавати ціле число, і також можна віднімати з покажчика ціле число. Крім того, можна вичитати з одного покажчика інший покажчик.

Розглянемо спочатку операції інкремента і декремента і для цього візьмемо покажчик на об'єкт типу int :

#include <stdio.h>
 
int main(void)
{
    int n = 10;
     
    int *ptr = &n;
    printf("address=%p \t value=%d \n", ptr, *ptr);
     
    ptr++;
    printf("address=%p \t value=%d \n", ptr, *ptr);
     
    ptr--;
    printf("address=%p \t value=%d \n", ptr, *ptr);
     
    return 0;
}

Операція інкремента ++ збільшує значення на одиницю. У випадку з покажчиком збільшення на одиницю означатиме збільшення адреси, який зберігається в покажчику, на розмір типу покажчика. Тобто в даному випадку покажчик на тип int, а розмір об'єктів int в більшості архітектур рівний 4 байтам. Тому збільшення покажчика типу int на одиницю означає збільшення значення покажчика на 4.

І в моєму випадку консольний висновок виглядає наступним чином:

printf("address=%d \t value=%d \n", ptr, *ptr);

У випадку з покажчиком типу int збільшення / зменшення на одиницю означає зміну адреси на 4. Аналогічно, для покажчика типу short ці операції змінювали б адреса на 2, а для покажчика типу char на 1.

#include <stdio.h>
 
int main(void)
{
    double d = 10.6;
    double *pd = &d;
    printf("Pointer pd: address=%p \n", pd);
    pd++;
    printf("Pointer pd: address=%p \n", pd);
         
    char c = 'N';
    char *pc = &c;
    printf("Pointer pc: address=%p \n", pc);
    pc++;
    printf("Pointer pc: address=%p \n", pc);
     
    return 0;
}

У моєму випадку консольний висновок буде виглядати наступним чином:

#include <stdio.h>
 
int main(void)
{
    double d = 10.6;
    double *pd = &d;
    printf("Pointer pd: address=%p \n", pd);
    pd = pd + 2;
    printf("Pointer pd: address=%p \n", pd);
     
     
    char c = 'N';
    char *pc = &c;
    printf("Pointer pc: address=%p \n", pc);
    pc = pc - 3;
    printf("Pointer pc: address=%p \n", pc);
     
    return 0;
}

Додавання до покажчика типу double числа 2

pd = pd + 2;

означає, що ми хочемо перейти на два об'єкта double вперед, що має на увазі зміну адреси на 2 * 8 = 16 байт.

Віднімання з покажчика типу char числа 3

pc = pc - 3;

означає, що ми хочемо перейти на три об'єкти char тому, що має на увазі зміну адреси на 3 * 1 = 3 байта.

І в моєму випадку я отримаю наступний консольний висновок:

#include <stdio.h>
 
int main(void)
{
    int a = 10;
    int b = 23;
    int *pa = &a;
    int *pb = &b;
    int c = pa - pb;
     
    printf("pa=%p \n", pa);
    printf("pb=%p \n", pb);
    printf("c=%d \n", c);
     
    return 0;
}

Консольний висновок в моєму випадку:

int a = 10;
int *pa = &a;
int b = *pa + 20;   // операция со значением, на который указывает указатель
pa++;               // операция с самим указателем
     
printf("b=%d \n", b);   // 30

Тобто в даному випадку через операцію разименованія *pa отримуємо значення, на яке вказує покажчик pa, тобто число 10, і виконуємо операцію складання. Тобто в даному випадку звичайна операція складання між двома числами, так як вираз *pa являє число.

Але в той же час є особливості, зокрема, з операціями инкремента і декремента. Справа в тому, що операції * , ++ і - мають однаковий пріоритет і при розміщенні поруч виконуються справа наліво.

Наприклад, виконаємо постфіксний інкремент:

int a = 10;
int *pa = &a;
printf("pa: address=%p \t value=%d \n", pa, *pa);
int b = *pa++;      // инкремент адреса указателя
     
printf("b: value=%d \n", b);
printf("pa: address=%p \t value=%d \n", pa, *pa);

У вираженні b = *pa++; спочатку до покажчика присвоюється одиниця (тобто до адресою додається 4, так як покажчик типу int ). Потім так як інкремент постфіксний, за допомогою операції разименованія повертається значення, яке було до инкремента - тобто число 10. І це число 10 присвоюється змінної b. І в моєму випадку результат роботи буде наступний:

b = (*pa)++;

Дужки змінюють порядок операцій. Тут спочатку виконується операція разименованія і отримання значення, потім це значення збільшується на 1. Тепер за адресою в покажчику знаходиться число 11. І потім так як інкремент постфіксний, змінна b отримує значення, яке було до инкремента, тобто знову число 10. Таким чином , на відміну від попереднього випадку всі операції проводяться над значенням за адресою, який зберігає покажчик, але не над самим покажчиком. І, отже, зміниться результат роботи:

b = ++*pa;

В даному випадку спочатку за допомогою операції разименованія отримуємо значення за адресою з покажчика pa, до цього значення додається одиниця. Тобто тепер значення за адресою, який зберігається в покажчику, так само 11. Потім результат операції присвоюється змінної b:

b = *++pa;

Тепер спочатку змінює адресу в покажчику, потім ми отримуємо за цією адресою значення і присвоюємо його змінної b. Отримане значення в цьому випадку може бути невизначеним:

ра: адреса = 0060FEA4 значення = 10
b: значення = 6356648
ра: адреса = 0060FEA8 значення = 6356648

Наш партнер:
beta test mp3 playlist downloader