Moikka. Kyselin taannoin tietueita koskevista muistinvarausmenetelmistä, ja nyt asiassa ollaan edetty niinkin kummallisiin asioihin kuin SDL_Surface-muuttujiin. Haluaisin varata SDL_Surface-muuttujia x kappaletta malloc-funktion avulla, mutta en ole ollenkaan varma ohjelman toiminnasta enkä siitä, kuinka muisti kuuluisi oikeaoppisesti vapauttaa.
Kasasin omin avuin pienen koodin kokeilemalla eri **, [] ja & -yhdistelmiä. Olen ohittanut C:n tekniikat todella hätäisesti ohjelmoinnin alkuvaiheessa, joten en mene vannomaan, ymmärsinkö esimerkiksi *- ja &-operaattorien oikean merkityksen. Seuraava koodi toimii, mutta muistinvapautus on kysymysmerkki.
#include <stdio.h> #include <stdlib.h> #include <SDL/SDL.h> SDL_Surface *naytto; void piirra(SDL_Surface **kuvat, short k_maara) { SDL_Rect k; k.x = k.y = 300; for (; k_maara >= 0; --k_maara, k.x -= 50) SDL_BlitSurface(kuvat[k_maara], NULL, naytto, &k); SDL_Flip(naytto); SDL_Delay(3000); } void alusta(SDL_Surface **kuvat[], short *k_maara) { char nimi[16]; SDL_Surface **tmp = NULL; short i; *k_maara = 3; tmp = (SDL_Surface **)malloc(sizeof(SDL_Surface *) * (*k_maara)); for (i = 0; i < *k_maara; ++i) { sprintf(nimi, "asd%hi.bmp", i); tmp[i] = SDL_LoadBMP(nimi); } *kuvat = tmp; } void funktio(void) { SDL_Surface **kuvat = NULL; short k_maara; alusta(&kuvat, &k_maara); piirra(kuvat, k_maara); for (; k_maara >= 0; --k_maara) SDL_FreeSurface(kuvat[k_maara]); /* ONGELMA! Sekä free(kuvat) että free(*kuvat) toimivat ilman, että ohjelma kaatuu tai tulee virheilmoitus. Kumpaa kuuluisi käyttää ja miksi? */ free(*kuvat); *kuvat = NULL; printf("elossa?\n"); } int main(int ac1, char *av1[]) { if (SDL_Init(SDL_INIT_VIDEO) < 0) return 1; atexit(SDL_Quit); SDL_WM_SetCaption("SDL-Testi", NULL); naytto = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE|SDL_DOUBLEBUF) funktio(); return 0; }
Pahoittelen rumia kooditottumuksia, mutta ylläoleva on kello kolmen aamuöinen tuotos. Halusin vain selvittää itselleni pari asiaa ennen nukkumaanmenoa. Joten, arvon Ohjelmointiputka, voisitteko kertoa ratkaisun kommentissa kysyttyy kysymykseen sekä mahdollisesti esitellä pienoisesti osoittimien käyttöä ja mm. sitä, miksi SDL_Surface:n eteen sijoitetaan tähti '*' ja mikä tarkoittaakaan SDL_Surface **tmp?
Kiitos paljon. :)
"SDL_Surface *foo" tarkoittaa, että luodaan osoitinmuuttuja, joka osoittaa SDL_Surface-tyyppiseen tietueeseen. "SDL_Surface **foo" taas tarkoittaa, että luodaan osoitinmuuttuja, joka osoittaa em. tyyppiseen osoittimeen. Kun haluat varata "SDL_Surface-muuttujia", tarkoitat varmaankin, että haluat varata juuri osoittimia SDL_Surface-tietueisiin. Tämä voidaan tehdä esimerkiksi luomalla taulukko kyseisiä osoittimia:
SDL_Surface *kuvat[100]; // Luodaan sata kappaletta osoittimia
Tällöin vapautus tietysti on automaattista. Jos taas haluat käyttää dynaamista muistinvarausta, homma menee näin:
SDL_Surface **kuvat = malloc(100 * sizeof(SDL_Surface *)); // Varataan tilaa sadalle SDL_Surface-osoittimelle ja sijoitetaan malloc():n palauttama osoite osoittimeen, joka osoittaa joukkoon SDL_Surface-osoittimia. free(kuvat); // Vapautetaan osoittimille varattu taulukko free(*kuvat); // Väärin! Tässä tehdään ensin viittaus osoittimen kautta, eli viitataan kuvat-taulukon ensimmäiseen alkioon, joka on siis osoitin SDL_Surfaceen. SDL_Surfacet tulee kuitenkin vapauttaa SDL:n omilla funktioilla, ei free():llä.
Osoittimien ymmärtäminen vie aikansa, joten sitä kannattanee harjoitella ensin jollain yksinkertaisemmalla.
Ymmärsinkö oikein, että free(*kuvat) vastaa melkein kuin SDL_FreeSurface:a? Jos näin on, niin mitä tapahtuu, kun pinnat on vapautettu ensin SDL_FreeSurface:lla ja sitten vahingon saattelemana ohjelma suorittaa komennon free(*kuvat)? Onko tässä mahdollista puhdistaa muistia jostain, mistä ei pitäisi?
Antaako Windows ohjelman koskea toisten ohjelmien muistiin sekä muistialueille, joita ei ole varattu ko. ohjelman käyttöön?
Miks et vain voi käyttää SDL_FreeSurface[kuvat] ?
Burton kirjoitti:
Ymmärsinkö oikein, että free(*kuvat) vastaa melkein kuin SDL_FreeSurface:a? Jos näin on, niin mitä tapahtuu, kun pinnat on vapautettu ensin SDL_FreeSurface:lla ja sitten vahingon saattelemana ohjelma suorittaa komennon free(*kuvat)?
Se riippuu monesta asiasta, mutta joka tapauksessa on virhe vapauttaa SDL_Surface jollain muulla kuin SDL_FreeSurface():lla. Samoin on virhe vapauttaa free():llä jo vapautettu muistialue. Linuxilla ohjelma omien kokemuksieni mukaan yleensä kaatuu.
Burton kirjoitti:
Antaako Windows ohjelman koskea toisten ohjelmien muistiin sekä muistialueille, joita ei ole varattu ko. ohjelman käyttöön?
Maalaisjärjellä sanoisin, että ei taatusti anna, mutta en mene takuuseen, kun en tarkemmin asiaa tunne.
vehkis91 kirjoitti:
Miks et vain voi käyttää SDL_FreeSurface[kuvat] ?
Ehkä siksi, ettei tuo toimi.
Kiitos vastauksista, hunajavohveli. Kokeilen selviytyä nyt omin avuin ainakin seuraavaan ylitsepääsemättömään ongelmaan asti.
Burton kirjoitti:
vehkis91 kirjoitti:
Miks et vain voi käyttää SDL_FreeSurface[kuvat] ?
Ehkä siksi, ettei tuo toimi.
SDL_FreeSurface(kuvat) ei toimi, koska kuvat ei osoita SDL_Surfaceen vaan taulukkoon, joka sisältää osoittimia SDL_Surface:ihin. Jokainen SDL_Surface, johon taulukosta on osoitin, on vapautettava erikseen. Suosittelen lukemaan osoitinmuuttujista tarkemmin, jos asia ei vielä selvinnyt.
Heitin ton vaan päästä ilman tarkempaa miettimistä... ;)
vehkis91, sinuna en yrittäisi neuvoa toisia ainakaan kokeilematta ensin, että koodi toimii. Itse et taida olla vielä aivan tälläkään tasolla. :)
Burton:
SDL_Surface *kuva; kuva = SDL_LoadBMP("kuva.bmp"); SDL_FreeSurface(kuva); // --- SDL_Surface **kuvat; kuvat = (SDL_Surface **) malloc(lkm * sizeof(SDL_Surface*)); // Nyt jokainen kuvat[i] toimii samalla tavalla kuin kuva yllä. // Niihin voi hakea kuvan, ja lopuksi kuva täytyy niistä vapauttaa. // Ei pidä lukkiutua tähän silmukkakonseptiin. ;) for (i = 0; i < lkm; ++i) { kuvat[i] = SDL_LoadBMP("kuva.bmp"); } for (i = 0; i < lkm; ++i) { SDL_FreeSurface(kuvat[i]); } free(kuvat);
Ajattele asiaa loogisesti: jokainen SDL_LoadBMP-kutsulla (tai vastaavalla) varattu asia täytyy vapauttaa SDL_FreeSurface-kutsulla, siis jokainen kuvat[i]. Vastaavasti jokainen malloc-kutsulla tai vastaavalla varattu asia täytyy vapauttaa free-kutsulla. Luonnollisesti vapautusten täytyy tapahtua varaamisiin nähden sikäli käänteisessä järjestyksessä, että kuvat-taulua ei pidä vapauttaa free-kutsulla, jos sen sisältämiä SDL_Surfaceita ei ole vapautettu SDL_FreeSurfacella.
Tarkista aina, että varaukset ja vapautukset muodostavat pareja:
x = varaus(); vapauta(x); y[i] = varaus(); vapauta(y[i]); *z[j] = varaus(); vapauta(*z[j]);
No kyllä osaan for silmukalla varata ja vapauttaa surfacet, mutta en miettinyt, kuten aiemmin sanoin. Anteeksi, että en testannut...
Aihe on jo aika vanha, joten et voi enää vastata siihen.