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 a[] = {1, 2, 3, 4, 5};
printf("a[0] = %d", *a);    // a[0] = 1

Ми можемо пробігтися по всіх елементом масиву, додаючи до адресою певне число:

#include <stdio.h>
 
int main(void)
{
    int a[5] = {1, 2, 3, 4, 5};
     
    for(int i=0;i<5;i++)
    {
        printf("a[%d]: address=%p \t value=%d \n", i, a+i, *(a+i));
    }
    return 0;
}

Тобто, наприклад, адреса другого елементу представлятиме вираз a+1 , а його значення - *(a+1) .

Зі складанням і відніманням тут діють ті ж правила, що і в операціях з покажчиками. Додавання одиниці означає додаток до адреси значення, яке дорівнює розміру типу масиву. Так, в даному випадку масив являє тип int , розмір якого, як правило, становить 4 байта, тому додаток одиниці до адресою означає збільшення адреси на 4. Додаючи до адресою 2, ми збільшуємо значення адреси на 4 * 2 = 8. І так далі.

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

int a[5] = {1, 2, 3, 4, 5};
a++;            // так сделать нельзя
int b = 8;
a = &b;         // так тоже сделать нельзя

Ім'я масиву завжди зберігає адресу самого першого елемента. І нерідко для переміщення по елементах масиву використовуються окремі покажчики:

int a[5] = {1, 2, 3, 4, 5};
int *ptr = a;
int a2 = *(ptr+2);
printf("value: %d \n", a2); // 3

Тут покажчик ptr спочатку вказує на перший елемент масиву. Збільшивши покажчик на 2, ми пропустимо 2 елементи в масиві і перейдемо до елементу a [2].

За допомогою покажчиків легко перебрати масив:

int a[5] = {1, 2, 3, 4, 5};
 
for(int *ptr=a; ptr<=&a[4]; ptr++)
{
    printf("address=%p \t value=%d \n", ptr, *ptr);
}

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

Аналогічним чином можна перебрати і багатовимірний масив:

#include <stdio.h>
#include <stdlib.h>
 
int main(void)
{
    int a[3][4] = { {1, 2, 3, 4} , {5, 6, 7, 8}, {9, 10, 11, 12}};
    int n = sizeof(a)/sizeof(a[0]);         // число строк
    int m = sizeof(a[0])/sizeof(a[0][0]);   // число столбцов
     
    int *final = a[0] + n*m - 1;    // указатель на самый последний элемент
    for(int *ptr=a[0], i=1; ptr<=final; ptr++, i++)
    {
        printf("%d \t", *ptr);
        // если остаток от целочисленного деления равен 0,
        // переходим на новую строку
        if(i%m==0)
        {
            printf("\n");
        }
    }   
    return 0;
}

Так як в даному випадку ми маємо справу з двовимірним масивом, то адресою першого елемента буде вираз a[0] . Відповідно покажчик вказує на цей елемент. З кожної итерацией покажчик збільшується на одиницю, поки його значення не стане рівним адресою останнього елемента, який зберігається в покажчику final.

Ми також могли б обійтися і без покажчика на останній елемент, перевіряючи значення лічильника:

for(int *ptr=a[0], i=0; i<m*n;)
{
    printf("%d \t", *ptr++);
    if(++i%m==0)
    {
        printf("\n");
    }
}

Але в будь-якому випадку програма вивела б наступний результат:

1 2 3 4
5 6 7 8
9 10 11 12

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