LINUXSOFT.cz Přeskoč levou lištu
Uživatel: Heslo:  
   CZUKPL

> 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 35889×

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

pridej.cz

 

DISKUZE

dalsi funkce 26.5.2005 10:44 Aleš Hakl




Příspívat do diskuze mohou pouze registrovaní uživatelé.
> Vyhledávání software
> Vyhledávání článků

17.4.2018 0:46 /František Kučera
Dubnový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 19. 4. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tématem tohoto srazu bude OpenStreetMap (OSM) aneb svobodné mapy.
Přidat komentář

16.3.2018 22:01 /František Kučera
Kulatý OpenAlt sraz v Praze oslavíme klasicky: u limonády a piva! Přijďte si posedět, dát si dobré jídlo a vybrat z mnoha piv do restaurace Kulový blesk, který najdete v centru Prahy nedaleko metra I. P. Pavlova na adrese Sokolská 13, Praha 2. Sraz se koná ve čtvrtek 22. března a začínáme v 18:00. Heslo: OpenAlt. Vezměte s sebou svoje hračky! Uvítáme, když si s sebou na sraz vezmete svoje oblíbené hračky. Jestli máte nějaký drobný projekt postavený na Arduinu, nějakou zajímavou elektronickou součástku, či třeba i pěkný úlovek z crowdfundingové akce, neváhejte. Oslníte ostatní a o zábavu bude postaráno.
Přidat komentář

13.2.2018 0:41 /František Kučera
Únorový pražský sraz OpenAltu se koná 15. 2. 2018 a tentokrát se vydáme na návštěvu do jednoho pražského datacentra. Sejdeme se v 17:50 v severovýchodní části nástupiště tramvajové zastávky Koh-I-Noor. Po exkurzi se přesuneme do restaurace U Pštrosa (Moskevská 49), kde probereme tradiční témata (svobodný software a hardware, DIY, CNC, SDR, 3D tisk…) a tentokrát bude k vidění i IoT brána od The Things Network.
Přidat komentář

11.2.2018 23:11 /Petr Ježek
Hledáte lehký a rychlý prolížeč PDF souborů? Pokud vás již omrzelo čekat na načítání stránek či jiné nešvary, zkuste xreader.
Přidat komentář

11.2.2018 20:35 /Redakce Linuxsoft.cz
Třetí ročník odborné IT konference na téma Cloud computing v praxi proběhne ve čtvrtek 1. března 2018 v konferenčním centru Vavruška, v paláci Charitas, Karlovo náměstí 5, Praha 2 (u metra Karlovo náměstí) od 9:00 hod. dopoledne do cca 16 hod. odpoledne. Konference o trendech v oblasti cloud computingu nabídne i informace o konkrétních možnostech využívání cloudů a řešení vybraných otázek souvisejících s provozem IT infrastruktury.
Přidat komentář

15.1.2018 0:51 /František Kučera
První letošní pražský sraz se koná již tento čtvrtek 18. ledna od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Vítáni jsou všichni příznivci svobodného softwaru a hardwaru, ESP32, DIY, CNC, SDR nebo dobrého piva. Prvních deset účastníků srazu obdrží samolepku There Is No Cloud… just other people's computers. od Free Software Foundation.
Přidat komentář

14.11.2017 16:56 /František Kučera
Máš rád svobodný software a hardware nebo se o nich chceš něco dozvědět? Zajímá tě DIY, CNC, SDR nebo morseovka? Přijď na sraz spolku OpenAlt – tradičně první čtvrtek před třetím pátkem v měsíci: 16. listopadu od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5).
Přidat komentář

12.11.2017 11:06 /Redakce Linuxsoft.cz
PR: 4. ročník odborné IT konference na téma Datová centra pro business proběhne již ve čtvrtek 23. listopadu 2017 v konferenčním centru Vavruška, v paláci Charitas, Karlovo náměstí 5, Praha 2 (u metra Karlovo náměstí) od 9:00. Konference o návrhu, budování, správě a efektivním využívání datových center nabídne odpovědi na aktuální a často řešené otázky, např Jaké jsou aktuální trendy v oblasti datových center a jak je využít pro vlastní prospěch? Jak zajistit pro firmu či jinou organizaci odpovídající služby datových center? Podle jakých kritérií vybrat dodavatele služeb? Jak volit součásti infrastruktury při budování či rozšiřování vlastního datového centra? Jak efektivně spravovat datové centrum? Jak eliminovat možná rizika? apod.
Přidat komentář

   Více ...   Přidat zprávičku

> Poslední diskuze

20.2.2018 18:48 / Ivan Majer
portal

20.2.2018 15:57 / Jan Havel
Jak využíváte služby cloudu v podnikání?

16.1.2018 1:08 / Ivan Pittner
verejna ip od o2 ubuntu

15.1.2018 17:26 / Mira Harvalik
Re: Jak udělat HTML/Javascript swiping gallery do mobilu?

30.12.2017 20:16 / Michal Knoll
odmocnina

Více ...

ISSN 1801-3805 | Provozovatel: Pavel Kysilka, IČ: 72868490 (2003-2018) | mail at linuxsoft dot cz | Design: www.megadesign.cz | Textová verze