malloc() Функція в бібліотеці C із ПРИКЛАДОМ

⚡ Розумний підсумок

malloc() у C резервує блок пам'яті в купі під час виконання та повертає вказівник void на його перший байт, дозволяючи програмам запитувати пам'ять, розмір якої невідомий, доки код фактично не виконається.

  • 🧠 Розподіл часу виконання: malloc() резервує пам'ять під час виконання, коли необхідний розмір невідомий під час компіляції.
  • 📦 Синтаксис: Вказівник типу cast_type отримує malloc(byte_size), розмір якого зазвичай залежить від sizeof для переносимості.
  • ⚠️ Перевірка NULL: Невдалий запит повертає вказівник NULL, тому перевірте результат перед розіменуванням.
  • Арифметика вказівників: Блок є суміжним, тому використовуйте +, а не ++, щоб дістатися до елементів масиву.
  • 🧹 Звільніть пам'ять: Звільняйте кожен блок за допомогою free(), щоб запобігти витокам пам'яті та зависаючим вказівникам.
  • 🤖 Допомога AI: Асистенти ШІ та GitHub Copilot створюють чернетки викликів malloc() та позначають відсутні оператори free().

Функція malloc() у C

Що таке malloc у C?

Функція malloc() означає розподіл пам'яті. Це функція, яка використовується для динамічного виділення блоку пам'яті. Він резервує простір пам’яті заданого розміру та повертає нульовий покажчик, що вказує на розташування пам’яті. Зазвичай повертається вказівник типу void. Це означає, що ми можемо призначити функцію malloc будь-якому покажчику.

Що таке malloc у C

синтаксис

ptr = (cast_type *) malloc (byte_size);

Тут,

  • ptr є вказівником на cast_type.
  • Функція malloc повертає вказівник на виділену пам’ять byte_size.
Example: ptr = (int *) malloc (50)

Коли цей оператор успішно виконується, резервується простір пам’яті розміром 50 байт. Адреса першого байта зарезервованого простору присвоюється покажчику ptr типу int.

Розглянемо інший приклад реалізації malloc:

#include <stdlib.h>
int main(){
int *ptr;
ptr = malloc(15 * sizeof(*ptr)); /* a block of 15 integers */
    if (ptr != NULL) {
      *(ptr + 5) = 480; /* assign 480 to sixth integer */
      printf("Value of the 6th integer is %d",*(ptr + 5));
    }
}

вихід:

Value of the 6th integer is 480

Зверніть увагу, що замість sizeof(int) було використано sizeof(*ptr), щоб зробити код більш стійким, коли оголошення *ptr пізніше буде перетворено на інший тип даних.

Розподіл може бути невдалим, якщо пам’яті недостатньо. У цьому випадку він повертає покажчик NULL. Отже, ви повинні включити код для перевірки покажчика NULL.

Майте на увазі, що виділена пам'ять є безперервною і її можна розглядати як масив. Ми можемо використовувати покажчик арифметичні операції для доступу до елементів масиву, а не використання дужок []. Ми рекомендуємо використовувати + для посилання на елементи масиву, оскільки використання інкременту ++ або += змінює адресу, що зберігається вказівником.

Функцію Malloc також можна використовувати з символьним типом даних, а також із складними типами даних, наприклад структурами.

Навіщо використовувати malloc() у C?

Статичні масиви та звичайні змінні фіксують свій розмір під час компіляції програми, що призводить до марнування місця, коли вимога виявляється меншою, і до повної невдачі, коли вона виявляється більшою. malloc() вирішує цю проблему, запитуючи пам'ять під час виконання, щоб програма могла визначити розмір буфера точно відповідно до обсягу даних, які вона отримує. Ця гнучкість під час виконання є основою... динамічний розподіл пам'яті в С.

Динамічне розподілення за допомогою malloc() є правильним вибором у кількох поширених ситуаціях:

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

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

Як звільнити пам'ять, виділену malloc()

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

Функція free() приймає один аргумент, вказівник, який повернула функція malloc(), і звільняє весь блок одразу:

int *ptr;
ptr = malloc(10 * sizeof(int));
if (ptr != NULL) {
    /* use the allocated memory here */
    free(ptr);   /* release the block */
    ptr = NULL;  /* avoid a dangling pointer */
}

Дотримуйтесь цих правил для безпечного керування динамічною пам'яттю:

  • Викликайте free() рівно один раз для кожного успішного malloc(); звільнення одного й того ж блоку двічі призводить до невизначеної поведінки.
  • Встановіть вказівник на NULL після звільнення, щоб його не можна було повторно використовувати як висячий вказівник.
  • Ніколи не звільняє() вказівник, який malloc() не повернув, включаючи той, що зміщений за допомогою арифметики вказівників.
  • Зіставте кожне виділення з відповідним випуском, перш ніж вказівник вийде за межі області видимості.

Кіping Розподіл та звільнення пам'яті в балансі є основною дисципліною ручного управління пам'яттю в C, і вона запобігає як витокам, так і збоям, спричиненим повторним використанням звільненої пам'яті.

malloc() проти calloc(): ключові відмінності

malloc() та calloc() Обидва резервують пам'ять купи, але вони відрізняються своїми аргументами та тим, як вони обробляють новий блок. malloc() приймає один аргумент, загальну кількість байтів, і залишає вміст неініціалізованим, тому блок зберігає непередбачувані значення сміття, доки програма не запише в нього. calloc() приймає два аргументи, кількість елементів та розмір кожного, і очищує кожен байт до нуля перед поверненням вказівника.

Практичні відмінності зводяться до трьох моментів:

  • Ініціалізація: calloc() обнуляє пам'ять, тоді як malloc() цього не робить, що робить malloc() трохи швидшим, коли значення все одно будуть перезаписані.
  • Аргументи: ви пишете malloc(n * size), але calloc(n, size) для резервування того самого масиву.
  • Випадок використання: оберіть calloc(), коли важливий чистий, обнулений блок, та malloc(), коли перевага надається швидкості, а ініціалізація виконується вручну.

Обидві функції оголошені в stdlib.h, обидві повертають покажчик void або NULL у разі невдачі, і обидві передають свою пам'ять назад за допомогою однієї й тієї ж функції free().

Поширені запитання

У C перетворення типів необов'язкове та часто не рекомендується, оскільки void* автоматично перетворюється на будь-який вказівник на об'єкт, а явне перетворення типів може маскувати відсутнє включення stdlib.h. C++, однак, актори обов'язкові.

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

realloc() змінює розмір блоку, попередньо зарезервованого malloc(), keeping існуючі дані до меншого розміру. Якщо це не вдається, повертається NULL і залишає початковий блок недоторканим, тому спочатку присвоїти його результат тимчасовому вказівнику.

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

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

malloc() — це бібліотечна функція, яка повертає void* та потребує sizeof для обчислення байтів. C++ new — це оператор, який повертає типізований вказівник та викликає конструктори. Поєднуйте malloc() з free(), а new — з delete.

Так. Помічники ШІ-кодування створюють виклики malloc(), вставляють перевірки NULL та позначають відсутні виклики free() або витоки, а також можуть пояснити арифметику вказівників. Завжди компілюйте та тестуйте згенерований код, перш ніж довіряти йому.

Копілот GitHub пропонує рядки malloc(), sizeof() та відповідні рядки free() з коментаря, що описує ваш намір. RevПерегляньте кожну пропозицію щодо пропущених перевірок NULL та витоків перед компіляцією.

Підсумуйте цей пост за допомогою: