[ RMAN @ 22.10.2011. 11:14 ] @
U cemu je stvar?

Kada pokrenem program u debug modu(bez breakpoint-a) radi savrseno. Medjutim kada ga pokrenem u normalnom modu pukne??

Da li neko ima predstavu sta moze biti?
[ RMAN @ 22.10.2011. 14:00 ] @
Uspeo sam da skontam da mi program puca kada alociram memoriju sa malloc.

Kada ga debagiram nema problema, a kad ga pokrenem pukne. Ne razumem. Kod je prost:

Code:


char *pathOnSystemDrive;

printf("AAA");

pathOnSystemDrive=(char *)malloc(100*sizeof(char));

printf("BBB");



Kada program pokrenem normalno ispise mi AAA ali nece BBB, medjutim kada debagiram ispise oba.
[ maksvel @ 22.10.2011. 15:28 ] @
Imaš li još nešto u programu, još neki deo koda ili sl? Jer, ovo sâmo radi, bar na Pelle's C kompajleru.
[ the_tosic @ 22.10.2011. 15:44 ] @
To sto se BBB ne ispise ne mora da znaci da se taj printf nije izvrsio. Output se bufferise, td posle printf-a stavi flush(stdin).

Moguce da koristis neki pointer a da ga nisi inicijalizovao.

Dalje proveri da li je memorija alocirana tim malloc-om, ako nije moguce da pokusavas da upises tamo gde mu mesto nije (na adresu 0)

[Ovu poruku je menjao the_tosic dana 22.10.2011. u 16:56 GMT+1]

EDIT:
Rekao sam i lupio:
U debug modu on ima neku vrednost (tipa 0xabababab), a u release modu je verovatno 0x0.

Neinicijalizovana globalna promenjiva (sto znaci i pointer) imaju vrednost 0 i u debug i u release modu.
Neinicijalizovana lokalna promenjiva obicno imaju neku "lepu" vrednost (0xabababab) u debug modu da bi bili uocljivi i random vrednost u release modu .

[Ovu poruku je menjao the_tosic dana 22.10.2011. u 17:03 GMT+1]

[Ovu poruku je menjao the_tosic dana 22.10.2011. u 17:05 GMT+1]
[ milanche @ 22.10.2011. 15:45 ] @
Uzrok problema moze biti nezgodna navika nekih kompajlera da u Debug modu inicijalizuju promenljive na 0/NULL,
dok u Release modu to ne cine.

Kod koji si prilozio nema nikakav vidljiv razlog da crash-uje. Moze da se desi da se pucanje desava nesto malo kasnije
iza drugog printf-a, pa tekst drugog printf-a ne stigne da bude flush-ovan niz STDIN. Takodje, ako imas jos thread-ova,
mozda se tamo nesto desava.
[ RMAN @ 22.10.2011. 16:04 ] @
Izgleda da sam otkrio sta je bio problem. Bili ste u pravu, drugi deo koda je bio u pitanju odnosno malloc.

Pretpostavljam da nisam uradio free kada sam alocirao memoriju. Funkcija koja je pravila problem je sledeca(funkcija splituje string po nekom charu):

Code:


char **split(char *string,char delimiter,unsigned *ret)
{
char **output;
//neki kod
//alokacija output-a sa malloc
//neki kod
return output;
}



E, sad ja nisam nigde u funkciji uradio free pa me zanima gde bi trebalo da se uradi?
Uradio sam u drugoj funkciji koja poziva ovu na sledeci nacin:

Code:


char **aa;

aa=split(// parametri);
free(aa);



Da li ima smisla ovako raditi free?
[ milanche @ 22.10.2011. 16:31 ] @
Ovako na prvu loptu, nije mi bas najjasnije sta tacno radis i zasto.

Citat:
RMAN:
Code:


char **aa;

aa=split();
free(aa);



Da li ima smisla ovako raditi free?


Deluje mi prilicno nedisciplinovano.

Predpostavljam da se u tvom kodu radi o sledecem:

ako se desi da u split-ovanom stringu imas N sub-stringova, onda negde u funkciji split()
- prvo alociras memoriju za N pointera na char,
- na svakom od tih pointera alociras memoriju dovoljnu za smestaj konkretnog substring-a (tj. strlen( ) + 1),
- u svaku tako alociranu memoriju kopiras svaki od N substring-ova + terminacioni NULL karakter.
- niz pointera vracas iz funkcije

Ako je to slucaj, onda ti dealokacija nije potpuna. Prvo treba da dealociras memoriju dodeljenu
svakom od N pointera, pa zatim da dealociras memoriju rezervisanu za smestaj pointera. Naravno,
treba da iz funkcije osim char** vratis i N da bi znao koliko puta da odradis dealokaciju.

U ovoj varijanti, zaboravljena/neizvrsena dealokacija sama po sebi nije razlog za crash, nego pre
za memory leak. Mora da posle free( ) radis jos nesto drugo sto ne bi trebalo (tj. pokusavas da koristis
neki od pointera koji jos uvek pokazuje na memoriju koja ti vise ne pripada ili nesto slicno).

Cisto teorije radi (tj. onoga sto omogucava sintaksa), postoji i druga hipoteticka mogucnost - da u
funkciji split() alociras memoriju za jedan jedini pointer na char, i da adresu tog pointera vracas iz funkcije.
U tom slucaju, statement free(aa) ce ti kompajler mozda odobriti, ali je run-time crash neminovan i u
Debug i u Release verziji (ispravno bi bilo free(*aa)). Mirise mi da se u slucaju tvog programa ipak ne
radi o ovome.


[ RMAN @ 22.10.2011. 16:46 ] @
Da. Prvo prebrojim koliko imam sub-stringova i nadjem duzinu najduzeg sub-stringa.
Onda alociram memoriju sa : broj redova je broj sub-stringova i broj kolona je duzina najduzeg stringa +1.
Da, broj redova (sub stringova) vracam preko adrese kao izlazni parametar (unsigned *ret).

Evo stavicu celu funkciju:

Code:

char **split(char *string,char delimiter,unsigned *ret)
{
    int countDelimiters=0;
    int totalLength=0,maxStringLength=0,maxStringLengthCounter=0;
    int i;
    char **output;
    int counter=0;
    int column=0;

    while(*string!='\0')
    {
        if(*(string++)==delimiter)
        {
            countDelimiters++;
            if(maxStringLengthCounter>maxStringLength)
                maxStringLength=maxStringLengthCounter;

            maxStringLengthCounter=-1;
        }

        maxStringLengthCounter++;
        totalLength++;
    }

    if(maxStringLengthCounter>maxStringLength)
        maxStringLength=maxStringLengthCounter;

    string-=totalLength;

    output=(char **)malloc((countDelimiters+1)*sizeof(char));
    for(i=0;i<countDelimiters+1;i++)
        output[i]=(char *)malloc(maxStringLength*sizeof(char));

    while(countDelimiters>0 && *string!='\0')
    {
        if(*string!=delimiter)
        {
            output[counter][column]=*(string++);
            column++;
        }
        else
        {
            output[counter][column]='\0';
            counter++;
            column=0;
            string++;
        }
    }

    output[counter][column+1]='\0';

    *ret=countDelimiters;

    return output;
}
[ RMAN @ 22.10.2011. 16:51 ] @
Da. Prvo prebrojim koliko imam sub-stringova i nadjem duzinu najduzeg sub-stringa.
Onda alociram memoriju sa : broj redova je broj sub-stringova i broj kolona je duzina najduzeg stringa +1.
Da, broj redova (sub stringova) vracam preko adrese kao izlazni parametar (unsigned *ret).

Evo stavicu celu funkciju:

Code:

char **split(char *string,char delimiter,unsigned *ret)
{
    int countDelimiters=0;
    int totalLength=0,maxStringLength=0,maxStringLengthCounter=0;
    int i;
    char **output;
    int counter=0;
    int column=0;

    while(*string!='\0')
    {
        if(*(string++)==delimiter)
        {
            countDelimiters++;
            if(maxStringLengthCounter>maxStringLength)
                maxStringLength=maxStringLengthCounter;

            maxStringLengthCounter=-1;
        }

        maxStringLengthCounter++;
        totalLength++;
    }

    if(maxStringLengthCounter>maxStringLength)
        maxStringLength=maxStringLengthCounter;

    string-=totalLength;

    output=(char **)malloc((countDelimiters+1)*sizeof(char));
    for(i=0;i<countDelimiters+1;i++)
        output[i]=(char *)malloc(maxStringLength*sizeof(char));

    while(countDelimiters>0 && *string!='\0')
    {
        if(*string!=delimiter)
        {
            output[counter][column]=*(string++);
            column++;
        }
        else
        {
            output[counter][column]='\0';
            counter++;
            column=0;
            string++;
        }
    }

    output[counter][column+1]='\0';

    *ret=countDelimiters;

    return output;
}
[ milanche @ 22.10.2011. 17:27 ] @
Ovo nije dobro:

Citat:
output=(char **)malloc((countDelimiters+1)*sizeof(char));


Treba

Citat:
output=(char **)malloc((countDelimiters+1)*sizeof(char*));


sizeof(char) je na sistemima sa 32-bitnim memorijskim opsezima 4x manje nego sizeof(char*),
pa si prakticno alocirao 4x manje memorije nego sto ti treba, sto za posledicu ima da u nastavku
programa

Code:

for(i=0;i<countDelimiters+1;i++)
        output[i]=(char *)malloc(maxStringLength*sizeof(char));


prakticno posle i > countDelimiters/4 kacis vrece sa alociranom memorijom na klinove koji vise u vazduhu.

(...ili jos bolje poredjenje: samo jednu cetvrtinu punih kesa iz samoposluge si stavio u svoj gepek, ostalo si okacio kojekude,
na banderu, klupu u parku, na grane drveca, itd...i u potpunoj si milosti slucajnih prolaznika sta ce da se desi sa tvojim kesama.
U Debug modu ti se skockalo da niko nije prolazio tuda pa je kao sve proslo OK...)
[ RMAN @ 22.10.2011. 17:46 ] @
Aha, ispravio sam to samo i dalje puca (odnosno kada pokrenem program vise puta nekad proradi).

Zanima me zasto je sizeof(char *) razlicito od sizeof(char) ?
[ the_tosic @ 22.10.2011. 17:57 ] @
char je velicine jednog bajta (neko konkretno slovo recimo 't')
char* je velicine adrese. Kod 32b sistema 4Bajta ( 32/8).

char t = 'T'; // slovo T
char* pt = &t; // pokazivac na to slovo (adresa u memoriji gde je to slovo zapisano)

recimo ako je pt = 0x12345 to znaci da se u memoriji na adresi 0x12345 nalazi neki bajt cija je vrednost ascii vrednost slova 'T'. Ako je sistem 32bitni (odnosno podrzava do 4gB memorije) za cuvanje bilo koje adrese u memoriji ti treba 32b (4B), pa je zato pt velicine 4B

http://www.cplusplus.com/doc/tutorial/pointers/
[ milanche @ 22.10.2011. 18:00 ] @
edit: the_tosic i ja smo pisali u isto vreme. Sorry zbog ponavljanja.

Svi pokazivaci (pointeri) su promenljive cija namena je da skladiste adrese memorijskih lokacija.

Oni po definiciji moraju da imaju tacno onoliko bita koliko je memorije dodeljeno programskom modelu.
Ako radimo sa 32-bitnim adresnim prostorima, da bi mogao da uskladisti adresu bilo koje lokacije, pointer
mora da ima najmanje 32 bita. Stavise, sizeof() bilo kog pokazivaca (long*, int*, struct XYZ*, ovo*, ono*...)
ima istu vrednost, diktiranu opsegom memorije dostupne programskom modelu.

Jedino sto je razlicito je sto se u nekim slucajevima (najcesce embedded sistemi sa optimizovanim DMA
kontrolerima) striktno trazi da adresa bude poravnata na celobrojni umnozak velicine (tj. adresa sadrzana u int* bude
umnozak od sizeof(int) = 4). Takodje, MMX/SSE instrukcije imaju slicne zahteve za adrese buffer-a.

sizeof(char) je odredjen po sasvim drugom pravilu - kolika je velicina tipa char za zadato okruzenje/operativni
sistem. Najcesce je 8 bita (1 byte), ali u opstem slucaju to se ne podrazumeva nego se izrazito preporucuje da
se kulturno koristi sizeof() operator.

To je sto se teorije tice.
[ RMAN @ 22.10.2011. 18:01 ] @
Da da, znam da je char 1 bajt i sve sto si napisao. Samo nisam ukljucio MOZAK!!

Logicno da je potrebno 32 bita za cuvanje 32-bitnih adresa. Kako sam glup
[ milanche @ 22.10.2011. 18:17 ] @
Ne znam da li se bas radi o tvojoj gluposti.

Stvar koja me vec dosta dugo vremena prilicno iritira je nesto drugo:

Uprkos cinjenici da je jezik C medju svim struktuiranijim jezicima cilja na to da najplasticnije
reflektuje arhitekturu sistema na kojem radi, jos uvek nisam naisao na udzbenik koji ce prvo
i pre svega da ljudima usadi najbitniju pra-sliku koju moraju da drze u glavi - procesor, registre,
a narocito memoriju - podelu na programsku memoriju i na podatke, stack, heap, itd.

Da se sve to shvati treba mozda 15 minuta.

Bez te slike, godinama se moze lupati glava o tome kako recimo funkcionise rekurzija, nesto manje
da se shvati kako radi alokacija, cemu tacno sluze pointeri itd.

I kasnije, bez te slike se ljudi muce da objasne prosto pitanje - kome je trebao objekat (objektno-orjentisano
programiranje i zasto), kao i 'zasto se objekat zove objekat a ne pegla ili smotuljak ?'

Opet, boli koga ona stvar da to lepo, otvoreno, point blank objasni, posle cega bi cela prica bila pesmica.

No, to je vec izgleda pitanje iz jednog drugog domena.

BTW - nisam uspeo da vidim sta bi jos moglo da ne valja u tvom kodu, a kako stvari stoje (decica vuku
za rukav da idemo u park) nece se desiti bar za jos dosta sati.

BTW: boldovano ti uopste ne treba:

Citat:
while(countDelimiters>0 && *string!='\0')

[ RMAN @ 22.10.2011. 18:23 ] @
Evo resio sam . Pored toga sto si mi rekao da stavim char * zaboravio sam da alociram jos jedan char za \0

for(i=0;i<countDelimiters+1;i++)
output=(char *)malloc((maxStringLength+1)*sizeof(char));

Reci mi samo da li je potrebno negde dealocirati pokazivac koji se vraca iz funkcije? Odnosno da li da uradim kao sto sam mislio, da preuzmem povratnu vrednost funkcije, da je iskoristim pa da je dealociram?

[ RMAN @ 22.10.2011. 18:27 ] @
Nisam video da si odgovorio, u to vreme sam kucao poruku.

Treba mi to boldovano, to sam stavio da ne udje u while ako nema delimitera.
[ milanche @ 23.10.2011. 03:15 ] @
Citat:
RMAN: Nisam video da si odgovorio, u to vreme sam kucao poruku.

Treba mi to boldovano, to sam stavio da ne udje u while ako nema delimitera.


OK, validan razlog.


Citat:
[url=/p2976212]RMAN[/url

Reci mi samo da li je potrebno negde dealocirati pokazivac koji se vraca iz funkcije? Odnosno da li da uradim kao sto sam mislio, da preuzmem povratnu vrednost funkcije, da je iskoristim pa da je dealociram?


Naravno. Sve dok je memorija alocirana u istom procesu (a funkcije jesu deo istog procesa) sacuvana numericka vrednost koju je malloc() vratio se moze iskoristiti (samo jednom) za validan free() poziv.U pogledu dealokacije je sasvim nebitno gde si tu numericku vrednost sacuvao, u povratnoj vrednosti funcije, u globalnoj promenljivoj, u clanu neke strukture - sve dok je promenljiva 'ziva' tj. jos uvek u vazecem scope-u sve je OK. Jedino gde postoji opasnost da promenljiva izadje iz scope-a su lokalne promenljive funkcija - cim se funkcija izvrsi, sve promenljive prakticno nestaju, stack frame funkcije je mrtav.
[ RMAN @ 23.10.2011. 15:20 ] @
Jasno, hvala ti