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 покажчики. Управління динамічної пам'яттю


У минулих темах розглядалося виділення і звільнення динамічної пам'яті під масиви. При виділенні пам'яті за допомогою функцій malloc () / calloc () / realloc () ми отримуємо покажчик на виділений блок пам'яті. І ми можемо використовувати виділений блок пам'яті всюди, де доступний покажчик.

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

  • Покажчик визначено в блоці коду. В цьому випадку покажчик буде доступний тільки в межах даного блоку коду. Відповідно пам'ять необхідно звільняти при виході з цього блоку.

  • Покажчик визначено як статичний об'єкт. В цьому випадку динамічна пам'ять виділяється один раз і доступна через покажчик при кожному повторному вході блок. У цьому випадку пам'ять потрібно звільняти тільки після завершення її використання.

  • Покажчик є глобальним об'єктом по відношенню до блоку. В цьому випадку динамічна пам'ять доступна у всіх блоках, де доступний покажчик, а пам'ять потрібно звільняти тільки після завершення її використання.

Перший варіант, якщо покажчик визначено в функції:

#include <stdio.h>
#include <stdlib.h>
 
void createPointer()
{
    int *p = NULL;
    int n = 1;
    if(p==NULL)
    {
        p = malloc(n * sizeof(int));
        *p = 1;
    }
    printf("%d \t", (*p));
    (*p)++;
    free(p);
}
 
int main(void)
{
    createPointer();
    createPointer();
    createPointer();
    return 0;
}

З метою демонстрації покажчик p вказує на блок виділеної динамічної пам'яті розміром в 4 байта, тобто для одного елемента типу int . Мінлива покажчика визначена в автоматичній пам'яті як локальна змінна функції createPointer, тому виділена динамічна пам'ять доступна тільки в рамках цієї функції createPointer. Відповідно в кінці виконання цієї функції потрібно звільнити пам'ять викликом функції free() .

При кожному новому виконанні функції createPointer в main буде заново виділятися динамічна пам'ять.

Консольний висновок:

#include <stdio.h>
#include <stdlib.h>
 
int * createPointer()
{
    static int *p = NULL;
    int n = 1;
    if(p==NULL)
    {
        p = malloc(n * sizeof(int));
        *p = 1;
    }
    printf("%d \t", (*p));
    (*p)++;
    return p;
}
 
int main(void)
{
    int *ptr;
    ptr=createPointer();
    ptr=createPointer();
    ptr=createPointer();
    free(ptr);
    return 0;
}

Оскільки виділена динамічна пам'ять після виходу з функції createPointer зберігається, то немає сенсу її повторно виділяти. І для цього покажчик p спочатку має значення NULL, а за допомогою перевірки на це значення ми можемо вирішити чи треба виділяти пам'ять.

Так як статичний покажчик перестає бути потрібен в кінці роботи програми, то при виконанні функції createPointer ми отримуємо покажчик в змінну ptr. І в кінці функції main звільняємо виділену пам'ять за допомогою функції free.

Консольний висновок:

#include <stdio.h>
#include <stdlib.h>
 
int *p = NULL; // глобальный объект
 
void createPointer()
{
    printf("%d \t", (*p));
    (*p)++;
}
 
int main(void)
{
    int n = 1;
    p = malloc(n * sizeof(int));
    *p = 1;
         
    createPointer();
    createPointer();
    createPointer();
     
    free(p);
    return 0;
}

Покажчик визначено як глобальний об'єкт, відповідно звільняти динамічну пам'ять необхідно, коли вона нам буде більше не потрібна. Тому функція free () викликається ближче до кінця функції main .


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