[Megoldva] C fuggvenyen belul memoriafoglalas

Sziasztok,

Azt gondoltam ez mukodik:


#include <stdlib.h>
#include <string.h>

void stralloc(char *str)
{
	str = malloc(10);
	strcpy(str, "Hello");
}

int main(void)
{
	char *str;
	stralloc(str);
	return 0;
}

..de nem. Viszont hogy lehet?

/sza2

Szerk.: Megoldva (es talan mar ertem is:-)

Hozzászólások

passed by value
.. (char **str) { *str = malloc(10); strcpy(*str, .. stralloc(&str); ..

Ertem, amit irsz, csak azt nem ertem, miert van igy. Az en agyamban ez van:

Adott egy valtozo, ami jelen esetben legyen *x, egy pointer. Merete mondjuk 32bites cimzes eseten 4byte. Ha azt mondom, *x = NULL akkor arra (azokra) a cim(ek)re ahol ez a valtozo van (tegyuk fel 0x00001234-0x00001237), beirodik 0x00000000, es mostantol ez lesz az x pointer.

Azutan a malloc()-kal foglalunk egy keves memoriat, a visszateresi erteke pedig szinten egy 32bites ertek, az a cim, ahol jo esetben talaltunk eleg egybefuggo memoriat, legyen 0x12345678.

Amikor azt mondom, x = malloc(N), ez az ertek felulirja a 0x00001234-0x00001237 cimeken levo erteket. Innentol kezdve, a x azt mondja meg, hol kezdodik a memoria terulet, ahova irhatok.

Azt nem ertem, miert kell ehhez a fuggveny hivasa elott tudni, hogy hol a szabad teruletem?

/sza2

Programozo szabaly #1: Az, hogy a te agyadban mi van, tokmindegy. A gep azt csinalja, amira utasitottad, nem azt, amire gondoltal.

Nagyjabol ugy van, ahogy leirtad, de javaslom, azert fusd at a C konyv vonatkozo reszeit ujra, hogy a szakzsargonnal tisztaban legyel.

Amiben hibadzol, az az, hogy fuggvenyhivas is van a kepben. A pointer, mint valtozo, ertek szerint adodik at (hogy mire mutat, az itt most mellekes - a pointer, mint valtozo maga ertek szerint adodik at. Ezert amikor a malloc() visszateresi erteket beleirod a valtozoba, az ott, a fuggvenyen belul megkapja az erteket, de amikor visszater a fuggveny, felszabadul a stack (mivel parameterek es helyi valtozok a stack-en kapnak helyet), es a hivasi helyen ujra a korabbi erteket kapja.

Ez most igy bonyi, de olvass utana, hogy muxik.

+1, csak kiegészítésnek:

@sza2king:

valszeg az zavar meg, hogy a függvénynek átadod a main-ben lévő lokális pointered értékét, ez a stack-en jön létre, majd ezt felülírod a függvényen belül a malloc-tól visszakapott értékkel, még mindig a stack-en. majd ahogy írták, ez visszatérés után felszabadul.

tehát ahogy már többen leírták, a pointer címének (mint érték) a címét kell átadnod, így ez a main lokális változójának memória részére fog mutatni, és ezt a malloc által visszaadott értékkel felülírhatod, ilyenkor már valóban az eredeti main lokális változójának a memória részébe írod vissza.

ami itt zavaró lehet, hogy a pointerek értéke is egy cím, mely további memória rész értékére mutathat.

megj.: motorolán lehetett assembly-ben jó kis indirekt címzéseket csinálni (ha jól rémlik, 68020 és attól felfelé volt bonyolultabb extra címzés mód is), na ott is volt olyan, hogy meg kellett állni tanárúr egy kicsit elgondolkodni :)

"Az, hogy a te agyadban mi van, tokmindegy. A gep azt csinalja, amira utasitottad, nem azt, amire gondoltal."
Ok, ez azert meg megvan :-) BTW, azert iram ide, hogy korrigalodjon az elkepzelesem, hiszen nem ugy volt ahogy en gondoltam, es ezt a program is bizonyitotta...

Mostmar viszont megertettem (legalabbis azt hiszem:-), s bar emlekeztem ra, hogy a lokalis valtozok a stack-en keresztul adodnak at, szukseg volt a magyarazatokra, amit koszonok is mindenkinek.

Annyira nem is bonyolult, csak vegig kellett gondolni.

Ja, raadasul mukodik is:-)

/sza2

szerintem meg ez működik.
igaz, nem csinál semmit, de végülis azt se értem, hogy mit szerettél volna...

Na ja működik a függvényen belül, csak éppen nem tudja ezen a módon visszadani a pointert. Mert az átadott változó pont úgy müködik, mint egy blokkra lokális dinamikus változó. Ha a kérdéses értéket (ebben az esetben az inicializált pointert) a paraméter szignatúrán keresztül akarod visszadani, akkor annak a címét add át, tehát a pointer címét.

Aztán a függvény belsejében mehet az indirekció.
Röviden ennyi.

igy az sem igaz, hogy nem csinal semmit, hiszen a kod vegrehajtodik

a fenti kódban teljesen mindegy, hogy a függvényből visszakerül-e a lefoglalt pointer a mainbe vagy sem, mivel a main se használja semmire se. tök mindegy, hogy melyik függvény dobja el.

egyébként erre találták ki alapvetően a visszatérési értéket.


char *stralloc()
{
char *str = malloc(10);
if (str != NULL) strcpy(str, "hello");
return str;
}

elvileg lehet úgy is, ahogy mások mutatták (pointer a pointerre átadásával), de ha nem muszáj (= lehet máshogy is), akkor azt inkább nem használjuk.

"main se használja semmire se"

Ez leginkabb azert lehet, mert nem akartam idemasolni az egesz programot, csak egy zanzasitott valtozatott, arrol a reszrol amit nem ertettem.

"main se használja semmire se"

Lasd fentebb. Van visszateresi ertek, csak mar foglalt masra.

Szoval a fenti program, csak a problemam bemutatasara szuletett, nem igy, ebben a formaban szerettem volna hasznalni:-)

/sza2

BTW, ezt a mulattsagot tombok tombjevel kellene eljatszanom, csak egyszerusitettem egy kicsit. Szoval a vegen majd valami int fuggveny(char *a, char* b, char ***c, int d, int e) lesz belole, csak a char *** mar eleg undorito...

Ennek semmi koze a C++-hoz. Siman jo a ***, ha tudod, mit csinalsz. Ez csak egy magasabb foku cimzes. Nyilvan csak ugy van ertelme, ha 3 masik parameterben atadod az egyes indexek ertelmezesi tartomanyat. Amugy ennel sokkal szebb megoldas a sima egyszeres pointer, es dope vector hasznalata.

Lenyeg a lenyeg, amit akartam haromcsillagos megoldas lett, es mukodik. A valodi programban valtozo hosszusagu, de 0 terminalt szovegek tombjere van szuksegem, es ezen szovegek darabszama dinamikusan valtozik (egy *argv[] szeru tomb a kimenete a fuggvenyemnek). A sztringek hossza adott a 0 lezaras miatt, azt pedig, hogy hany darab, szamolom.

/sza2

Ha tombos modon adod at, akkor a stackbe belekerul a memoriaterulet hossza, ugyanugy, mintha dope vectort vagy eppen plusz parameterkent az egyes tombdimenziok ertelmezesi tartomanyat adnad meg. Az, hogy a compiler ezt neked igy talalja, attol meg ugyanugy at KELL adni az informaciot, csak az egyik esetben nyelvi elem az informacioatadas, a masik esetben meg neked kell gondoskodnod rola.
Magyaran: a tombos modon valo adatas ugyanaz, mintha melleirnad egy valtozoban a sormeretet. Ugyanaz a kod fog generalodni. Remelem erted, miert ugyanaz a ket dolog. Amit mindig szem elott kell tartani C programozasnal: nem mas ez, mint egy portable assembly, alacsonyszintu minden, a nyelv nem sok midnent rejt el eloled a gep kepessegeibol.

"egyébként erre találták ki alapvetően a visszatérési értéket."
Igen is, meg nem is. Pl. adott egy bonyolultabb struktura, amit fel kell inicializalni, mondjuk tobbek kozt fajlbol (ez egy egyszerubb eset). Ket dolgot kell jelezned a hivo fele: az inicializalas sikerult/nem sikerult, illetve a konkret strukturat.
C-nel altalaban az a megoldas, hogy egy int mystruct_init(struct mystruct*) vagy egy int mystruct_init(struct mystruct**) szignaturaju fuggvennyel toltjuk fel a strukturat, az int visszateresi ertek pedig egy statuskod (jobb esetben 0/1), ami jelzi az inicializalas sikeresseget.
--

Ki oda vagyik, hol szall a galamb, elszalasztja a kincset itt alant. | Gentoo Portal 

Jelezhet, de nem biztos, hogy ez a tokeletes megoldas. Ugyanis a 0/1 es a pointer NULL/nem NULL ertek mar eleve 4 fele hibajelzesre ad lehetoseget, mig siman csak a pointer vizsgalata 2 fele hibajelzest foglal magaban.
--

Ki oda vagyik, hol szall a galamb, elszalasztja a kincset itt alant. | Gentoo Portal 

> a master hogyan latja a worker altal eloallitott hibakat

Általánosságban: a master átad egy feladatot egy worker-nek, az meg visszaadja a feladatot, kiegészítve a feldolgozás eredményeivel. A szálak nem olvasgatják egymás errno-ját, mert csak az adott szál tudja helyesen értelmezni az értékét.

Ezt en sem ertem... mintha ez lett volna a felvetesed: "a hibakód meg kiderülhet az errno -ból.", viszont most meg azt mondod, hogy nem olvasgatjuk az errno-t. Akkor a master honnet fogja tudni a hiba okat? No offense, tenyleg nem vilagos nekem.
--

Ki oda vagyik, hol szall a galamb, elszalasztja a kincset itt alant. | Gentoo Portal 

> void stralloc(char *str)

void stralloc(char **str)
*str = malloc(10);
...
char *str;
stralloc(&str);

Vagy valami ilyesmi.


void stralloc(char **strptr)
{
*strptr = malloc(10);
strcpy(*strptr, "Hello");
}

int main(void)
{
char *str;
stralloc(&str);
printf("%s\n", str);
return 0;
}

Ez nagyjából jónak tűnik.
Hozzáteszem fogalmam sincs a C programozásról, sajnos :(

Igazabol ez szimpla ertek atadas tovabbra is, a pointer is ertek (memoriacim egesz pontosan). Ha jol szeretned megvalositani, akkor egy pointer kell, ami a pointeredre mutat:)

jajam, csak nem láttam sehol sem megmagyarázva a miértet, gondoltam leírom az utókornak:)
Rengeteg alkalommal futok bele olyan fórumokba, ahol a kérdést feltették, majd leírták hogy "megoldottam", csak a hogyan/miért nincs odaírva.
(közben fentebb látom valaki kicsit obfuszkáltabban, de leírta:))