Масиви. Разпределяне на памет в C (функция malloc) Как работи malloc

При всяко инициализиране на указателя се използва адресът на една или друга променлива. Това се дължи на факта, че компилаторът на езика C++ автоматично разпределя памет за съхранение на променливи и с помощта на указател можете да работите с тази разпределена област без последствия. Има обаче функции malloc() и free(), които ви позволяват да разпределяте и освобождавате памет според нуждите. Тези функции се намират в библиотеката и имат следния синтаксис:

void* malloc(size_t); // функция за разпределение на паметта
void free(void* memblock); //функция за освобождаване на паметта

Тук size_t е размерът на разпределената област на паметта в байтове; void* е общ тип указател, т.е. не е свързан с конкретен тип. Нека да разгледаме как работят тези функции, използвайки примера за разпределяне на памет за 10 елемента от двоен тип.

Списък 4.3. Програмиране на динамичен масив.

#включи
#включи
int main()
{
двойно*ptd;
ptd = (double *)malloc(10 * sizeof(double));
ако (ptd != NULL)
{
for(int i = 0;i ptd[i] = i;
) else printf(“Неуспешно заделяне на памет.”);
безплатно (ptd);
връщане 0;
}

Когато се извика функцията malloc(), необходимата област на паметта се изчислява за съхранение на 10 двойни елемента. За да направите това, използвайте функцията sizeof(), която връща броя байтове, необходими за съхраняване на един двоен елемент. След това стойността му се умножава по 10 и резултатът е обемът за 10 двойни елемента. В случаите, когато по някаква причина определеното количество памет не може да бъде разпределено, функцията malloc() връща NULL. Тази константа е дефинирана в няколко библиотеки, включително и. Ако функцията malloc() върна указател към разпределената област на паметта, т.е. не е равно на NULL, тогава се изпълнява цикъл, където се записват стойностите за всеки елемент. При излизане от програмата се извиква безплатна функция(), което освобождава предварително разпределена памет. Формално, програма, написана на C++ след завършване автоматично освобождава цялата предварително разпределена памет и функцията free() в този случай може да бъде пропусната. Въпреки това, когато пишете по-сложни програми, често трябва да разпределяте и освобождавате памет много пъти. В този случай функцията free() играе голяма роля, т.к Паметта, която не е освободена, не може да се използва повторно, което ще доведе до ненужна загуба на компютърни ресурси.

Използването на указатели е „наследено“ от езика C. За да опрости процеса на промяна на параметрите, C++ въвежда концепцията за препратка. Препратката е псевдоним (или второ име), който програмите могат да използват за препратка към променлива. За да декларирате връзка в програма, използвайте знака & пред нейното име. Особеността на използването на връзки е необходимостта те да се инициализират веднага след деклариране, например:

int var;
int &var2 = var;

Тук се декларира препратка с име var2, която се инициализира от променливата var. Това означава, че променливата var има свой собствен псевдоним var2, чрез който е възможна всяка промяна в стойностите на променливата var. Предимството на използването на препратки пред указатели е, че те трябва да бъдат инициализирани, така че програмистът винаги е сигурен, че променливата var2 работи с разпределена област на паметта, а не с произволна, което е възможно при използване на указатели. За разлика от указателите, референцията се инициализира само веднъж, когато се декларира. Повторната инициализация ще доведе до грешка по време на компилиране. Това осигурява надеждно използване на връзките, но намалява гъвкавостта на тяхното използване. Обикновено препратките се използват като аргументи на функции за промяна на предадени променливи във функциите. Следният пример демонстрира използването на такава функция:

Списък 4.4. Пример за използване на връзки.

void swap (int& a, int& b)
{
int temp = a;
a = b;
b = температура;
}
int main()
{
int agr1 = 10, arg2 = 5;
размяна (arg1, arg2);
връщане 0;
}

В този пример функцията swap() приема два аргумента, които са препратки към две променливи. Използвайки референтните имена a и b, променливите arg1 и arg2, дефинирани в main, се манипулират основни функции() и се предава като параметри на функцията swap(). Предимството на функцията swap() (която използва препратки, а не указатели към променливи) е, че тя гарантира, че функцията приема подходящите типове променливи като аргументи, а не друга информация, и че препратките се инициализират правилно, преди да бъдат използвани. Това се следи от компилатора, когато преобразува програмния текст в обектен код и извежда съобщение за грешка, ако използването на препратки е неправилно. За разлика от указателите, следните операции не могат да се извършват с препратки:

Не можете да получите адреса на връзка, като използвате C++ адресния оператор;
не можете да присвоите указател към връзка;
не можете да сравнявате референтни стойности с помощта на C++ оператори за сравнение;
Не можете да извършвате аритметични операции върху препратка, например добавяне на отместване;

Динамично разпределение на паметта

Основни проблеми при приложението

Нулев указател

Нулевият указател е указател, който съхранява специална стойност, използвана за указване, че дадена променлива на указателя не препраща към (сочи към) никакъв обект. В различните езици за програмиране се представя от различни константи.

·В езиците C# и Java: null

·В езиците C и C++: 0 или NULL макрос. В допълнение, в стандарта C++11, за обозначаване нулев указателнов предложен ключова дума nullptr

·В Pascal и Ruby: нула

·На езика Component Pascal: NIL

·В Python: Няма

Указателите са трудни за управление. Доста лесно е да напишете грешна стойност в указател, което може да причини трудна за възпроизвеждане грешка. Например, случайно сте променили адреса на указател в паметта или сте разпределили неправилно памет за информация и тогава може да ви очаква изненада: друга много важна променлива, която се използва само в програмата, ще бъде презаписана. В този случай ще ви бъде трудно да възпроизведете грешката. Няма да е лесно да разберете къде точно е грешката. И не винаги ще бъде тривиално да го премахнете (понякога ще трябва да пренапишете значителна част от програмата).

За решаване на някои проблеми има методи за защита и застраховка:

След като изучавахме указатели в езика C, открихме възможностите за динамично разпределение на паметта. Какво означава? Това означава, че при динамичното разпределение на паметта паметта се запазва не на етапа на компилация, а на етапа на изпълнение на програмата. И това ни дава възможност да разпределяме паметта по-ефективно, главно за масиви. При динамичното разпределение на паметта не е необходимо да задаваме размера на масива предварително, особено след като не винаги се знае какъв размер трябва да бъде масивът. След това нека да разгледаме как може да се разпредели паметта.

Функцията malloc() е дефинирана в заглавния файл stdlib.h, използва се за инициализиране на указатели с необходимото количество памет. Паметта се разпределя от сектор оперативна паметдостъпен за всички програми, работещи на тази машина. Аргументът на функцията malloc() е броят байтове памет, които трябва да бъдат разпределени; функцията връща указател към разпределения блок в паметта. Функцията malloc() работи точно като всяка друга функция, нищо ново.

защото Различни видоведанните имат различни изисквания към паметта, по някакъв начин трябва да се научим как да получаваме размера в байтове за данните различни видове. Например, имаме нужда от част от паметта за масив от стойности от тип int - това е един размер на паметта и ако трябва да разпределим памет за масив със същия размер, но от тип char - това е различен размер. Следователно трябва по някакъв начин да изчислите размера на паметта. Това може да стане с помощта на операцията sizeof(), която взема израз и връща неговия размер. Например sizeof(int) ще върне броя байтове, необходими за съхраняване на int стойност. Да разгледаме един пример:


Yandex.Direct


#включи int *ptrVar = malloc(sizeof(int));

В този пример, в ред 3На указателя ptrVar се присвоява адрес на място в паметта, чийто размер съответства на типа данни int. Автоматично тази област от паметта става недостъпна за други програми. Това означава, че след като разпределената памет стане ненужна, тя трябва да бъде изрично освободена. Ако паметта не е изрично освободена, тогава при завършване на програмата паметта няма да бъде освободена за операционна система, това се нарича изтичане на памет. Можете също така да определите размера на разпределената памет, която трябва да бъде разпределена, като подадете нулев указател, ето пример:



Както можете да видите, в такъв запис има един много силна страна, не трябва да извикваме функцията malloc() с помощта на sizeof(float). Вместо това предадохме указател към типа float на malloc(), в който случай размерът на разпределената памет ще се определи автоматично!

Това е особено полезно, ако трябва да разпределите памет далеч от дефиницията на указателя:


float *ptrVar; /* . . . сто реда код */ . . . ptrVar = malloc(sizeof(*ptrVar));

Ако трябваше да използвате конструкция за разпределяне на памет с операцията sizeof(), тогава ще трябва да намерите дефиницията на указател в кода, да погледнете неговия тип данни и едва тогава ще можете да разпределите правилно паметта.

  • опишете указател (тип * указател;);
  • определя размера на масива;
  • разпределете част от паметта за съхраняване на масива и присвоете адреса на тази секция от паметта на указателя.

За да разпределите памет в C++, можете да използвате оператора new или функциите на езика C - calloc, malloc, realloc. Всички функции са в библиотеката stdlib.h.

5.2.1 malloc функция

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

void* malloc(размер_t размер);

където размерът е цяло число без знак 1 size_t - основен без знак целочислен типезик C/C++, който е избран така, че да може да бъде написан максимален размертеоретично възможен масив от всякакъв тип. В 32-битова операционна система size_t е 32-битово число без знак (максимална стойност 2 32 - 1), в 64-битова операционна система е 64-битово число без знак (максимална стойност 2 64 - 1)., който определя размера на разпределената памет в байтове. Ако запазването на паметта е било успешно, функцията връща променлива от тип void*, която може да бъде преобразувана във всеки желан тип указател. Ако паметта не може да бъде разпределена, функцията ще върне празен указател NULL.

Например,

двойно *h; //Опишете указател за удвояване. int k; cin>>k; //Въведете цяло число k. //Разпределете област на паметта за съхраняване на k елемента от двоен тип. //Адресът на тази секция се съхранява в променливата h. h=(double *) malloc (k* sizeof (double)); //h - адрес на началото на секцията с памет, //h + 1, h + 2, h + 3 и т.н. - адреси на следващи елементи от двоен тип

5.2.2 функция calloc

Функцията calloc е предназначена да разпределя и изчиства памет.

void * calloc(size_t num, size_t size);

С помощта на функцията ще бъде разпределена секция от памет, в която ще се съхраняват num елементи с размер байтове всеки. Всички елементи от избраната област се нулират. Функцията връща указател към разпределената област или NULL, ако паметта не може да бъде разпределена.

Например,

плаващ *h; //Опишете указател към плаващ. int k; cin>>k; //Въведете цяло число k. //Разпределете област на паметта за съхраняване на k елемента от тип float. //Адресът на тази секция се съхранява в променливата h. h=(float *) calloc (k, sizeof (float)); //h е адресът на началото на секцията с памет, //h + 1, h + 2, h + 3 и т.н. са адресите на следващите елементи от типа float.

5.2.3 функция за прехвърляне

Функцията realloc преоразмерява предварително разпределено място в паметта. Достъпът до функцията се осъществява по следния начин:

void *realloc(void *p, size_t size);

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

5.2.4 Безплатна функция

Функцията free се използва за освобождаване на разпределената памет. Те се обръщат към нея така:

void free(void *p);

където p е указател към място в паметта, предварително разпределено от malloc, calloc или realloc.

5.2.5 Оператори new и delete

Езикът C++ има новите оператори за разпределяне и изтриване, за да освободите част от паметта.

За да разпределите памет за съхраняване на n елемента от същия тип, новият оператор има формата [

Описание на функциите

#включи void * malloc (размер_t размер) ; void * calloc (size_t num, size_t size) ;

Предназначение

mallocприема като аргумент размера на разпределената област в байтове; връща нетипизиран указател (void*) към област на паметта с декларирания размер или NULL, ако паметта не може да бъде разпределена. Съдържанието на разпределената област на паметта е недефинирано.

callocприема като аргумент броя на елементите и размера на всеки елемент в байтове; връща нетипизиран указател (void*) към област на паметта с декларирания размер или NULL, ако паметта не може да бъде разпределена. Стойностите на елемента са зададени на нула. mallocработи по-бързо от calloc, поради липса на функция за нулиране на разпределената памет.

Функционални параметри

malloc

  • размер- размер на разпределената област на паметта

calloc

  • бр- брой на разпределените елементи
  • размер- размер на всеки елемент

Върната стойност

Функциите връщат нетипизиран (void*) указател към областта на паметта, ако е успешно, или NULL в противен случай.

Типични грешки при използване

  • Паметта остава „заета“, дори ако никой указател в програмата не препраща към нея (функцията free() се използва за освобождаване на памет). Натрупването на „загубени” области на паметта води до постепенно деградиране на системата. Грешките, свързани с неуспешно освобождаване на заети области на паметта, се наричат ​​изтичане на памет. изтичане на памет).
  • Ако количеството данни, които се обработват, е по-голямо от количеството разпределена памет, други области на динамичната памет може да бъдат повредени. Тези грешки се наричат ​​грешки при препълване на буфера. препълване на буфера).
  • Ако указател към разпределена област на паметта продължава да се използва след освобождаване, може да възникне изключение при достъп до „вече несъществуващ“ блок от динамична памет. изключение), програмата се срива, други данни са повредени или нищо не се случва (в зависимост от вида на операционната система и използвания хардуер).
  • Ако free() се извика повече от веднъж на едно място в паметта, това може да повреди данните на библиотеката, съдържаща самата malloc/free и да доведе до непредсказуемо поведение в произволни моменти.
  • Лоша организация на програма, в която се разпределят и освобождават много малки количества памет - възможно е фрагментиране свободна памет(„пунктирана линия“), в която остава общо много свободна памет, но е невъзможно да се разпредели голямо парче.

Точното поведение на функциите е описано в стандарта ANSI C и също е посочено в дефиницията на функцията в стандарта POSIX.

Примери за използване

malloc

Float * dynamic_array = malloc(number_of_elements * sizeof (float) ) ; ако (! динамичен_масив) ( )

calloc

Float * dynamic_array = calloc(number_of_elements, sizeof (float) ) ; ако (! динамичен_масив) ( /* обработка на грешка при разпределяне на памет */ } /* ... работа с елементи от масив ... */безплатен (динамичен_масив); динамичен_масив = NULL;

Вижте също

  • stdlib
  • разпределяне
  • сапун malloc
  • сапун унищожи

Източници

  • malloc (английски) . - Описание на функцията malloc в стандарта POSIX.
  • calloc (английски). - Описание на функцията calloc в стандарта POSIX.

Фондация Уикимедия. 2010 г.

Вижте какво е "Malloc" в други речници:

    Малок- est en informatique une fonction de la bibliothèque standard du C permettant d allouer dynamiquement de la mémoire. La libération de la mémoire ainsi réservée s effectue avec la fonction free. Cette fonction est déclarée dans le fichier d en tête … Wikipédia en Français

    malloc- est en informatique une fonction de la bibliothèque standard de C permettant d allouer dynamiquement de la mémoire. La libération de la mémoire ainsi réservée s effectue avec la fonction free. Cette fonction est déclarée dans l en tête

    Малок- В компютрите malloc е подпрограма, предоставена в стандартните библиотеки на езика за програмиране C и C++ за извършване на динамично разпределение на паметта. Обосновка Езикът за програмиране C управлява паметта статично или автоматично. Статично... ...Уикипедия

    Малок- En informática, malloc es una subrutina para el ejercicio de asignación de memoria dinámica en los lenguajes de programación C y C++. Това е съкращение на английски език Разпределение на паметта. Forma parte de la biblioteca estándar stdlib.h para ambos... ... Wikipedia Español

    malloc- 1. съществително Подпрограма в стандартната библиотека на езиците за програмиране C за извършване на динамично разпределение на паметта. Той сравнява поведението на девет различни mallocs, когато се използва с Hummingbird и GNU Emacs проследяване на активността на динамичната памет. 2. глагол ... Уикиречник

    malloc- ● np. cde. LANGC CMDE Свиване на разпределението на паметта. Nom d une fonction très importante de la bibliothèque C, car elle permet d attributer une partie de la mémoire à un processus. Voir aussi calloc. (D après) ... Франкофонски информационен речник

    C динамично разпределение на паметта- C Standard Library Типове данни Класификация на знаци Низове Математика Вход/изход на файл Дата/час Локализация ... Wikipedia

    показалец (изчислителен)- Тази статия е за типа данни за програмиране. За интерфейса за въвеждане (например компютърна мишка) вижте Посочващо устройство. Указател a, сочещ към адреса на паметта, свързан с променлива b. Обърнете внимание, че в тази конкретна диаграма изчислителната... Wikipedia

    Значимостта на темата на статията е поставена под въпрос. Моля, покажете в статията значимостта на нейния предмет, като добавите доказателства за значимост според частни критерии за значимост или, в случай на частни критерии за значимост за... ... Wikipedia

    Висяща показалка- Висящите указатели и дивите указатели в компютърното програмиране са указатели, които не сочат към валиден обект от съответния тип. Това са специални случаи на нарушения на безопасността на паметта. Висящ указател Висящи указатели възникват, когато даден обект е... ... Wikipedia

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

char place = "Pork Liver Bay";

и ще бъде разпределена достатъчно памет за запомняне на този низ.

Или можем да бъдем по-конкретни и да поискаме определено количество памет:

вътрешен плочи;

Това описание разпределя 100 места в паметта, всяко от които е проектирано да съхранява целочислена стойност.

Езикът C не спира дотук. Позволява ви да разпределите допълнителна памет, докато програмата работи. Да предположим, че например пишете разговорна програма и не знаете предварително колко данни ще трябва да въведете. Можете да разпределите количеството памет, от което (както смятате) се нуждаете, и след това, ако е необходимо, да поискате повече. На фиг. 15.5 дава пример, който използва функцията malloc()да направи точно това. Също така обърнете внимание как такава програма използва указатели.

/* добавя памет, ако е необходимо */

#включи

#define STOP " " /* сигнал за спиране на входа */

#define БЛОК 100 /* байтове памет */

#define LIM 40 /* ограничава дължината на входния низ */

#define MAX 50 /* максимален брой входни редове */

#define DRAMA 20000 /* дълго забавяне */

магазин за въглища; /* начален блок памет */

чарсимфа; /* приемник на входен низ */

char *край; /* сочи към края на паметта */

char *започва; /* сочи към началото на редовете */

int индекс = 0; /* брой редове за въвеждане */

int брой; /* брояч */

char *malloc(); /* разпределител на памет */

започва = съхранява;

край = започва + БЛОКИРАНЕ - 1;

puts("Назовете няколко симфонични оркестъра.");

puts("Въведете един по един: натиснете [enter] в началото");

puts(" редове, за да завършите списъка си. Добре, готов съм.");

докато (strcmp (fgets (symph, LIM, stdin), STOP) != 0 && индекс< MAX)

( if(strlen(symph) > край - започва)

( /* действия, ако няма достатъчно памет за запомняне на въведените данни */

puts(" Чакай малко. Ще се опитам да намеря допълнителна памет.");

край = започва + БЛОКИРАНЕ - 1;

за (брой = 0; брои< DRAMA; count++);

puts("Намерих някои!"); )

strcpy(започва, симф);

започва = започва + strlen(symph) + 1;

ако (++ индекс< MAX)

printf("Това е %d. Продължете, ако искате.n", индекс); )

puts("Добре, ето какво имам:");

за (брой = 0; брои< index; count ++)

поставя (започва);

ОРИЗ. 15.5. Програма, която добавя памет при поискване.

Ето примерна програма:

Назовете няколко симфонични оркестъра.

Въведете ги един по един; натиснете [enter] в началото

редове, за да завършим нашия списък. Добре, готов съм.

Симфония на Сан Франциско.

Това е 1. Продължете, ако искате.

Чикагска симфония

Това е 2. Продължете, ако искате.

Берлинска филхармония

Това е 3. Продължете, ако искате.

Московска камара

Това е 4. Продължете, ако искате. Лондонска симфония

Това е 5. Продължете, ако искате. Виенска филхармония

Само за секунда. Ще се опитам да намеря допълнителна памет.

Намерих някои!

Това е 6. Продължете, ако искате.

Питсбъргска симфония

Това е 7. Продължете, ако искате.

Добре, ето какво имам:

Симфония на Сан Франциско

Чикагска симфония

Берлинска филхармония

Московска камара

Лондонска симфония

Виенска филхармония

Питсбъргска симфония

Първо нека видим какво прави функцията malloc(). Той приема неподписан целочислен аргумент, който представлява необходимия брой байтове памет. Така, malloc(БЛОКИРАНЕ)изисква 100 байта. Функцията връща указател към типа въглендо началото на нов блок памет. Използвахме описанието

char *malloc();

за да предупреди компилатора, че malloc()връща указател към типа въглен. Затова присвоихме стойността на този указател на елемента от масива започвас помощта на оператора

стартира = malloc(BLOCK);

Добре, нека сега да разгледаме програмен дизайн, който включва съхраняване на всички оригинални низове в един ред в голям масив магазин. Искаме да използваме започваза препратка към началото на първия ред, започва [l]- вторият ред и т.н. На междинния етап програмата въвежда реда в масива симф. Използвахме fgets()вместо получава ()за ограничаване на входния низ до дължината на масива симф.

ОРИЗ. 15.6. Последователни симф линии, записани в масива за съхранение.

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

Ако няма достатъчно място, ние се обаждаме malloc()за подготовка на допълнителна памет. Ние монтираме започвадо началото на нов блок памет, a край- в края на нов блок. Имайте предвид, че нямаме име за тази нова памет. Не е например разширение магазин. Имаме само обозначения за указатели, сочещи към новата област на паметта.

Когато програмата се изпълнява, всеки нов ред се реферира от елемент от масива на указателя започва. Има някои редове магазин, други в една или повече нови области на паметта.

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

Така се използва malloc(). Но да предположим, че искате да работите с памет като вътр, но не въглен. Можете да го използвате и тук malloc(). Ето как се прави:

char *malloc(); /* все още се описва като указател към char */

int *newmem;

newmem = (int *) malloc(l00); /* използвайте операцията за преобразуване на типове */

Отново са необходими 100 байта. Операцията за преобразуване на тип преобразува стойността, върната от указател, в тип въглен, към указател към тип вътр. Ако, както в нашата система, вътрзаема два байта памет, което означава, че нова памет + 1ще увеличи указателя с два байта, т.е. ще го премести към следващото цяло число. Това също означава, че 100 байта могат да се използват за съхраняване на 50 цели числа.

Друга възможност за разпределяне на памет се дава чрез използване на функцията calloc():

char * calloc ();

дълго *newmem;

newmem = (дълъг *) calloc(100, sizeof(дълъг));

като malloc()функция calloc()връща указател към въглен. Трябва да използвате оператора за преобразуване на типа, ако искате да запомните различен тип. Тази нова функция има два аргумента, като и двата трябва да са цели числа без знак. Първият аргумент съдържа необходимия брой места в паметта. Вторият аргумент е размерът на всяка клетка в байтове. В нашия случай дълго



Зареждане...
Връх