Hjälp!
Elikkäs semmoista että kun olen yritän vapauttaa dynaamisesti varattua muistia niin muuttujan sisältö ei vapaudu. Onko ok? Koodi:
#include
#include
#include
int Vaihda(char** pnLuku1);
void Vapauta(char* pnLuku1);
int main(int argc, char* argv[])
{
char* nLuku1 = "foo";
printf("Luvut ennen vaihtamista: \n");
printf("Luku1 = %s\n", nLuku1);
Vaihda(&nLuku1);
printf("Luvut vaihtamisen jälkeen: \n");
printf("Luku1 = %s\n", nLuku1);
Vapauta(nLuku1);
printf("Luvut vapauttamisen jälkeen: \n");
printf("Luku1 = %s\n", nLuku1);
nLuku1 = NULL;
printf("Luvut nullaamisen jälkeen: \n");
printf("Luku1 = %s\n", nLuku1);
sleep(10);
return 0;
}
int Vaihda(char** pnLuku1)
{
char* testi = "testistr";
*pnLuku1 = malloc((strlen(testi 1))* sizeof(char));
strcpy((char*)(*pnLuku1), testi);
return 0;
}
void Vapauta(char* pnLuku1)
{
printf("Vapautetaan... \n");
free(pnLuku1);
}
Tulostaa:
Luvut ennen vaihtamista:
Luku1 = foo
Luvut vaihtamisen jälkeen:
Luku1 = testistr
Vapautetaan...
Luvut vapauttamisen jälkeen:
Luku1 = testistr
Luvut nullaamisen jälkeen:
Luku1 = (null)
Ajoin Leaksilla ja se ei ainakaan havainnut muistivuotoa, mutta miksi luku1 tulostuu vielä vapautuksen jälkeen? Mikä tässä nyt kusee?
Elikkäs semmoista että kun olen yritän vapauttaa dynaamisesti varattua muistia niin muuttujan sisältö ei vapaudu. Onko ok? Koodi:
#include
#include
#include
int Vaihda(char** pnLuku1);
void Vapauta(char* pnLuku1);
int main(int argc, char* argv[])
{
char* nLuku1 = "foo";
printf("Luvut ennen vaihtamista: \n");
printf("Luku1 = %s\n", nLuku1);
Vaihda(&nLuku1);
printf("Luvut vaihtamisen jälkeen: \n");
printf("Luku1 = %s\n", nLuku1);
Vapauta(nLuku1);
printf("Luvut vapauttamisen jälkeen: \n");
printf("Luku1 = %s\n", nLuku1);
nLuku1 = NULL;
printf("Luvut nullaamisen jälkeen: \n");
printf("Luku1 = %s\n", nLuku1);
sleep(10);
return 0;
}
int Vaihda(char** pnLuku1)
{
char* testi = "testistr";
*pnLuku1 = malloc((strlen(testi 1))* sizeof(char));
strcpy((char*)(*pnLuku1), testi);
return 0;
}
void Vapauta(char* pnLuku1)
{
printf("Vapautetaan... \n");
free(pnLuku1);
}
Tulostaa:
Luvut ennen vaihtamista:
Luku1 = foo
Luvut vaihtamisen jälkeen:
Luku1 = testistr
Vapautetaan...
Luvut vapauttamisen jälkeen:
Luku1 = testistr
Luvut nullaamisen jälkeen:
Luku1 = (null)
Ajoin Leaksilla ja se ei ainakaan havainnut muistivuotoa, mutta miksi luku1 tulostuu vielä vapautuksen jälkeen? Mikä tässä nyt kusee?
Vastaukset 46
Vanhimmat
Kyllä free vapauttaa muistin, mutta free ei nullaa pointeria. Niin se näyttää tässä tapauksessa vielä samaa, kun mikään muukaan prosessi ei ole muuttanut ko muistia.
Jos muistia tutkii/käyttää vapautuksen jälkeen, sen sisältö voi olla mitä hyvänsä ja siitä voi seurata epämääräisesti esiintyviä virheitä.
Monesti käytetään seuraava funktio pohjaa muistinvapautusten suorittamiseen:
my_free(void *ptr) {
if(ptr) free(ptr);
ptr = NULL;
}
Tämä menettely varmistaa että ei vapauteta jo vapautettua muistia. Lisäksi se asettaa pointterin arvoksi NULL jolla varmistetaan edelleen mahdollisten ongelmien kertyminen ja mahdolliset varaamattoman alueen käytöt huomataan nopeammin.
Mieluummin:
#define my_free(ptr) {free(ptr);ptr=NULL;}
muuten ajatuksesi ei toimi.
Ei tartte vapauttaa, jos asetetaan osoittamaan tietokoneen nollaan!
Tietokoneen nolla on todennäköisesti eri asia kuin ihmisen nolla!
Höpöhöpö. Mene kotiin syömään puuroa.
Sama asia. Kääntäjä kuitenkin inlainaa pienet funktiot pääsääntöisesti. Kirjoittamalla vapautuksen funktion muotoon mahdollistetaan parempi kääntäjäoptimointi.
Höpöhöpö. Et siis ymmärrä makron ja funktion eroa. Eikä tässä puhuta C ohjelmasta.
Toi Jamppo ei oo koskaan ohjelmoinnu: kaikki ketä on joskus ohjelmoinnu nollaaki, tietää, et NULL on keksitty erilaisia tietokoneita varte, että ne äkkäis, et jossain toisenlaises tietokonees nolla onkin erilainen kuin siinä ja siks tarttee NULL: ia, et vois joustavast siirtää sorsat ja kaikki tietokoneesta toisenlaiseen ilman, että tarttee siä alkaa millää sripktil selittään, et täs ois niinkö nolla, jos siin on nolla, ku riittää, et sanoo joka konees, et siin on NULL ja ne ymmärtää heti, mist siin on kysymys: nollasta, joka on ihmisellä eri asia kuin tietokoneilla!
Et taida itse ymmärtää.
Jos nyt tarkoitat sitä että funktion argumenttina oleva tyyppi on eri kuin esim. sille heitettävä pointteri niin luonnollisesti kirjoitetaan se funktio hyväksymään sitä oikeaa tyyppiä.
Voihan tuon aivan hyvin makrollakin hoitaa mutta funktiota käytetään yleisemmin juurikin tuon kääntäjäoptimoinnin takia.
Meneppäs C-kielen alkeiskurssille, Sitten muutamalle jatkokurssille. Tule sitten takaisin tänne pyytämään anteeksi tietämättömyyttäsi.
Sen verran häiritsee tämä disinformaatio, että pakko korjata. Olkoon koodi
inline my_free(void *ptr) {
if(ptr) free(ptr);
ptr = NULL;
}
int main(void) {
int *jep = malloc(100);
my_free(jep);
printf("%d", (int)jep);
}
Nyt siis my_free on inline-funktio, mutta mikä arvo tulostuu? Vastaus - ei ainakaan nolla. Vaikka funktio on inline, muuttuja ptr on silti lokaali muuttuja ja jep ei nollaudu.
Sen sijaan tällaisessa voisi olla jotain järjen hiven:
inline my_free(void **ptr) {
if(*ptr) free(*ptr);
*ptr = NULL;
}
Makro on vielä parempi. Mutta vielä parempi on C++:n auto_ptr.
Inline kannattaa jättää pois ja antaa kääntäjän päättä optimoinneista.
Jos vapautusta kutsutaan useasti niin ei ole mitään järkeä kirjoittaa sitä makroksi.
C taas aivovammainen kieli aivovaimmaisine standardikirjastoinene joten sen voi jättää kokonaan laskuista.
vittu noiden kurssien kanssa.. Opetetaan aivan päin persettä kaikki.
Aloitetaan yleensä "void main(void)".
rage.
Olet kyllä oikeassa, c :n suhteen. Qbasic on jopa parempi.
Mutta kun me harrastelijatkin halutaan vähän käyttää älynystyröitä, niin c on
kivaa ajanvietettä.
"Opetetaan aivan päin persettä kaikki."
Sitähän sinä et voi tietää.
Meeppäs vaan nyt sinne kurssille niin ehkä opitkin jotain.
En oikeastaan osaa C:tä, mut yritetään. Korjatkaa jos olen väärässä. C:ssä välitetään arvot funktioille, eikä niiden referenssejä. Eli funktiokutsua varten muuttujista tehdään paikalliset kopiot. Hän käyttää makroa, koska ne laajennetaan esikääntäjän toimesta, funktiokutsua ei tehdä ja siis muuttujaakin pystyy roppaamaan suoraan. Tai sit funktiolle täytyis laittaa osoitinmuuttujan osoite? Ei yhtäkään C-kurssia, ja luulen että sain ton oikein. \o/ Ketä kiinnostaa in-lainaako kääntäjä jotain? Menee enemmän käshee.
No eipä ole tullut vielä yhtään kurssia vastaan jossa "opettaja" osaisi paremmin C:tä kuin minä.
Niin juurikin näin.
Toinen vaihtoehto on passata funktiolle osoittimen pointteri ja hoitaa sitten asi funkiton sisällä. Tämä mahdollistaa paremman kääntäjänoptimoinnin.
Itse suosin yleensä sitä vaihtoehtoa joka näyttää selkeimmältä ja auttaa kääntäjää tekemään hommansa kunnolla. Tämä on hieman rajatapaus.
Et siis ymmärtänyt kurssista mitään.
Etkö parempaa keksinyt. ad hominem abusivum ja sitä rataa.
Mutta joo jos olet koskaan edes näitä yleisiä kursseja oikeasti katsellut niin ne ovat pääosin täyttä sontaa.
Tähän asti kaikki C/C kielestä lausumasi osoittaa ettet ymmärrä asiasta mitään. Siksi sinun on ihan turha arvostella esim. niitä kursseja.
Koska 90% kursseista on täyttä paska jossa opetetaan kaikki vastoin standardeja.
Kannattaisi varmaan lukea C:n standardi whitepaperit ettei tarvi täällä länkyttää turhanpäiväisesti.
Ilmeiseti tähän alalankaan on vastannut monta eri henkilöä ja sekoitat nyt jonkun muun toiseen.
ps. Kurssit todella ovat suurimmaksi osaksi huonolaatuisia.
Kuinka monen kurssin kokemuksella arvioit valtaosan niistä huonolaatuisiksi?
Useamman koulukurssin (AMK ja Ammattikoulu) muutaman erillisen alkeis ja jatkokurssin.
void main ja sitä rataa.
Jep, ammattikoulukurssit (AK and AMK) ovat kyllä keskimäärin syvältä. Helmiä kyllä löytyy, mutta yleisesti ottaen parempi kurssitarjonta on yliopistoissa, joita löytyy myöskin Suomesta pilvin pimein.
Niin, ja entisenä C-opettajan kommentoisin, että "void main" on huonoa ohjelmointityyliä. Se on "int main".
Niin juurikin. Ja "wanahat parrat" opettaa vielä näillä paljon parjatuilla C kursseilla nimenomaan "void main()" eikä standardinmukaista versiosta.
Lisäksi edelleen törmää usein johonkin kivikautiseen Borlandin C builderiin jota noilla kursseilla käytetään.
Joskus tehdään myös jollain sairaalla C/C kombinaatiolla asiat kun kurssin vetäjä ei osaa kumpaakaan kieltä kunnolla vaan vähän molempia :D
Se ei ole huonoa tyyliä vaan yksiselitteisesti väärin.
http://c-faq.com/ansi/voidmain.html
http://c-faq.com/ansi/maindecl.html
Siis C-ohjelman käynnistyskoodi odottaa main-funktiolta palautuksena int-arvoa.
(Tietysti kääntäjä lisää ohjelmaan automaattisesti tuon käynnistyskoodin)
Joo sehän on siis täysin standardinvastainen menettely.
Sulautetussa ympräristössä salittakkoon alustan sallimien rajojen puitteissa. Sulautetussa ei voi muutenkaan aina seurata kaikkia standardeja sata prosenttisesti.
C fanipojat käyneet pistämässä thumbs downia oikein urakalla. :D
Siitä ei kyllä pääse yli eikä ympäri että C standarikirjast on uskomattoman huonosti suunniteltu.
Kun kerran ilmoitat olevasi tuollainen asiantuntija, niin kerrohan yksityiskohtaisesti ja perustellen mikä siinä niin huonoa on?
Sitten kerro yksityiskohtaisesti miten itse olisit suunnitellut paremman.
Mutta koska et asiasta mitään tiedä, niin varmasti et pysty vastaamaan edes omaan huutoosi.
Esimerkiksi pahamainen file io joka on aivan vitun turha verrattuna C:n yksinkertaiseen ja tehokkaaseen tiedostojenkäsittelyyn.
Käytänössä C ifstream on huonosti suunniteltu luokkamöhkäle joka sisältää kaikki samat funktiot kuin C:n yksinkertainen malli. Tiedoston lataaminen muistiin ifstreamilla on vittumaista purkkaa ja tiedoston koon selvittäminenkin tapahtuu juuri samalla tavalla kuin C:ssä. Mikä on siis if/ofstreamien pointti.
Koko standardirjasto on täynnä tälläistä purkkaa ja monesti saman asian voi tehdä yli 9000 eri tavalla. C:ssä hyviä tapoja on vain yksi. C standardikirjastoa pitäsi yksinkertaistaa.
STL on varsin hyvin suunniteltu kokonaisuus, ja se on erityisesti tarkoitettu isojen ohjelmistojen tekoon eikä mihinkään "helloworldiin". Hyvä ohjelmoija käyttää tarkoituksiinsa parhaiten sopivia (luokka)kirjastoja, mutta osaamaton pelle ei ymmärrä suurista kokonaisuuksista mitään ja tietenkin turhautuu.
Tässä muutamia pointteja miksi STL on myöskin hieman päin vittua suunniteltu alusta alkaen:
http://www.cherea.de/usability/stlbad.html
http://www.ski-epic.com/templates_stl_rant/index.html
Mutta joo.. Minusta C standarikirjasto ei rohkaise yksinkertaiseen ja selkeään ratkaisuun koska sieltä löytyy kaikenlaista nippelia ja nappelia liikaa. C on vaikea opetella juurikin tuon levahtaneen standardikirjaston takia.
Tietysti hyvä koodaaja valitseet työkalut tehtävän mukaan mutta onko siitä pakko tehdä tarpeettoman monimutkaista ja vaikeasti opeteltavaa.
Onneksi on D on nousussa ja Vala vahvasti kehityksen alla. Saadaa vihdoin se kunnon hyödyllinen harppaus C:stä eteenpäin.
Heitetäänpä tähän vielä Linus Torvaldsin kieli poskessa heittämä kommentti C :sta:
"C is in that inconvenient spot where it doesn't help make things simple enough to be truly usable for prototyping or simple GUI programming, and yet isn't the lean system programming language that C is that actively encourages you to use simple and direct constructs."
Pakko tässä kohdin yhtyä herran mielipiteeseen.
SLT on hemmetin vaikea käyttää, mikä oikeastaan on se syy mikä tekee siitä huonon. Tunnustan käyttäneeni STL:ää aika-ajoin ja periaatteessa se on kunnon nörtin taivas - sehän toteuttaa geneerisen ohjelmoinnin työkalut ihan oikeasti ja niin, että koodista tulee oikeasti tehokasta. Juuri tehokkuussyistä olen sitä välillä käyttänyt (ja välttääkseni dynaamisen muistinvarauksen kirot). Mutta ehkä on ollut huono idea toteuttaa tällainen kirjasto C :n päälle, mikä ei ihan ole yhteensopiva tällaisen toteuttamiseen syntaksiltaan.
Tunnustan myös käyttäväni I/O-toiminnallisuuksiin C:n stdio:ta C :n streamien sijaan, koska pelkkä formatoitu tulostus on tehty niin hemmetin vaikeaksi perus printf:iin verrattuna.
C sen sijaan vähän tavallisimmilta olio-ominaisuuksiltaan on ihan hyvä C:n jatke. Sillä voi tehdä puhtaasti pass-by-value-tyyppistä koodia ja silti käyttää olioita, minkä vastaavan toteuttaminen vaatisi C:ssä pointteita ja dynaamista muistin varausta. Ne taas ovat synti jos tehdään koodia vaikka sulautettuun järjestelmään minkä pitää toimia ihan oikeasti (todistetusti).
Itseasiassa pidän siitä ajatuksesta että käyttää C oliomallia C:n standardikirjaston kanssa. Tämän tietysti C koodaajat tyrmää täysin mutta pidän C omaa standardikirjastoa suurimmaksi osaksi niin hyödyttömänä ettei huvita käyttää.
C Oliomalli käytännöllä saa mukavan selkeää ja toiminnallisuudeltaan helposti luettavaa koodia aikaan.
Muistia ei tarvitse vapauttaa, koska ohjelman suorituksen päätyttyä kaikki muisti vapautetaan automaattisesti. Nykykoneissa on niin paljon muistia, ettei haittaa vaikka jättäisikin muistin vapauttamatta.
Taidat olla Nokialla töissä? Ei ihme että firmalla menee huonosti...
Ei tullut mieleen sellainen mahdollisuus jos esim. sovellus pyörii monta tuntia tai päiviä putkeen. Ei siinä kauaa mene kun se on imaissu ja vuotanut kaiken muistin.
C/C != Java
En ole töissä Nokialla vaan eräässä toisessa suuressa IT-alan yrityksessä, jonka nimeä en ala nyt paljastamaan. Kyllä meille annettiin ainakin selkeästi ohjeistus, että niitä muistivuotoja on turha lähteä metsästämään koska ajan voi käyttää paljon tuottavammin. Sillon kun ohjelman suoritus lakkaa, vapautuu muisti. Myös muistin vapautus on sen verran hidas operaatio, että mielummin tekee ohjelmasta vähän nopeamman.
Harvemmin ne ohjelmat montaa päivää putkeen pyörii, itse ainakin sammutan koneen joka ilta ja käynnistän joka aamu, keskusmuistia on 4 4 gb eli ei ihan heti ala muistivuodon riivaamaan ;)
Varsinainen C tohtori. :) Toivottavasti en työelämässä koskaan törmää tuollaisiin koodareihin tai projektipäälliköihin jotka noin ohjeistavat. Mikä firma mahtaa olla kyseessä, kenties Tieto? :P
"itse ainakin sammutan koneen joka ilta ja käynnistän joka aamu"
Jaahas.
Palvelinsofta?
Taidat olla trolli. Ja jos et oli niin haluaisin todellakin tietää sen firman joka ohjeistaa moiseen älyttömyyteen.
Et taida olla ihan välkky.