Forum » Programiranje » Heap vs Stack [C]
Heap vs Stack [C]
marjan_h ::
Jaz sem začel programirati v Pythonu in Javi in v bistvu sedaj ne razumem dinamične alokacije pomnilnika v C-ju. Prebral sem mnogo tutorialov na spletu in pogledal nekaj youtube razlag, vendar še vedno ne razumem. Ali lahko kdo to razloži na enostaven in pregleden način (kot idiotu, nepoznavalcu programskih jezikov ipd.)?
Vem, da ko naredimo tole:
Se rezervira pomnilnik na Stacku.
Ko naredimo tole je isto, samo se rezervira na Heapu:
Prebral sem, da je sklad precej majhen v primerjavi s kopico. Vendar ne razumem, za koliko celih števil, decimalnih števil ali nizov uporabimo eno ali drugo?
Skratka, če tabelo deklariram s 1000 ali več elementi bo sklada zmanjkalo in verjetno bo prišlo do stack overflowa. V bistvu, bi se moral sklad uporabljati samo znotraj funkcij, vendar sem na spletu našel kodo, ki naredi natanko to, da rezervira (deklaracija) "int tabela[100];" zunaj int main() funkcije. V bistvu znotraj ničesar.
Ne razumem.
Vem, da ko naredimo tole:
int tabela[100];
Se rezervira pomnilnik na Stacku.
Ko naredimo tole je isto, samo se rezervira na Heapu:
ptr = (int*) malloc(100 * sizeof(int));
Prebral sem, da je sklad precej majhen v primerjavi s kopico. Vendar ne razumem, za koliko celih števil, decimalnih števil ali nizov uporabimo eno ali drugo?
Skratka, če tabelo deklariram s 1000 ali več elementi bo sklada zmanjkalo in verjetno bo prišlo do stack overflowa. V bistvu, bi se moral sklad uporabljati samo znotraj funkcij, vendar sem na spletu našel kodo, ki naredi natanko to, da rezervira (deklaracija) "int tabela[100];" zunaj int main() funkcije. V bistvu znotraj ničesar.
Ne razumem.
Vesoljc ::
ce se ne motim je recimo na windows platformi v visual studio okolju, 1MB default stack size (c++ program). ce tvoj program to preseze, se zgodi tako kot si rekel stack overflow. na stack se nalozi tvoj program, in ko se izvaja, se stvari pushajo in popajo na stack. recimo da imas podfunkcijo, ki na zacetku definira int tabelo veliko 1000 elementov, se takrat ko se ta funkcija poklice, na stacku alocira 1000 * 4B ~ 4KB stacka. ko se funkcija zakljuci, se teh 4KB sprosti, sklad se zmanjsa. ce imas globalne spremenljivke (ala zunaj main funca) gre to pac tudi na stack (ko se program zazene).
heap je namenjen vecjim zadevam in takrat ko recimo vnaprej ne ves koliko res potrebujes, recimo ob pisanju programa ne ves ali bos rabil tabelo veliko 100 ali pa 100000 elementov. niti ni smotrno prevec. pac pocakas do takrat ko ves koliko potrebujes in takrat alociras toliko kot rabis. razlika je se to, da stack alokacije/de-alokacije delujejo avtomatsko, medtem ko stvari na heapu moras sam alocirat in de-alocirat (malloc, free).
heap je namenjen vecjim zadevam in takrat ko recimo vnaprej ne ves koliko res potrebujes, recimo ob pisanju programa ne ves ali bos rabil tabelo veliko 100 ali pa 100000 elementov. niti ni smotrno prevec. pac pocakas do takrat ko ves koliko potrebujes in takrat alociras toliko kot rabis. razlika je se to, da stack alokacije/de-alokacije delujejo avtomatsko, medtem ko stvari na heapu moras sam alocirat in de-alocirat (malloc, free).
Abnormal behavior of abnormal brain makes me normal...
secops ::
Razlika se najboljše vidi, ko pogledaš program z debuggerjem, recimo z GDBjem...
Načeloma imaš 3 možnosti pri spremenljivah, te lahko živijo na stacku, heapu in pa statične spremenljivke, ki živijo kar v posebnem segmentu binaryja in zato mora biti njihova velikost znana ob compailanju, odpri scompailan program recimo z Ghidra orodjem pa boš videl različne segmente (.data itd..).
Heap je omejen z RAMom tvojega PCa, ko bo heapa začelo zmanjkovati, ti bo operacijski sistem dodal nov del RAMA, da bo heapa vedno dovolj. Načeloma na heap postaviš velike spremenljivke oziroma take, katerih velikost določa nekdo drug (recimo uporabnik). Prostor na heapu rezerviraš z mallocom ali kakšno podobno komando. Potem pa pointer na ta prostor potiskaš naokoli. Samo na koncu ne pozabu sprostiti pomnilnika z free funkcijo in nastaviti pointerja na NULL, tako se izogneš neprijetnim situacijam kot sta recimo memory leak in use after free vulnarability.
Stack je fina zadeva za lokalne variable funkcije, preko njega se pošiljajo tudi argumenti pri klicih funkcij (to se lepo vidi v GDBju). Pazi edino to, da ko returnaš iz funkcije ven, se variable na stacku izgubijo, tudi če vrneš pointer nanj ven. V nadaljevanju se bo to polje v stacku prepisalo. Torej v tem primeru uporabi heap.
Če pa že ob pisanju programa veš kako velika bo spremenljivka, jo pa lahko pospraviš med statične spremenljivke. Taka spremenljivka se bo ohranila med klici funkcij, nerabiš jo mallocat, freejat, ker je že tam. Edino pazi na to, da njene velikosti ne moraš spremeniti drugače kot da popraviš v kodi in nanovo scompailaš.
Načeloma imaš 3 možnosti pri spremenljivah, te lahko živijo na stacku, heapu in pa statične spremenljivke, ki živijo kar v posebnem segmentu binaryja in zato mora biti njihova velikost znana ob compailanju, odpri scompailan program recimo z Ghidra orodjem pa boš videl različne segmente (.data itd..).
Heap je omejen z RAMom tvojega PCa, ko bo heapa začelo zmanjkovati, ti bo operacijski sistem dodal nov del RAMA, da bo heapa vedno dovolj. Načeloma na heap postaviš velike spremenljivke oziroma take, katerih velikost določa nekdo drug (recimo uporabnik). Prostor na heapu rezerviraš z mallocom ali kakšno podobno komando. Potem pa pointer na ta prostor potiskaš naokoli. Samo na koncu ne pozabu sprostiti pomnilnika z free funkcijo in nastaviti pointerja na NULL, tako se izogneš neprijetnim situacijam kot sta recimo memory leak in use after free vulnarability.
Stack je fina zadeva za lokalne variable funkcije, preko njega se pošiljajo tudi argumenti pri klicih funkcij (to se lepo vidi v GDBju). Pazi edino to, da ko returnaš iz funkcije ven, se variable na stacku izgubijo, tudi če vrneš pointer nanj ven. V nadaljevanju se bo to polje v stacku prepisalo. Torej v tem primeru uporabi heap.
Če pa že ob pisanju programa veš kako velika bo spremenljivka, jo pa lahko pospraviš med statične spremenljivke. Taka spremenljivka se bo ohranila med klici funkcij, nerabiš jo mallocat, freejat, ker je že tam. Edino pazi na to, da njene velikosti ne moraš spremeniti drugače kot da popraviš v kodi in nanovo scompailaš.
hbgqzR ::
Saj si ugotovil bistvene stvari, malo se prever alokacijo/dealokacijo na heapu, pa tvoja trzna vrednost naraste za 27,8% :-)
kuall ::
najprej je vse v heapu, ko pa se program izvaja in pride do ene funkcije naloži spremenljivke od te funckije v stack. če imaš pointer se naloži samo referenca, podatki na katerega kaže pointer pa še vedno ostanejo v heapu.
stack overflow se ponavadi dobi, ko delaš neskončno rekuzrijo in se spremenljivke kopičijo v stack in ne sprostijo, dokler ne požrejo celega mb stacka.
zadaj je vse RAM, samo razlika je kako so podatki strukturirani: v stacku je vse lepo zloženo za hiter acces, heap pa je fragmentiran.
ko se funkcija konča se iz stacka avtomatično pobrišejo vse njene spremenljivke in naredijo prostor za nove, zato ne rabiš delat npr free (nek integer).
vsak program ima funkcijo main, ta kliče funkcijo x, ta kliče funkcijo y itd. tako se gnezdijo funkcije in kopičijo na stack svoje spremenljivke v LIFO metodi (last in, first out).
ko debuggiraš program imaš call stack in lahko vidiš to vgnezdenost funkcij. vse spremenljivke teh funkcij so shranjene v stacku in njihove vrednosti lahko vidimo z debuggerjem, pointerji pa imajo dodatno še podatke v heapu.
zdej nisem ziher a vsi OSi uporabljajo stack arhitekturo? tu bi bilo treba še naštudirat kako točno deluje CPU, to je povezano. baje če ni rekurzije se da preživet tudi brez stacka, to mi še ni čist jasno.
stack overflow se ponavadi dobi, ko delaš neskončno rekuzrijo in se spremenljivke kopičijo v stack in ne sprostijo, dokler ne požrejo celega mb stacka.
zadaj je vse RAM, samo razlika je kako so podatki strukturirani: v stacku je vse lepo zloženo za hiter acces, heap pa je fragmentiran.
ko se funkcija konča se iz stacka avtomatično pobrišejo vse njene spremenljivke in naredijo prostor za nove, zato ne rabiš delat npr free (nek integer).
vsak program ima funkcijo main, ta kliče funkcijo x, ta kliče funkcijo y itd. tako se gnezdijo funkcije in kopičijo na stack svoje spremenljivke v LIFO metodi (last in, first out).
ko debuggiraš program imaš call stack in lahko vidiš to vgnezdenost funkcij. vse spremenljivke teh funkcij so shranjene v stacku in njihove vrednosti lahko vidimo z debuggerjem, pointerji pa imajo dodatno še podatke v heapu.
zdej nisem ziher a vsi OSi uporabljajo stack arhitekturo? tu bi bilo treba še naštudirat kako točno deluje CPU, to je povezano. baje če ni rekurzije se da preživet tudi brez stacka, to mi še ni čist jasno.
Zgodovina sprememb…
- spremenilo: kuall ()
mr_chai ::
Splača se mal iz assembler perspektive stvari pogledat, ker konec koncev se vmes tvoj C-jevski program skompajla v assembler kodo.
Za en program se torej vzame del pomnilnika in se ga razreže na naslednje kose:
- Text ali Code segment, kjer dejansko počiva tvoja koda , ta del pomnilnika je read only
- Data, ta segment pomnilnika vsebuje inicializirane spremenljivke in konstante. Sprva so lahko te spremenljivke, katerih velikost in vrednost je vnaprej znana, zapisane samo v Code/Text segmentu, a se ob zagonu programa prepišejo v Data segment.
- BSS segment, tu so vse spremenljivke, ki so samo definirane, ne pa inicializirane
- Heap segment, tu se hrani vse dinamično alocirane spremenljivke /podatke. Za podatke, katere velikosti ne moreš vedeti pred zagonom programa. Npr, uporabnik programa bo nekje hranil kontakte, vsak uporabnik ima pa različno število kontaktov..
- Stack segment. Tu se hranijo vsi argumenti pri vhodu v funkcijo in tudi return naslov iz kje je bila funnkcija poklicana.
Koncept spremenljivke v asemblerju v bistvu ne obstaja tako kot recimo v C-ju. Nekam pa se mora ta spremenljivka oz. podatek shraniti. Al je to na stack, na heap, v data segment, bss al pa celo samo v register.
Jaz ti svetujem, da se naučiš malo osnove assemblerja, pa ti bodo stvari hitro bolj jasne.
Za en program se torej vzame del pomnilnika in se ga razreže na naslednje kose:
- Text ali Code segment, kjer dejansko počiva tvoja koda , ta del pomnilnika je read only
- Data, ta segment pomnilnika vsebuje inicializirane spremenljivke in konstante. Sprva so lahko te spremenljivke, katerih velikost in vrednost je vnaprej znana, zapisane samo v Code/Text segmentu, a se ob zagonu programa prepišejo v Data segment.
- BSS segment, tu so vse spremenljivke, ki so samo definirane, ne pa inicializirane
- Heap segment, tu se hrani vse dinamično alocirane spremenljivke /podatke. Za podatke, katere velikosti ne moreš vedeti pred zagonom programa. Npr, uporabnik programa bo nekje hranil kontakte, vsak uporabnik ima pa različno število kontaktov..
- Stack segment. Tu se hranijo vsi argumenti pri vhodu v funkcijo in tudi return naslov iz kje je bila funnkcija poklicana.
Koncept spremenljivke v asemblerju v bistvu ne obstaja tako kot recimo v C-ju. Nekam pa se mora ta spremenljivka oz. podatek shraniti. Al je to na stack, na heap, v data segment, bss al pa celo samo v register.
Jaz ti svetujem, da se naučiš malo osnove assemblerja, pa ti bodo stvari hitro bolj jasne.
kow ::
Jaz sem začel programirati v Pythonu in Javi in v bistvu sedaj ne razumem dinamične alokacije pomnilnika v C-ju. Prebral sem mnogo tutorialov na spletu in pogledal nekaj youtube razlag, vendar še vedno ne razumem. Ali lahko kdo to razloži na enostaven in pregleden način (kot idiotu, nepoznavalcu programskih jezikov ipd.)?
Ne razumem.
Postavil si zelo tezko vprasanje. Da ne razumes, je popolnoma razumljivo za zacetnika.
Vredno je zelo pocasi prebrati:
Stack-based memory allocation @ Wikipedia
kuall ::
kow, on hoče domačo razlago ne fakin wikipedia članka, to si lahko sam najde.
za to bi celo znal biti slo tech koristen, za domačo slovensko razlago. žal je le redkokdo sposoben razložiti, najbrž iz strahu, da bi napisal kake neumnosti in se osramotil. :D
za to bi celo znal biti slo tech koristen, za domačo slovensko razlago. žal je le redkokdo sposoben razložiti, najbrž iz strahu, da bi napisal kake neumnosti in se osramotil. :D
NiDobraCena ::
kow, on hoče domačo razlago ne fakin wikipedia članka, to si lahko sam najde.
za to bi celo znal biti slo tech koristen, za domačo slovensko razlago. žal je le redkokdo sposoben razložiti, najbrž iz strahu, da bi napisal kake neumnosti in se osramotil. :D
No, gospod STROKOVNJAK! A bi Vi razložili razliko med dinamično in statično alokacijo, ali je tema preneumna za vas?
kow ::
kow, on hoče domačo razlago ne fakin wikipedia članka, to si lahko sam najde.
za to bi celo znal biti slo tech koristen, za domačo slovensko razlago. žal je le redkokdo sposoben razložiti, najbrž iz strahu, da bi napisal kake neumnosti in se osramotil. :D
Drzi. Samo 4 so podali razlago, pa noben ni znal enostavno razloziti. Ker potrebujes globoko razumevanje podrocja, da znas razloziti. Sam ne znam oz. bi si moral vzeti veliko casa.
Zgodovina sprememb…
- spremenil: kow ()
napsy ::
OP, na Linuxu je stack size ~ 8MB (ulimit -s), za Visual Sudio interneti pravijo 1MB.
Pri linuxu je tudi tako, da ima vsak thread, ki ga na novo kreiras 8 MB stack size, ki se potem dalje uporablja pri funkcijskih klicih.
Naceloma se stack uporablja za res manjse alokacije (recimo 8kb), seveda pa ce ves koliko stacka pokuri tvoj program, pa tut lahko kamot tistih 8 MB uporabis, ni pa priporocljivo, ker potem lahko hitro prides do stack overflow, kakor si omenil.
Pri linuxu je tudi tako, da ima vsak thread, ki ga na novo kreiras 8 MB stack size, ki se potem dalje uporablja pri funkcijskih klicih.
Naceloma se stack uporablja za res manjse alokacije (recimo 8kb), seveda pa ce ves koliko stacka pokuri tvoj program, pa tut lahko kamot tistih 8 MB uporabis, ni pa priporocljivo, ker potem lahko hitro prides do stack overflow, kakor si omenil.
"If you die, you die. But when you live you live. There is no time to waste."
Zgodovina sprememb…
- spremenil: napsy ()
3p ::
najprej je vse v heapu, ko pa se program izvaja in pride do ene funkcije naloži spremenljivke od te funckije v stack. če imaš pointer se naloži samo referenca, podatki na katerega kaže pointer pa še vedno ostanejo v heapu.
To, da je najprej vse na "heapu" (aka kopici), ne drži. Lokalnih spremenljivk do vstopa v funkcijo sploh ni.
---
Kar se originalnega vprašanja tiče, se meni zdi bistvena razlika v življenjski dobi spremenljivk. Lokalne spremenljivke po izstopu iz funkcije izginejo, podatke na kopici pa moraš v Cju sprosititi "ročno", kar lahko narediš kadarkoli. Slednje pa je en način, da podatki preživijo izhod iz funkcije.
blay44 ::
Čist tko po kmečk.
Ko kličeš funkcijo, se parametri prenesejo na sklad in od tu se posredujejo funkciji.
Pa še prekinitve, itd...
Sklad je omejen in pri majhnih mlinčkih zlahka pride do prelivanja rama.
Heap je pa običajni ram, ki ostane po naložitvi programa, določitvi velikosti steka in je rezerviran za, pač, določeno spremenljivko. Odvisno od OSja,
Načeloma je stvar varnejša. Vsaj jest tko razumem.
Ko kličeš funkcijo, se parametri prenesejo na sklad in od tu se posredujejo funkciji.
Pa še prekinitve, itd...
Sklad je omejen in pri majhnih mlinčkih zlahka pride do prelivanja rama.
Heap je pa običajni ram, ki ostane po naložitvi programa, določitvi velikosti steka in je rezerviran za, pač, določeno spremenljivko. Odvisno od OSja,
Načeloma je stvar varnejša. Vsaj jest tko razumem.
kuall ::
do stackoverflow pride v praksi samo, če ima program buge in skor vedno je to infinite rekuzrzija. tak da stackoverflow bugi so izi! če vidiš stackoverflow napako si lahko ziher, da jo boš hitro rešil za razliko od kakih mnogo bolj zajebanih bugov.
WhiteAngel ::
OP: Izvoren razlog, zakaj imamo stack, je hitrost. Stack je mnogo hitrejši zaradi vseh vrst predpomnilnikov, push in pop sta celo *strojna* ukaza v procesorjih (shranita/naložita vsebino zadnjega elementa na stacku in zmanjšata/povečata stack pointer), zato prevajalniki (med drugim) uporabljajo stack za podajanje argumentov funkcijam. Lahko bi dostopal do vsake spremenljivke tudi z load/store strojnim ukazom, ampak bi za to rabil več ukazov, pa še predpomnilnik bi imel zelo verjetno več zgrešitev. Slaba stran stacka pa je, da mora biti zvezen v navideznem pomnilniku (za razliko od malloca, ki ti pač vrže nek naslov segmenta na heapu, ki je prost), zato ti ga mora OS "na pamet" alocirati in lahko ti ga zmanjka, če npr. preveč rekurzivnih klicev narediš.
Python interpretira sproti kodo in dela samo s heapom, če ne uporabljaš cpythona ali podobnih čarovnij.
Python interpretira sproti kodo in dela samo s heapom, če ne uporabljaš cpythona ali podobnih čarovnij.
Zgodovina sprememb…
- spremenil: WhiteAngel ()
WhiteAngel ::
Zato python nima težav z globokimi rekurzijami, saj vse funkcijske okvirje (spremenljivke z življenjsko dobo enega klica funkcije) zmeče na heap.
Aja, spraševal si glede statične/dinamične alokacije. Funkcijski okvir kamot izračuna prevajalnik. npr. Imaš 2 inta kot parametra, v funkciji pa še 3 inte in 2 shorta, in to nanese 40+4 bytov. To je ta statična alokacija. Če pa upprabnik vnese neko število x, ti moraš pa alocirati polje z x elementi, pa tega prevajalnik ne more statično alocirati. Ti kločeš malloc za teh x elementov na heapu, na stack bo pa verjetno prevajalnik dal samo kazalec na prvi element, to je 8 bajtov.
Aja, spraševal si glede statične/dinamične alokacije. Funkcijski okvir kamot izračuna prevajalnik. npr. Imaš 2 inta kot parametra, v funkciji pa še 3 inte in 2 shorta, in to nanese 40+4 bytov. To je ta statična alokacija. Če pa upprabnik vnese neko število x, ti moraš pa alocirati polje z x elementi, pa tega prevajalnik ne more statično alocirati. Ti kločeš malloc za teh x elementov na heapu, na stack bo pa verjetno prevajalnik dal samo kazalec na prvi element, to je 8 bajtov.
Zgodovina sprememb…
- spremenil: WhiteAngel ()
mr_chai ::
Ja, stack je vedno "hot" ket se stvari na stacku keširajo tudi v registrih. Tudi pomemben podatek je, da je lifetam objektov na stacku zelo kratek.
Ampak, tako kot sem rekel, OP naj si raje pogleda malo osnove assemblerja. In mu bo malo bolj jasno kako stroj deluje.
Ker razumeti to vprašanje samo na nivoju C-ja ni mogoče.
Ampak, tako kot sem rekel, OP naj si raje pogleda malo osnove assemblerja. In mu bo malo bolj jasno kako stroj deluje.
Ker razumeti to vprašanje samo na nivoju C-ja ni mogoče.
Zgodovina sprememb…
- spremenilo: mr_chai ()
Spura ::
Stacka lahko zmanjka tudi brez neskoncne rekurzije, ga mi je ze veckrat. Vsaki funkciji compiler izracuna velikost stack framea, ko jo klices se premakne stack pointer za to vrednost in notri skopira parametre od funkcije (je pa tam tudi prostor za vse lokalne spremenljivke. Pri trenutno izvajajoci niti je stack pointer v enem registru in je zelo hitro samo povecat to vrednost. Ko se nit zamenja se iz tega registra vrednost shrani. V tipicne OSu ima vsaka nit dva stacka, enega v kernelu in enega v user spaceu.
kow ::
Izgubljate se v podrobnostih. Rekurzija je za OP vprasanje, popolnoma nepomembna. Cakamo sicer na OP, da pride s kaksnim nadaljnim vprasanjem.
Zgodovina sprememb…
- spremenil: kow ()
marjan_h ::
Vesoljc in WhiteAngel sta verjetno najbolj preprosto povedala, npr. Vesoljc je napisal tole:
To sem dejansko testiral:
In to deluje. Kljub temu, da ne vemo za koliko elementov potrebujemo tabelo, se stvar prevede in lahko vnesem poljuben integer. Ter tako rezerviramo na stacku 100, 1000 ali koliko pač prenese (1MB windows, Linux 8MB), celih števil. Kot ste nekateri napisali.
Nekateri ste pisali tudi, da naj si pogledam Assembler. Nekaj osnov imam iz zbirnega jezika. Vendar tam sem samo postavljal registre na neko vrednost, ali pa delal logične operacije z biti. Vem, kaj je register, vem kaj je sklad, vem kaj je kopica (to ni podatkovna struktura) v mojem primeru, gre samo za košček RAMa.
Vidim, da je tudi veliko zanimanja za ta topic, glede na število klikov na temo , kar pomeni, da tudi tisti ki programirajo v C/C++ jih zanima kaj točno počne PC, ko kliče malloc.
Bo kdo komentiral mojo kodo, ali sem jaz narobe razumel Vesoljca glede tistega citata? Uporabljam gcc prevajalnik.
ko recimo vnaprej ne ves koliko res potrebujes, recimo ob pisanju programa ne ves ali bos rabil tabelo veliko 100 ali pa 100000 elementov.
To sem dejansko testiral:
#include <stdio.h> #include <stdlib.h> int main() { int number; printf("Enter an integer: "); scanf("%d", &number); int array[number]; array[0] = 42; array[1] = 2; array[2] = 3; printf("\n %d", array[0]); return 0; }
In to deluje. Kljub temu, da ne vemo za koliko elementov potrebujemo tabelo, se stvar prevede in lahko vnesem poljuben integer. Ter tako rezerviramo na stacku 100, 1000 ali koliko pač prenese (1MB windows, Linux 8MB), celih števil. Kot ste nekateri napisali.
Nekateri ste pisali tudi, da naj si pogledam Assembler. Nekaj osnov imam iz zbirnega jezika. Vendar tam sem samo postavljal registre na neko vrednost, ali pa delal logične operacije z biti. Vem, kaj je register, vem kaj je sklad, vem kaj je kopica (to ni podatkovna struktura) v mojem primeru, gre samo za košček RAMa.
Vidim, da je tudi veliko zanimanja za ta topic, glede na število klikov na temo , kar pomeni, da tudi tisti ki programirajo v C/C++ jih zanima kaj točno počne PC, ko kliče malloc.
Bo kdo komentiral mojo kodo, ali sem jaz narobe razumel Vesoljca glede tistega citata? Uporabljam gcc prevajalnik.
kow ::
Tvoj primer ni smiseln. Ker nisi povozil nobene sosednje kode. Lahko naredis stack overflow, ne da bi program crashiral. Tvoj itak, razen izpisa nic ne pocne, in takoj konca izvajanje.
Ker ima stack tudi return naslov, mozno da sem tukaj tudi zgresil - malo mi ze pesa spomin kako tocno se stvari zlagajo na stacku. Ampak poanta ostane.
Mislim, da prelahkotno operiras z besedami. Recimo "rezerviramo na stacku" - v resnici se samo premakne pointer za X bajtov, ne zgodi se nobena rezervacija v neki entiteti, ki operira s polnilnikom.
Pri heapu je drugace. Dejansko se rezervira (memory allocation, i.e. malloc) del pomnilnika, ki je neodvisen od lokalnega izvajanja.
Ker ima stack tudi return naslov, mozno da sem tukaj tudi zgresil - malo mi ze pesa spomin kako tocno se stvari zlagajo na stacku. Ampak poanta ostane.
Mislim, da prelahkotno operiras z besedami. Recimo "rezerviramo na stacku" - v resnici se samo premakne pointer za X bajtov, ne zgodi se nobena rezervacija v neki entiteti, ki operira s polnilnikom.
Pri heapu je drugace. Dejansko se rezervira (memory allocation, i.e. malloc) del pomnilnika, ki je neodvisen od lokalnega izvajanja.
Zgodovina sprememb…
- spremenil: kow ()
marjan_h ::
Hm, bom še počakal Vesoljca.
Vendar kaj jaz želim slišati je izkušnja: Sem programer, ki programira v C 10+ let in, ko imam problem X rezerviram dinamični pomnilnik zaradi A in ko imam problem Y uporabim kar stack zaradi B. Ja in kow ima prav, stack se ne rezervira, v bistvu se samo pointer premakne, ko se pusha gor ali popa.
Vendar kaj jaz želim slišati je izkušnja: Sem programer, ki programira v C 10+ let in, ko imam problem X rezerviram dinamični pomnilnik zaradi A in ko imam problem Y uporabim kar stack zaradi B. Ja in kow ima prav, stack se ne rezervira, v bistvu se samo pointer premakne, ko se pusha gor ali popa.
kow ::
Ja in kow ima prav, stack se ne rezervira, v bistvu se samo pointer premakne, ko se pusha gor ali popa.
No, nisem povedal pravilno. Obstajati mora tudi naslov zacetka arraya. Drugace "array[0] = 42;" ne bi vedel kam zapisati.
Torej, premakni pointer za X bajtov on naslova Y. Dokler smo znotraj funkcije, se naslov Y ne sme prepisati z drugo vrednostjo.
Zgodovina sprememb…
- spremenil: kow ()
marjan_h ::
Ko rabis nekaj kratkorocno (lokalno), pa ves, da ne more biti veliko, uporabis stack.
Kul. Še kdo?
Verjetno se ta malloc uporablja bolj v game engine, OS, DBMS itd? Ker te krajši programi, kot sem ga jaz napisal, pač delujejo tudi samo s stackom.
Ha, verjetno vi, ki programirate v C-ju, probate narediti s stackom int tabela[1000], in če dobite stackoverflow, naredite isto samo s heapom. Verjetno je to vse in jaz preveč kompliciram...
WhiteAngel ::
Vsak netrivialen program, ima recimo kaksen cache itd. Tako, da se malloc vedno uporablja.
^^ to.
Tega, kar si napisal
int array[number];
se ne počne. Ne vem, kakšne so zadnje specifikacije od C standarda, ampak hočeš tole, če ne veš, kakšen bo number:
int array[] = malloc(sizeof(int)*number);
kow ::
Da. Marjan tvoj tesni program, bi moral tudi kaj ZAPISATI za sledeco vrstico: int array[number];
Pa ne na zacetek arraya, kot si pisal ti.
Dodaj samo int z = 15; ter prevedi in pozeni (vnesi visoki number, recimo milijarda). Za vsak slucaj tudi izpisi to stevilko na zaslon, da ne bo kompiler pameten in bo odvrgel neuporabljeno vrstico.
Pa ne na zacetek arraya, kot si pisal ti.
Dodaj samo int z = 15; ter prevedi in pozeni (vnesi visoki number, recimo milijarda). Za vsak slucaj tudi izpisi to stevilko na zaslon, da ne bo kompiler pameten in bo odvrgel neuporabljeno vrstico.
Zgodovina sprememb…
- spremenil: kow ()
kuall ::
Stacka ti ne uporabljaš ampak ga funkcije. Ti uporabljaš fixed size arr znotraj funkcij, kar se prevede v uporabo stacka. Dinamičen array (heap) je v praksi uporaben, fixed sized pa samo v kakih testih in učbenikih, torej nerealen peace of sheet.
kuall ::
Če imaš npr array s črkami abecede ali imeni mesecev to daš na stack ampak skor bolj smiselno naredit global const array iz tega (tako se dela v praksi), kar pa ne gre na stack ampak v data segment.
Ahim ::
Ko rabis nekaj kratkorocno (lokalno), pa ves, da ne more biti veliko, uporabis stack.
Kul. Še kdo?
Verjetno se ta malloc uporablja bolj v game engine, OS, DBMS itd? Ker te krajši programi, kot sem ga jaz napisal, pač delujejo tudi samo s stackom.
Ha, verjetno vi, ki programirate v C-ju, probate narediti s stackom int tabela[1000], in če dobite stackoverflow, naredite isto samo s heapom. Verjetno je to vse in jaz preveč kompliciram...
Saj si ze zdavnaj dobil pravilen odgovor, pa se parkrat so ga ponovili z malo drugacnimi besedami, in en je bil sploh zelo datajlen (od uporabnika mr_chai). A si res tako trdobucen, da ga rabis se vsaj enkrat napisanega?
Nehaj komplicirat - za stavri, ki jih bos ti pocel, je preprosto pravilo da ce (1) vnaprej ne ves koliko pomnilnika bos porabil ali pa je (2) kolicina, ki bi jo porabil, relativno velika (npr. da vnaprej ves da bos potreboval 10 MB, na voljo je pa samo 8 MB), potem klici malloc() in free(), v vseh ostalih primerih pa lepo definiraj spremenljivko izbranega tipa, jo normalno uporabljaj in prepusti handlanje prevajalniku.
Debate o rekurzivnih klicih, ki zapolnijo stack, so pa tako smiselne kot o klicanju malloc() tolikokrat oz. za toliko RAMa, kot ga skupaj ni na voljo. Kot vsaka druga naprava tudi racunalnik ne dela pravilno, ce dobi nesmiselne ukaze, samo to je vsem jasno za avto ali stedilnik, zacuda pa rabimo eno stran debate o stack overflowih, povzrocenih s preglobko rekurzijo ...
marjan_h ::
Sem se malo igral:
Ko vnesem 100 000 ali 1 000 000. Stvar deluje. Vendar pa neha delovati pri okoli 2 000 000, vrne sledečo napako: "Napaka segmentacije (izpis jedra)".
In ker uporabljam Linux ter rezerviram cela števila (4 B), je to ravno okoli 8 MB pri 2 000 000, kar pomeni, da se vse ujema.
#include <stdio.h> #include <stdlib.h> int main() { int number; printf("Enter an integer: "); scanf("%d", &number); int array[number]; int z = 15; array[0] = 42; array[1] = 2; array[2] = 3; printf("\n %d", array[0]); printf("\n %d", z); printf("\n %d", number); return 0; }
Ko vnesem 100 000 ali 1 000 000. Stvar deluje. Vendar pa neha delovati pri okoli 2 000 000, vrne sledečo napako: "Napaka segmentacije (izpis jedra)".
In ker uporabljam Linux ter rezerviram cela števila (4 B), je to ravno okoli 8 MB pri 2 000 000, kar pomeni, da se vse ujema.
kuall ::
po moje c++ prevede tele oglate oklepaje v kak malloc. nisem c++ stručnjak samo vem, da se da tudi določene operaterje overloadat pa take fore.
murrieta ::
Tole si preberite, pa vam bo zelo veliko jasno. Ne pravim, da kodirajte v assemblerju, vzamite kot arhitekturne osnove, ko jih enkrat poznas, ni C noben bavbav vec.
https://www.ic.unicamp.br/~pannain/mc40...
Wtf... ne nic jih ne prevede v malloc (heap), alocira na stacku (alloca).
Da, ker je velikost stacka definirana ob casu compajliranja in ti si z 2000000 presegel defaultno vrednost. Ali bos uporabil na gccju -Wl,--stack,*size*, bos klical getrlimit ali pa bos nehal uporabljati stack za take neumnosti in bos uporabil heap, kar bi naredila vecina ljudi. Ko se ze ravno na C spravljas, ti dam eno veliko pomoc, memorija v Cju ni nek tip, ampak je tip samo kako predstaviti memorijo. In se ena zlata: pointer je memorija, kjer je napisan naslov memorije, kjer so podatki. Brez * se sprasujes po naslovu, z zvezdico po podatkih.
Stacka in heapa ti pa ne mislim razlagat, imas na netu toliko sranja spisanega okrog tega, da ne bom tratil casa, pac BERI, namesto iskanja bliznjic.
https://www.ic.unicamp.br/~pannain/mc40...
po moje c++ prevede tele oglate oklepaje v kak malloc. nisem c++ stručnjak samo vem, da se da tudi določene operaterje overloadat pa take fore.
Wtf... ne nic jih ne prevede v malloc (heap), alocira na stacku (alloca).
Ko vnesem 100 000 ali 1 000 000. Stvar deluje. Vendar pa neha delovati pri okoli 2 000 000, vrne sledečo napako: "Napaka segmentacije (izpis jedra)".
Da, ker je velikost stacka definirana ob casu compajliranja in ti si z 2000000 presegel defaultno vrednost. Ali bos uporabil na gccju -Wl,--stack,*size*, bos klical getrlimit ali pa bos nehal uporabljati stack za take neumnosti in bos uporabil heap, kar bi naredila vecina ljudi. Ko se ze ravno na C spravljas, ti dam eno veliko pomoc, memorija v Cju ni nek tip, ampak je tip samo kako predstaviti memorijo. In se ena zlata: pointer je memorija, kjer je napisan naslov memorije, kjer so podatki. Brez * se sprasujes po naslovu, z zvezdico po podatkih.
Stacka in heapa ti pa ne mislim razlagat, imas na netu toliko sranja spisanega okrog tega, da ne bom tratil casa, pac BERI, namesto iskanja bliznjic.
Zgodovina sprememb…
- spremenilo: murrieta ()
marjan_h ::
Glejte jaz ne iščem bližnjic. Sem napisal, da sem prebral večino tutorial na spletu in nisem vsega razumel. V šoli ti tudi ne povejo, preberite si knjigo ARS od Kodeka in potem boš razumel. Jaz sem generacija, ko smo se učili Python in znam npr. uporabljati beautifulSoup, ampak to ti ne koristi pri Malloc in free ker o tem ne rabiš vedeti.
Če ste pozorni brali moja vprašanja nisem vprašal kaj je Malloc, dinamična aloikacija, heap, stack... Ker sem to izvedel iz tutorialov. Jaz sem napisal preprost program za testiranje in je delal. In nisem razumel zakaj nekaj kar dela, zakaj to ne bi smel uporabljati.
Mislil sem, da bo nekdo z izkušnjami povedal, ja ko sem programiral kernel od OS, je bil primer da sem poskušal X, in ni delovalo zato sem moral uporabiti Malloc.
To je vse. V bistvu imam še eno vprašanje glede pointerjev, ampak se nanaša na en algoritem in nima veze s temo. Tako, da bom to vprašal v drugi temi.
V bistvu je Vesoljc v tej temi najbolj enostavno povedal. Nekateri so pa napisali odgovore na višjem nivoju, za katere potrebuješ še dodatno predznanje.
Če ste pozorni brali moja vprašanja nisem vprašal kaj je Malloc, dinamična aloikacija, heap, stack... Ker sem to izvedel iz tutorialov. Jaz sem napisal preprost program za testiranje in je delal. In nisem razumel zakaj nekaj kar dela, zakaj to ne bi smel uporabljati.
Mislil sem, da bo nekdo z izkušnjami povedal, ja ko sem programiral kernel od OS, je bil primer da sem poskušal X, in ni delovalo zato sem moral uporabiti Malloc.
To je vse. V bistvu imam še eno vprašanje glede pointerjev, ampak se nanaša na en algoritem in nima veze s temo. Tako, da bom to vprašal v drugi temi.
V bistvu je Vesoljc v tej temi najbolj enostavno povedal. Nekateri so pa napisali odgovore na višjem nivoju, za katere potrebuješ še dodatno predznanje.
Vesoljc ::
:)
zivimo v svetu luksuza, desktop aplikacije imajo "ogromno" pomnilnika na voljo. naj si bo 1MB ali 8MB stacka, za solske primere in ucenje "osnov" je to v 99% cisto dovolj. kako bos iteracijo cez polje z for zanko nekoga naucil, ce mu bos notri vrinil se pointerje? pac nardis polje na stacku, veliko ali 100 ali pa 100.000 in to je to. vse spila.
ne gre za to da tega ne smes tako delat, pac lahko, compiler/linker to dovolita, samo zavedat se moras omejitev. pa tudi heap ni nek bav bav, ze nek semi primitiven tool za obdelavo slik ne more laufat na stacku, ce rabi za obdelavo imet celotno sliko v pomnilniku (ce obdelujes ikone ajdi :) ), takrat moras uporabit heap, druge nimas.
zivimo v svetu luksuza, desktop aplikacije imajo "ogromno" pomnilnika na voljo. naj si bo 1MB ali 8MB stacka, za solske primere in ucenje "osnov" je to v 99% cisto dovolj. kako bos iteracijo cez polje z for zanko nekoga naucil, ce mu bos notri vrinil se pointerje? pac nardis polje na stacku, veliko ali 100 ali pa 100.000 in to je to. vse spila.
ne gre za to da tega ne smes tako delat, pac lahko, compiler/linker to dovolita, samo zavedat se moras omejitev. pa tudi heap ni nek bav bav, ze nek semi primitiven tool za obdelavo slik ne more laufat na stacku, ce rabi za obdelavo imet celotno sliko v pomnilniku (ce obdelujes ikone ajdi :) ), takrat moras uporabit heap, druge nimas.
Abnormal behavior of abnormal brain makes me normal...
Vredno ogleda ...
Tema | Ogledi | Zadnje sporočilo | |
---|---|---|---|
Tema | Ogledi | Zadnje sporočilo | |
» | [C++] Ali je mogoče?Oddelek: Programiranje | 1648 (1124) | Ciklamen |
» | Java program (strani: 1 2 )Oddelek: Programiranje | 8598 (7747) | kunigunda |
» | [C] struct in int[] (strani: 1 2 )Oddelek: Programiranje | 7354 (6427) | MrBrdo |
» | [C++] Stack corrupted? Memory allocation f****p?Oddelek: Programiranje | 1377 (1144) | BigWhale |
» | kazalci, funkcije ipd...Oddelek: Programiranje | 1317 (1248) | OwcA |