C/C++ (20) - Alokace paměti
Jazyk C poskytuje programátorovi poměrně nízkoúrovňový přístup do paměti. Dnes si ukážeme jak o pamět za běhu programu požádat a jak ji uvolnit. Dojde i na některé další paměťové knihovní funkce.
26.5.2005 06:00 |
Jan Němec
| Články autora
| přečteno 39812×
Alokace paměti
Z předchozích dílů známe dva odlišné způsoby vyhrazení paměti, v obou případech
se jedná o víceméně implicitní alokaci paměti, o kterou se postará překladač
při definici proměnné. V prvním případě jde o proměnnou definovanou mimo
tělo funkce, zde se místo vyhradí již při zavedení programu do paměti. Do druhé
kategorie spadají parametry a lokální proměnné funkcí, pro něž vyhradí
překladač místo na zásobníku a to až za běhu programu při vstupu do funkce.
Problém nastane, pokud neznáme paměťové požadavky programu již v době překladu.
Jedná se přitom o zcela běžnou situaci, například programátor grafického
editoru nezná velikost obrázků, které bude uživatel upravovat. První způsob
vyhrazení paměti pro data upravovaného obrázku, definice globální proměnné
typu pole, je prakticky nepoužitelný. Při malém rozměru bychom nemohli
editovat velké obrázky, definice velkého pole by zase znemožnila spuštění
programu na slabších počítačích, navíc i na silných strojích by se jednalo
o trestuhodné mrhání pamětí, která by pak chyběla jiným procesům. Druhý způsob,
definice lokální proměnné sice ve spojení s rekurzí problém teoreticky řeší
(ve funkci můžeme definovat malé pole a vyvolat rekurzi do potřebné hloubky,
čímž získáme dostatek instancí malých polí, na něž můžeme přistupovat přes
ukazatele), ale pro praktickou použitelnost a efektivitu algoritmů by měl
podobný přístup ještě mnohem horší důsledky než segmentace paměti v MS-DOSu.
Navíc celkové množství paměti na zásobníku může být na konkrétních platformách
nepříjemně omezené.
Naštěstí lze o paměť požádat za běhu programu i explicitně.
#include <stdlib.h>
void *malloc(size_t size);
void free(void *ptr);
Funkce malloc alokuje paměť o velikosti size bytů. Typ size_t je nezáporný
celočíselný typ podobně jako například unsigned. V případě úspěchu vrací funkce
platný ukazatel na počátek alokované paměti, v opačném případě NULL.
Obsahem paměti mohou být libovolná data, která můžeme přepsat.
Po ukončení práce s pamětí je třeba zavolat free, jinak by zůstala rezervována
a nevyužita.
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv) {
int pocet, i;
int *pole;
/* Ošetření parametrů programu */
if (argc != 2 || (pocet = atoi(argv[1])) < 1) {
puts("syntaxe: alokace [celé kladné číslo]");
return 1;
}
/* Alokace paměti, něco jako definice
int pole[pocet];
ale pocet je proměnná, nikoli konstanta, uvedená definice by tedy
ani neprošla překladem.
*/
pole = malloc(pocet * sizeof(int));
/*
Alokace se nemusí podařit, například pokud chceme větší blok paměti, než
je dostupný.
*/
if (!pole) {
puts("neúspěch alokace");
return 1;
}
/*
Paměť nějakým způsobem použijeme. Jistě by se dal vymyslet užitečnější
příklad.
*/
for (i = 0; i < pocet; i++)
pole[i] = i;
for (i = 0; i < pocet; i++)
printf("%i ", pole[i]);
/*
A uvolníme.
*/
free(pole);
}
Běžné operační systémy poskytují procesům služby, které zhruba odpovídají
funkcím malloc a free, nicméně C runtime knihovna se obvykle snaží využití
paměti nějakým způsobem optimalizovat, takže jednotlivá volání ještě nemusí
vždy skončit na operačním systému. Udržovat informaci o volném místě pro
jednotlivé byty by bylo velmi neefektivní, paměť se proto zpravidla
ve skutečnosti volajícímu přiděluje po blocích (například 16 bytů), takže
malloc(1) nezabere jen jeden byte. Alokace velkého množství několikabytových
polí může být proto neefektivní.
Při práci s dynamicky alokovanou pamětí se můžeme dopustit celé řady chyb
s nepříjemnými důsledky. Chyba se v některých případech nemusí projevit
vždy, navíc dost často ovlivní chování programu mimo chybné místo.
- Přístup na nenaalokované místo
Program zpravidla spadne nebo si přepíše vlastní data.
- Přístup za naalokované místo
Nemusí se stát vůbec nic (alokace po blocích), program může spadnout
hned (neplatná adresa), později (porušeny struktury volné paměti) nebo
si přepsat data z jiné alokace.
- Přístup do uvolněné paměti
Projev chyby opět závisí na okolnostech.
- Neuvolnění paměti
Dnešní operační systémy paměť uvolní po ukončení procesu, ale při alokaci
v cyklu a dostatečně dlouhém běhu programu může nastat nedostatek paměti.
- Opakované volání free
Již jednou uvolněný ukazatel znovu dealokujeme. Opět může vést k pádu
programu, ale nemusí se stát vůbec nic.
Je vidět, že jazyk C "nabízí" vývojářům opravdu velké množství druhů
chyb při práci dynamicky alokovanou pamětí a programátoři tuto "nabídku"
intenzivně využívají. Na druhou stranu v C má programátor správu paměti pod
kontrolou a záleží jen na něm, zda dokáže svůj program odladit. O modernějších
jazycích typu Java, kde se o dealokaci stará runtime se to říci nedá.
Ukazatel vrácený funkcí malloc můžeme přetypovat na ukazatel na
unsigned char
a získat tak přístup do paměti jako do pole bytů. Jednoduchými for cykly
tak lze paměť kopírovat, porovnávat nebo do ní psát, nicméně pro základní
operace je jednodušší a efektivnější používat knihovní funkce pro práci
s pamětí.
#include <string.h>
void *memcpy(void *dest, const void *src, size_t n);
void *memmove(void *dest, const void *src, size_t n);
void *memset(void *s, int c, size_t n);
int memcmp(const void *s1, const void *s2, size_t n);
Funkce memcpy kopíruje size_t bytů z adresy src na adresu dest, tento ukazatel
je zároveň návratovou hodnotou funkce. Důležité je, že se oba bloky paměti
nesmějí překrývat, nelze tedy například pomocí memcpy posunout nějaké delší
pole o jeden byte. Tento nedostatek odstraňuje funkce memmove, která však může
být nepatrně pomalejší. Pomocí memset lze nastavit všechny byty v bloku paměti
na adrese s délky n na hodnotu c. V praxi se nejčastěji používá pro nulování.
Funkce memcmp paměť porovnává. Oba bloky s1 i s2 mají délku n a funkce vrací
záporné číslo pokud je první odlišný byte obou bloků menší u s1, v opačném
případě vrací kladné číslo a konečně v případě rovnosti je návratovou hodnotou
0. Když dodám, že porovnání probíhá bezznaménkově, jistě uhodnete, co vypíše
na běžné platformě následující program.
#include <stdio.h>
#include <string.h>
int main(void) {
signed char s1 = 0;
signed char s2 = -1;
printf("%i\n", memcmp(&s1, &s2, 1));
return 0;
}
Funkce memcmp porovnává dva jednobytové bloky o hodnotách s1 a s2. Při běžném
porovnání pomocí operátoru < by si překladač odvodil z typu operandů, že
má použít znaménkové porovnání, ale memcmp kontext volání pochopitelně nezná
a porovnává obě čísla, jako by se jednalo o unsigned char. Běžnou implementací
záporných čísel je dvojkový doplněk, -1 je 255 bezznaménkově, tedy s1 < s2.
Program vypíše -1.
Z příkladu je patrné, že funkce pro práci s pamětí lze použít nejen pro
dynamicky alokovanou paměť, ale i na běžné proměnné nebo pole. V těchto
případech je vhodné velikost bloku paměti zadat pomocí operátoru sizeof.
#define VELIKOST 1024
int a[VELIKOST];
int b[VELIKOST];
/* ... */
/* do pole a nakopíruj pole b */
memcpy(a, b, sizeof(a));
Nedbalí programátoři jsou často líní definovat velikost pole pomocí makra,
a velikost kopírovaného bloku pomocí sizeof. Obvykle také předpokládají, že
velikost číselných typů je neměnná. Při změně velikosti polí nebo dokonce
platformy programu pak musejí opravovat kód na více místech a vznikají tak
zbytečné chyby.
Pokračování příště
V příštím dílu se podíváme na funkce pro práci s řetězci.
Verze pro tisk
|
Příspívat do diskuze mohou pouze registrovaní uživatelé.
|
|

Vyhledávání software

Vyhledávání článků
28.11.2018 23:56 /František Kučera Prosincový sraz spolku OpenAlt se koná ve středu 5.12.2018 od 16:00 na adrese Zikova 1903/4, Praha 6. Tentokrát navštívíme organizaci CESNET. Na programu jsou dvě přednášky: Distribuované úložiště Ceph (Michal Strnad) a Plně šifrovaný disk na moderním systému (Ondřej Caletka). Následně se přesuneme do některé z nedalekých restaurací, kde budeme pokračovat v diskusi.
Komentářů: 1
12.11.2018 21:28 /Redakce Linuxsoft.cz 22. listopadu 2018 se koná v Praze na Karlově náměstí již pátý ročník konference s tématem Datová centra pro business, která nabídne odpovědi na aktuální a často řešené otázky: Jaké jsou aktuální trendy v oblasti datových center a jak je optimálně využít pro vlastní prospěch? Jak si zajistit odpovídající služby datových center? Podle jakých kritérií vybírat dodavatele služeb? Jak volit vhodné součásti infrastruktury při budování či rozšiřování vlastního datového centra? Jak efektivně datové centrum spravovat? Jak co nejlépe eliminovat možná rizika? apod. Příznivci LinuxSoftu mohou při registraci uplatnit kód LIN350, který jim přinese zvýhodněné vstupné s 50% slevou.
Přidat komentář
6.11.2018 2:04 /František Kučera Říjnový pražský sraz spolku OpenAlt se koná v listopadu – již tento čtvrtek – 8. 11. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma umění a technologie, IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář
4.10.2018 21:30 /Ondřej Čečák LinuxDays 2018 již tento víkend, registrace je otevřená.
Přidat komentář
18.9.2018 23:30 /František Kučera Zářijový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 20. 9. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář
9.9.2018 14:15 /Redakce Linuxsoft.cz 20.9.2018 proběhne v pražském Kongresovém centru Vavruška konference Mobilní řešení pro business.
Návštěvníci si vyslechnou mimo jiné přednášky na témata: Nejdůležitější aktuální trendy v oblasti mobilních technologií, správa a zabezpečení mobilních zařízení ve firmách, jak mobilně přistupovat k informačnímu systému firmy, kdy se vyplatí používat odolná mobilní zařízení nebo jak zabezpečit mobilní komunikaci.
Přidat komentář
12.8.2018 16:58 /František Kučera Srpnový pražský sraz spolku OpenAlt se koná ve čtvrtek – 16. 8. 2018 od 19:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát jsou tématem srazu databáze prezentaci svého projektu si pro nás připravil Standa Dzik. Dále bude prostor, abychom probrali nápady na využití IoT a sítě The Things Network, případně další témata.
Přidat komentář
16.7.2018 1:05 /František Kučera Červencový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 19. 7. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát bude přednáška na téma: automatizační nástroj Ansible, kterou si připravil Martin Vicián.
Přidat komentář
Více ...
Přidat zprávičku
 Poslední diskuze
31.7.2023 14:13 /
Linda Graham iPhone Services
30.11.2022 9:32 /
Kyle McDermott Hosting download unavailable
13.12.2018 10:57 /
Jan Mareš Re: zavináč
2.12.2018 23:56 /
František Kučera Sraz
5.10.2018 17:12 /
Jakub Kuljovsky Re: Jaký kurz a software by jste doporučili pro začínajcího kodéra?
Více ...
|