C Програмиране

malloc на език c

malloc на език c
Можете да дойдете тук по две причини: или искате да разпределите динамично съдържание, или искате да научите повече за това как работи malloc. И в двата случая сте на правилното място! Динамичното разпределение е процес, който се случва много, но обикновено не го използваме сами: по-голямата част от програмните езици управляват паметта вместо вас, тъй като това е трудна работа и ако не успеете да го направите правилно, има последици за сигурността.

Ако обаче правите C, C ++ или код за сглобяване или ако внедрите нов външен модул на любимия си език за програмиране, ще трябва сами да управлявате разпределението на динамичната памет.

Какво е динамично разпределение? Защо ми трябва malloc?

Е, във всички приложения, когато създавате нова променлива - често се нарича деклариране на променлива - имате нужда от памет, за да я съхранявате. Тъй като компютърът ви е в съвременните дни, той може да изпълнява повече от едно приложение наведнъж и така, всяко приложение трябва да казва на вашата операционна система (тук Linux) че се нуждае от това количество памет. Когато пишете този вид код:

#include
#include
#define DISK_SPACE_ARRAY_LENGTH 7
void getFreeDiskSpace (int statsList [], size_t listLength)
връщане;

int main ()
/ * Съдържа свободно място на диска през последните 7 дни. * /
int freeDiskSpace [DISK_SPACE_ARRAY_LENGTH] = 0;
getFreeDiskSpace (freeDiskSpace, DISK_SPACE_ARRAY_LENGTH);
връщане EXIT_SUCCESS;

Масивът freeDiskSpace се нуждае от памет, така че ще трябва да поискате одобрение от Linux, за да получите малко памет. Тъй като обаче е очевидно, когато четете изходния код, че ще ви е необходим масив от 7 int, компилаторът автоматично иска Linux за него и той ще го разпредели в стека. Това по същество означава, че това хранилище се унищожава, когато върнете функцията, където е декларирана променливата. Ето защо не можете да направите това:

#include
#include
#define DISK_SPACE_ARRAY_LENGTH 7
int * getFreeDiskSpace ()
int statsList [DISK_SPACE_ARRAY_LENGTH] = 0;
/ * ЗАЩО ПРАВИМ ТОВА?! statsList ще бъде унищожен! * /
return statsList;

int main ()
/ * Съдържа свободно място на диска през последните 7 дни. * /
int * freeDiskSpace = NULL;
freeDiskSpace = getFreeDiskSpace ();
връщане EXIT_SUCCESS;

Сега виждате по-лесно проблема? След това искате да обедините два низа. В Python и JavaScript бихте направили:

newStr = str1 + str2

Но както знаете, в C не работи така. Така че, за да създадете URL адрес например, трябва да обедините два низа, като URL път и име на домейн. В C имаме strcat, нали, но работи само ако имате масив с достатъчно място за него.

Ще се изкушите да знаете дължината на новия низ, като използвате strlen и ще бъдете прав. Но тогава, как бихте поискали от Linux да резервира това неизвестно количество памет? Компилаторът не може да ви помогне: точното пространство, което искате да разпределите, е известно само по време на изпълнение. Точно там се нуждаете от динамично разпределение и malloc.

Писане на първата ми C функция с malloc

Преди да напишете код, малко обяснение: malloc ви позволява да разпределите определен брой байтове за използването на вашето приложение. Наистина е лесен за използване: извиквате malloc с необходимия брой байтове и той връща указател към новата ви област, която Linux е запазил за вас.

Имате само 3 отговорности:

  1. Проверете дали malloc връща NULL. Това се случва, когато Linux няма достатъчно памет за предоставяне.
  2. Освободете променливите си веднъж неизползвани. В противен случай ще загубите памет и това ще забави приложението ви.
  3. Никога не използвайте зоната на паметта, след като сте освободили променливата.

Ако следвате всички тези правила, всичко ще върви добре и динамичното разпределение ще ви реши много проблеми. Тъй като избирате кога да освободите паметта, можете също безопасно да върнете променлива, разпределена с malloc. Само не забравяйте да го освободите!

Ако се чудите как да освободите променлива, това е с безплатната функция. Извикайте го със същия указател, от който ви е върнал malloc, и паметта се освобождава.

Позволете ми да ви покажа с примера на concat:

#include
#include
#include
/ *
* Когато извиквате тази функция, не забравяйте да проверите дали връщаната стойност е NULL
* Ако не е NULL, трябва да извикате free на върнатия указател, след като стойността
* вече не се използва.
* /
char * getUrl (const char * const baseUrl, const char * const toolPath)
size_t finalUrlLen = 0;
char * finalUrl = NULL;
/ * Проверка за безопасност. * /
if (baseUrl == NULL || toolPath == NULL)
връщане NULL;

finalUrlLen = strlen (baseUrl) + strlen (toolPath);
/ * Не забравяйте '\ 0', следователно + 1. * /
finalUrl = malloc (sizeof (char) * (finalUrlLen + 1));
/ * Следвайки правилата за malloc ... * /
if (finalUrl == NULL)
връщане NULL;

strcpy (finalUrl, baseUrl);
strcat (finalUrl, toolPath);
return finalUrl;

int main ()
char * googleImages = NULL;
googleImages = getUrl ("https: // www.google.com "," / imghp ");
ако (googleImages == NULL)
връщане EXIT_FAILURE;

put ("URL адрес на инструмента:");
поставя (googleImages);
/ * Вече не е необходимо, освободете го. * /
безплатно (googleImages);
googleImages = NULL;
връщане EXIT_SUCCESS;

Така че виждате практически пример за използване на динамични разпределения. Първо, избягвам подводни камъни, като например даване на getUrl възвръщаема стойност направо в функция пут. След това отделям време и за коментар и документирам факта, че връщаната стойност трябва да бъде освободена правилно. Също така проверявам за NULL стойности навсякъде, така че всичко неочаквано може да бъде безопасно уловено, вместо да срива приложението.

И накрая, полагам допълнителни грижи за освобождаването на променливата и след това задаването на указателя на NULL. Това избягва да бъдете изкушени да използвате - дори по погрешка - освободената вече зона на паметта. Но както можете да видите, лесно е да освободите променлива.

Може да забележите, че използвах sizeof в malloc. Той позволява да се знае колко байта използва char и изяснява намерението в кода, така че да е по-четлив. За char sizeof (char) винаги е равен на 1, но ако вместо това използвате масив от int, той работи точно по същия начин. Например, ако трябва да резервирате 45 int, просто направете:

fileSizeList = malloc (sizeof (int) * 45);

По този начин бързо виждате колко искате да разпределите, затова винаги препоръчвам използването му.

Как работи malloc под капака?

malloc и free са всъщност функции, включени във всички програми на C, които ще говорят с Linux от ваше име. Това също ще улесни динамичното разпределение, тъй като в началото Linux не ви позволява да разпределяте променливи от всички размери.

Linux предоставя два начина да получите повече памет всъщност: sbrk и mmap. И двете имат ограничения и едно от тях е: можете да разпределите само относително големи суми, като 4 096 байта или 8 192 байта. Не можете да поискате 50 байта, както направих в примера, но също така не можете да поискате и 5894 байта.

Това има обяснение: Linux трябва да поддържа таблица, в която да казва кое приложение е запазило коя зона на паметта. И тази таблица използва и пространство, така че ако всеки байт се нуждае от нов ред в тази таблица, ще е необходим голям дял памет. Ето защо паметта е разделена на големи блокове, например, 4096 байта, и подобно на това, че не можете да си купите 2 портокала и половина в хранителна стока, не можете да поискате половин блокове.

Така че malloc ще вземе тези големи блокове и ще ви даде малко парче от тези блокове памет, когато го извикате. Освен това, ако сте освободили няколко променливи, но недостатъчно, за да оправдае освобождаването на цял блок, системата на malloc може да запази блокове и да рециклира зони на паметта, когато извикате отново malloc. Това има предимството да направи malloc по-бърз, но паметта, запазена от malloc, не може да се използва в друго приложение, докато програмата в момента не го използва в действителност.

Но malloc е умен: ако се обадите на malloc, за да разпредели 16 MiB или голяма сума, malloc вероятно ще поиска Linux за пълни блокове, посветени само за тази голяма променлива, като използва mmap. По този начин, когато се обадите безплатно, по-вероятно ще избегнете загубата на място. Не се притеснявайте, malloc върши много по-добра работа при рециклирането, отколкото хората с нашите боклуци!

Заключение

Мисля, че сега по-добре разбирате как работи всичко това. Разбира се, динамичното разпределение е голяма тема и мисля, че можем да напишем пълна книга по темата, но тази статия трябва да ви улесни с концепцията както като цяло, така и с практически съвети по програмиране.

Емулирайте кликванията на мишката, като задържите курсора на мишката с кликаща мишка в Windows 10
Използването на мишка или клавиатура в неправилна поза при прекомерна употреба може да доведе до много здравословни проблеми, включително напрежение, ...
Добавете жестове на мишката към Windows 10, като използвате тези безплатни инструменти
През последните години компютрите и операционните системи значително се развиха. Имаше време, когато потребителите трябваше да използват команди за на...
Контролирайте и управлявайте движението на мишката между множество монитори в Windows 10
Двоен дисплей на мишката ви позволява да контролирате и конфигурирате движението на мишката между множество монитори, като забавя движенията му близо ...