Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C: SDL_Surface ja oikeaoppinen muistinvaraus

Sivun loppuun

Burton [03.07.2008 03:15:17]

#

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. :)

hunajavohveli [03.07.2008 11:57:27]

#

"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.

Burton [03.07.2008 14:28:57]

#

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?

vehkis91 [03.07.2008 15:02:15]

#

Miks et vain voi käyttää SDL_FreeSurface[kuvat] ?

hunajavohveli [03.07.2008 15:07:10]

#

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.

Burton [03.07.2008 15:42:31]

#

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.

hunajavohveli [03.07.2008 16:28:39]

#

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.

vehkis91 [03.07.2008 16:46:43]

#

Heitin ton vaan päästä ilman tarkempaa miettimistä... ;)

Metabolix [03.07.2008 19:09:57]

#

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]);

vehkis91 [03.07.2008 19:23:51]

#

No kyllä osaan for silmukalla varata ja vapauttaa surfacet, mutta en miettinyt, kuten aiemmin sanoin. Anteeksi, että en testannut...


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta