muistinhallinta ja malloc

Eli tehtävän anto on: Kirjoita funktio, joka etsii merkkijonosta tiettyä merkkiä.

Funktiolle annetaan parametreina merkkijono ja merkki. Funktio palauttaa arvonaan osoittimen merkkijonon ensimmäiseen sellaiseen merkkiin, jota etsitään. Ellei etsittävää merkkiä löydy, funktio palauttaa arvon NULL.

Kirjoita funktiolle myös käyttöympäristö eli pääohjelma, josta kutsut sitä.
--------------------------------

Ongelmani on että en ymmärrä täysin tuota muistinvarausta. Eli kun käännän seuraavan ohjelman gcc:llä linuxissa, niin ohjelma kääntyy, mutta ohjelmaa ajettaessa tulee ilmoitus "muistialueen ylitys". Tämä siis tulee heti kun olen syöttänyt kysyttävän merkin.

Löytyisikö joltakin ystävälliseltä sielulta apuja, että tietäisin missä kohdassa koodiani mennään metsään? Kiitos.

Tässä yritelmäni:


#include
#include
#define MAX 20

char *merkkijono(char *mjono, char merkki);

int main(void){
char mj[MAX 1];
char m,*ptr;

printf("Anna merkkijono (max %d merkkiä): ",MAX);
fgets(mj,MAX 1,stdin);
mj[strlen(mj)-1]='\0';

printf("Anna merkki: ");
scanf("%c",&m);

ptr=(char *)malloc( sizeof (char) );

ptr=merkkijono(mj,m);

printf("\nMerkkijono: %s\n",*ptr);

free(ptr);

return 0;

}

char *merkkijono(char *mjono, char merkki){

while ((*mjono != '\0') && (*mjono != merkki )){
    mjono ;
}

if (*(mjono) == '\0') { return NULL; }

else{

return mjono;

}
}
12496
Äänestä

Muut lukivat myös

Vastaukset 12

Vanhimmat

Hyvä et laitoit koko koodin. Onkin helppo sanoa virhekohta hirveesti arvaamatta.
Viimeisessä tulostuksessa ei saisi käyttää osoittimen osoittamaa arvoa vaan itse osoitinta:
printf("\nMerkkijono: %s\n",ptr);
Toiseksi määrittelit ptr -osoittimelle arvon kahdesti:
ptr=(char *)malloc( sizeof (char) );
ptr=merkkijono(mj,m);
jolloin ptr:n aiempi sisältö poistuu ja näin ollen lopussa ollut free(ptr) ei toimi. Poista siis malloc ja free -rivit.

Äänestä
  • >Viimeisessä tulostuksessa ei saisi käyttää >osoittimen osoittamaa arvoa vaan itse osoitinta:
    >printf("\nMerkkijono: %s\n",ptr);

    Eli onko tämä koska merkkijonotaulukkokin on itsessään vaan osoitin taulukon alkuun?

    Niin ja sitten vielä ymmärsin etten ole tuota malloc() funktiota ymmärtänyt koska tässä sitä turhaan käytin. Eli minkälaisissa tilanteissa tuota muistia on varattava?

    Kiitos vielä paljon!

    Äänestä

  • jumissa kirjoitti:

    >Viimeisessä tulostuksessa ei saisi käyttää >osoittimen osoittamaa arvoa vaan itse osoitinta:
    >printf("\nMerkkijono: %s\n",ptr);

    Eli onko tämä koska merkkijonotaulukkokin on itsessään vaan osoitin taulukon alkuun?

    Niin ja sitten vielä ymmärsin etten ole tuota malloc() funktiota ymmärtänyt koska tässä sitä turhaan käytin. Eli minkälaisissa tilanteissa tuota muistia on varattava?

    Kiitos vielä paljon!

    silloin kun käsitellään suuria märiä tietoa.

    Äänestä

  • jumissa kirjoitti:

    >Viimeisessä tulostuksessa ei saisi käyttää >osoittimen osoittamaa arvoa vaan itse osoitinta:
    >printf("\nMerkkijono: %s\n",ptr);

    Eli onko tämä koska merkkijonotaulukkokin on itsessään vaan osoitin taulukon alkuun?

    Niin ja sitten vielä ymmärsin etten ole tuota malloc() funktiota ymmärtänyt koska tässä sitä turhaan käytin. Eli minkälaisissa tilanteissa tuota muistia on varattava?

    Kiitos vielä paljon!

    printf:n %s -parametri tarvitsee osoitinta merkkijonoon (ptr). %c -parametrilla tulostettaisiin yksittäinen merkki (*ptr).
    Sulla oli siinä mallocissa varattavana vain yksi tavu. Normaalisti miten mä varailen muistia:
    - jos taulukon koko on ennakkoon tiedossa ja koko on korkeintaan pari sataa kilotavua (ja ohjelmassa on alustamattomia arvoja alle ½ megaa)
    · pienet varaukset funktion sisällä (pinomuisti) tai seuraavan kohdan mukaisesti
    · suuret varaukset ja sellaiset jotka on alustettava nollaksi, käyttäen static -valintaa (data -osio)
    - jos tarvittavan tiedon koko ei ole tiedossa, käyttäen mallocia vastaavaa käskyä. Esimerkkinä tiedoston luku muistiin

    Koska teen tällä hetkellä pelkästään winkkarille, en käyttele mallocia, vaan vastaavaa HeapAllocia (malloc käyttää HeapAlloc -funktiota). Jos tiedosto on suurempi kuin 500 kiloa, täytyy muistinhallintaa mietiskellä uudestaan. Tällöin voisi käytellä suurilla tiedostoilla CreateFileMapping -funktiota.

    Kun muistinvarauksen tekee ohjelmassa, tulisi välttää alustettujen arvojen kohdalla varaamasta hirveen isoo klönttiä muistia. Esim. char tiedosto[10240]="c:\\hakemisto\\" sijoitettuna funktioiden ulkopuolelle, vie exe -tiedostosta 10 kilotavua tilaa (loppu teksti on alustettu nolliksi). Jos määrittely on taas funktion sisällä, ohjelman alussa varataan muistia pinosta ja alustettu osa (c:\hakemisto\) siirretään data- osiosta varatun muistin alkuun (loppu muisti on sattumanvaraisia numeroita).
    Vuosia sitten, kun tein yhtä dll:n ensimmäistä versiota, opin kantapään kautta mihin alustetut arvot kuuluvat. Tuli meinaan laitettua funktion sisään ilman mitään const -parametrejä, isoja liukulukutaululukoita. Kun siirsin arvot funktion ulkopuolelle, koko pieneni sadoilla kilotavuilla ja ohjelma nopeutui huomattavasti. Funktion sisällä oleviin taulukoihin arvot siirretään koodissa. Liukuluvuilla siirto tapahtuu vieläpä arvo kerrallaan.

    Äänestä

mj[strlen(mj)-1]='\0';

Eli etsi merkkijonosta '\0' ja sijoita siihen kohtaan '\0'.


strlen toimii siten että se laskee merkkejä siihen asti että se törmää loppumerkkiin '\0'.


ps. mallocin sijaan käyttäisin callocia, joka varaa muistin ja alustaa sen nollalla.

Äänestä
  • koska fgets() funktio lukee stdin:ä niin mukaan tulee rivinvaihtomerkki. Eli siitä yritin päästä eroon.. olisiko se sitten pitänyt olla:

    mj[strlen(mj)-2]='\0';

    Äänestä

  • jumissa kirjoitti:

    koska fgets() funktio lukee stdin:ä niin mukaan tulee rivinvaihtomerkki. Eli siitä yritin päästä eroon.. olisiko se sitten pitänyt olla:

    mj[strlen(mj)-2]='\0';

    Joko
    - poista koko rivi mj[strlen(mj)-1]='\0';
    - tai muuta aikaisemmat char mj[MAX 2]; fgets(mj,MAX 2,stdin);

    Äänestä

  • test kirjoitti:

    Joko
    - poista koko rivi mj[strlen(mj)-1]='\0';
    - tai muuta aikaisemmat char mj[MAX 2]; fgets(mj,MAX 2,stdin);

    Eli ilmeisesti tuo fgets ottaa enterin painalluksen yhdeksi merkiksi. Eli jos siis syötän kissa, niin minulla on tällainen merkkijonotaulukko:

    0:k 1:i 2:s 3:s 4:a 5:\n 6:\0

    eli eikös tämä minun alkuperäinen rivini:
    mj[strlen(mj)-1]='\0';

    toimi juuri niin että se poistaa tuon enterin painalluksen eli rivinvaihdon ja korvaa sen loppumerkillä '\0'? tätä ajoin tuossa takaa.

    Äänestä

  • jumissa kirjoitti:

    Eli ilmeisesti tuo fgets ottaa enterin painalluksen yhdeksi merkiksi. Eli jos siis syötän kissa, niin minulla on tällainen merkkijonotaulukko:

    0:k 1:i 2:s 3:s 4:a 5:\n 6:\0

    eli eikös tämä minun alkuperäinen rivini:
    mj[strlen(mj)-1]='\0';

    toimi juuri niin että se poistaa tuon enterin painalluksen eli rivinvaihdon ja korvaa sen loppumerkillä '\0'? tätä ajoin tuossa takaa.

    Riippuen onko harkkatyöhön automaattitarkastin, joka katsoo rivivaihdot, jolloin rivivaihto täytynee poistaa. Jos ei niin, ei tuo rivinvaihto pahalta näytä.
    Jos päätät poistaa rivinvaihdon, niin sulla oli alussa tekstinä max 20 merkkiä. Tällöin se ei pidä paikkaansa, vaan joudut muuttamaan ne kaksi riviä.

    Äänestä

  • test kirjoitti:

    Riippuen onko harkkatyöhön automaattitarkastin, joka katsoo rivivaihdot, jolloin rivivaihto täytynee poistaa. Jos ei niin, ei tuo rivinvaihto pahalta näytä.
    Jos päätät poistaa rivinvaihdon, niin sulla oli alussa tekstinä max 20 merkkiä. Tällöin se ei pidä paikkaansa, vaan joudut muuttamaan ne kaksi riviä.

    joo eli se MAx 2 taulukon kooksi.

    Tämä alkaa mennä jo vähän naurettavaksikin kysellä kyseisestä asiasta näin paljon, mutta haluan tämän ymmärtää perusteellisesti. Toivottavasti ymmärrystä riittää siellä päässä :)

    Eli siis jos mulla on kaksi merkkijonoa esim vaikka
    mj='kissa'
    mj2='kala'

    niin sitten kun yhdistän nuo ja en ole poistanut sitä rivinvaihtomerkkiä, niin eikö se haittaa jos minulla on kissa\nkala eikös tuo tuotos ole tavallaan väärin? tietenkin riippuu mitä haetaan, mutta jos pyritään yhdistämään vaikka kaksi nimeä tms...

    Äänestä

  • jumissa kirjoitti:

    joo eli se MAx 2 taulukon kooksi.

    Tämä alkaa mennä jo vähän naurettavaksikin kysellä kyseisestä asiasta näin paljon, mutta haluan tämän ymmärtää perusteellisesti. Toivottavasti ymmärrystä riittää siellä päässä :)

    Eli siis jos mulla on kaksi merkkijonoa esim vaikka
    mj='kissa'
    mj2='kala'

    niin sitten kun yhdistän nuo ja en ole poistanut sitä rivinvaihtomerkkiä, niin eikö se haittaa jos minulla on kissa\nkala eikös tuo tuotos ole tavallaan väärin? tietenkin riippuu mitä haetaan, mutta jos pyritään yhdistämään vaikka kaksi nimeä tms...

    Oot ymmärtäny täysin oikein. Jos ei tajuu jotain, niin on todellakin hyvä kysellä. C:ssä jos perusasioita ei tajua, ohjelmointi ei avaudu ja varmasti tympäsee.
    Tottakai jos halutaan yhdistää 'Etunimi' ja 'Sukunimi', niin tarvitaan jokin erotinmerkki. Jos tehtäisiin ohjelmaa Windowsin graaffiseen käyttöliittymään, rivinvaihtomerkki saattaisi näkyä laatikkomerkkinä, jolloin voisi sanoa, että '\n' -merkkiä ei saa käyttää.
    Sun esimerkissäs toi 'kissakala' ei tarvii erotinmerkkiä, jolloin mahdolliset rivinvaihdot on poistettava.

    Äänestä

  • test kirjoitti:

    Oot ymmärtäny täysin oikein. Jos ei tajuu jotain, niin on todellakin hyvä kysellä. C:ssä jos perusasioita ei tajua, ohjelmointi ei avaudu ja varmasti tympäsee.
    Tottakai jos halutaan yhdistää 'Etunimi' ja 'Sukunimi', niin tarvitaan jokin erotinmerkki. Jos tehtäisiin ohjelmaa Windowsin graaffiseen käyttöliittymään, rivinvaihtomerkki saattaisi näkyä laatikkomerkkinä, jolloin voisi sanoa, että '\n' -merkkiä ei saa käyttää.
    Sun esimerkissäs toi 'kissakala' ei tarvii erotinmerkkiä, jolloin mahdolliset rivinvaihdot on poistettava.

    Okei, eiköhän asia mennyt nyt aika hyvin jakeluun. Kiitos vielä paljon sulle vaivannäöstä!

    Äänestä

Kommentoi aloitusta


jumissa kirjoitti:

Eli tehtävän anto on: Kirjoita funktio, joka etsii merkkijonosta tiettyä merkkiä.

Funktiolle annetaan parametreina merkkijono ja merkki. Funktio palauttaa arvonaan osoittimen merkkijonon ensimmäiseen sellaiseen merkkiin, jota etsitään. Ellei etsittävää merkkiä löydy, funktio palauttaa arvon NULL.

Kirjoita funktiolle myös käyttöympäristö eli pääohjelma, josta kutsut sitä.
--------------------------------

Ongelmani on että en ymmärrä täysin tuota muistinvarausta. Eli kun käännän seuraavan ohjelman gcc:llä linuxissa, niin ohjelma kääntyy, mutta ohjelmaa ajettaessa tulee ilmoitus "muistialueen ylitys". Tämä siis tulee heti kun olen syöttänyt kysyttävän merkin.

Löytyisikö joltakin ystävälliseltä sielulta apuja, että tietäisin missä kohdassa koodiani mennään metsään? Kiitos.

Tässä yritelmäni:


#include
#include
#define MAX 20

char *merkkijono(char *mjono, char merkki);

int main(void){
char mj[MAX 1];
char m,*ptr;

printf("Anna merkkijono (max %d merkkiä): ",MAX);
fgets(mj,MAX 1,stdin);
mj[strlen(mj)-1]='\0';

printf("Anna merkki: ");
scanf("%c",&m);

ptr=(char *)malloc( sizeof (char) );

ptr=merkkijono(mj,m);

printf("\nMerkkijono: %s\n",*ptr);

free(ptr);

return 0;

}

char *merkkijono(char *mjono, char merkki){

while ((*mjono != '\0') && (*mjono != merkki )){
    mjono ;
}

if (*(mjono) == '\0') { return NULL; }

else{

return mjono;

}
}

Anonyymi
5000

Ilmoita asiaton sisältö

  • Sisältää materiaalia, joka on loukkaavaa, herjaavaa, rasistista, uhkailevaa tai ahdistelevaa.

  • Materiaali sisältää nimiä, yhteystietoja tai muita henkilökohtaisia tietoja. Julkisuuden henkilöistä, julkisissa viroissa toimivista ihmisistä sekä yritysten vastuuhenkilöistä saa keskustella työhön liittyen. Myös yksityiselämään liittyvistä asioista voi keskustella siltä osin, kuin niistä on julkisesti kerrottu.

  • Sisältää lapsille haitallista tai heiltä kiellettyä materiaalia. Seksuaalinen sisältö on sallittua aiheeseen tarkoitetuilla palstoilla, joiden ikäraja on 18 vuotta.

  • Lainvastaista sisältöä voi olla mm. yksityiselämää loukkaavan tiedon levitys, kiihottaminen kansanryhmää vastaan, laiton uhkaaminen, alaikäisiin liittyvä seksuaalinen sisältö/grooming, petokset, identiteettivarkaudet, kunnianloukkaukset ja tekijänoikeusrikkomukset.

  • Sisältö ei liity palstan tai keskusteluketjun aiheeseen.

  • Viesti ei ole suomea tai ruotsia (pl. International Forums), se sisältää mainontaa, se sisältää tekijänoikeuksin suojattua materiaalia, se on massapostitus tai jokin muu syy.

Jaa keskustelu