Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C: Vektorin alustaminen calloc()-funktiolla?

Sivun loppuun

ongelma [24.03.2009 13:02:53]

#

Osaisikohan joku selittää miksi seuraava c-koodinpätkä ei toimi?
Haluaisin siis määritellä ja nollata vektorin käyttämällä calloc()-funktiota ja lukea siihen arvot tiedostosta. Homma toimii ongelmitta jos käytän nyt kommentoitua tapaa vektorin määrittelyyn, mutta kun pitäisi käyttää dynaamista muistinhallintaa.

#include <stdio.h>
#include <stdlib.h>
int main(){

    int koko = 5;
    double *vektori = calloc(koko, sizeof(double));
    //double vektori[koko];

    FILE *pointteri;
    pointteri = fopen("tiedosto.bin", "rb");
    fread(&vektori, koko*sizeof(double), 1, pointteri);

    int i;
    for(i = 0; i < koko; i++){
          printf("alkio %i: %lf\n", i+1, vektori[i]);
    }

    free(vektori);
    fclose(pointteri);
    return 0;
}

tneva82 [24.03.2009 13:17:19]

#

Sivustolla http://www.cplusplus.com/reference/clibrary/cstdlib/calloc.html näytettiin esimerkkinä:

int * pData;
printf ("Amount of numbers to be entered: ");
scanf ("%d",&i);
pData = (int*) calloc (i,sizeof(int));

Kokeiles vastaavasti tehdä tuo näin:

double *vektori = (double*)calloc(koko, sizeof(double));

Sain ainakin kääntymään ja ajamaan tuon kohdan ohi ilman virhettä. En tiedä ratkaiseeko mutta worth a try varmaan?

Ja laita ihmeessä tarkistus että tiedosto myös aukeaa :D Ilman sitä tulee kiva segmentation fault ;-)

Sisuaski [24.03.2009 13:18:50]

#

Varmaankin tämän rivin:

fread(&vektori, koko*sizeof(double), 1, pointteri);

pitäisi olla:

fread(vektori, koko*sizeof(double), 1, pointteri);

Tuossa vektori on osoitin, joka osoittaa muistialueeseen, jonne tiedoston sisältö halutaan lukea. &vektori taas on osoitin osoittimeen, eli sen lähettämisestä freadille tuskin seuraa mitään hyvää.

ongelma [24.03.2009 13:30:46]

#

tneva82 kirjoitti:

Sivustolla http://www.cplusplus.com/reference/clibrary/cstdlib/calloc.html näytettiin esimerkkinä:

int * pData;
printf ("Amount of numbers to be entered: ");
scanf ("%d",&i);
pData = (int*) calloc (i,sizeof(int));

Kokeiles vastaavasti tehdä tuo näin:

double *vektori = (double*)calloc(koko, sizeof(double));

Sain ainakin kääntymään ja ajamaan tuon kohdan ohi ilman virhettä.

Kokeiltu en, tyyppimuunnos ei vaikuta toimintaan. Ymmärtääkseni tyyppimuunnoksen tarve/tarpeettomuus riippuu kääntäjästä.

tneva82 kirjoitti:

Ja laita ihmeessä tarkistus että tiedosto myös aukeaa :D Ilman sitä tulee kiva segmentation fault ;-)

Juu tiedossa on. Kyse on isohkosta projektista jota en viitsinyt kokonaisuudessaan läväyttää tähän foorumille, siksi tässä vain ongelmani kannalta relevantti pätkä.

Sisuaski kirjoitti:

Varmaankin tämän rivin:

fread(&vektori, koko*sizeof(double), 1, pointteri);

pitäisi olla:

fread(vektori, koko*sizeof(double), 1, pointteri);

Tuossa vektori on osoitin, joka osoittaa muistialueeseen, jonne tiedoston sisältö halutaan lukea. &vektori taas on osoitin osoittimeen, eli sen lähettämisestä freadille tuskin seuraa mitään hyvää.

No nyt toimii, kiitos! Yllättäen taas vika johtuu ponttereista (tai siis käyttäjästä joka ei ole ihan sisäistänyt pointtereita).

Metabolix [24.03.2009 13:39:15]

#

C:ssä osoittimen tyyppimuunnosta ei tarvita.

Sisuaski osui ongelman ytimeen. Kysyjän koodin kommentoitukaan tapa ei toimi oikein, kyseessä on lähes oikeasta toiminnasta johtuva harha.

ongelma [24.03.2009 13:44:10]

#

Metabolix kirjoitti:

Sisuaski osui ongelman ytimeen. Kysyjän koodin kommentoitukaan tapa ei toimi oikein, kyseessä on lähes oikeasta toiminnasta johtuva harha.

Selitätkö vähän tarkemmin? Oon nimittäin taistellut asian kanssa pitkään ja hartaasti.

eq [25.03.2009 11:53:31]

#

ongelma kirjoitti:

Kokeiltu en, tyyppimuunnos ei vaikuta toimintaan. Ymmärtääkseni tyyppimuunnoksen tarve/tarpeettomuus riippuu kääntäjästä.

Jep, C-kielen speksejä noudattavat kääntäjät eivät tarvitse eksplisiittistä tyyppimuunnosta.

<ot> Jotkut kuitenkin suosittelevat sitä virheiden välttämiseksi, sillä sen avulla kääntäjästä on apua esimerkiksi seuraavassa skenaariossa:

//--
    short *a;
    a = malloc(size * sizeof(short));

Jaa, tarvitsenkin suurempia muuttujia:

//  short *a;
    int *a;
    a = malloc(size * sizeof(short));
    /* Mahdollinen virhe: a ei välttämättä osoita size-alkion kokoiseen muisti-
       alueeseen. Koodi on kuitenkin sinänsä oikein, joten kääntäjä ei valita;
       oikea määrittelemätön toiminta sattuu (jos sattuu) kun a:n viimeisiä
       alkiota käytetään */
//  Toisaalta:
    a = (short *)malloc(size * sizeof(short));
    /* Mahdollinen virhe: Myös kääntäjä huomauttaa asiasta */

Toiset (ml. minä itse) suosivat dereferointia koon selvittämiseksi dynaamisen muistinhallinnan kanssa (allaoleva on oikein, kunhan a on osoitin, muttei void*). Tämä säästää paljolta visuaaliselta tauhkalta varsinkin structien kanssa (toteutettavissa haluttaessa myös makroilla):

//--
    int *a;
    a = malloc(size * sizeof(*a));
/*  vertaa:
    tmp = (struct type_s *)malloc(size * sizeof(struct type_s));
    tmp = malloc(size * sizeof(*tmp));
*/

</ot>

//--
    int koko = 5;
    double vektori[koko];

Ylläoleva olisi väärin, koska koko ei ole (teknisesti) vakio, vaan nimenomaisesti muuttuja. Staattinen, tai automaattinen muistinhallinta vaatii koon tietämistä käännöshetkellä; koko on muistissa sijaitseva muuttuja, ei staattinen vakio. const-attribuuttikaan ei auta, sillä se on vain "vihje".

edit: sisennys

koodic näemmä hylkää kaiken whitespacen ennen ensimmäistä "ei-whitespace":a. Lieköhän tarkoituksenmukaista, kun esim. koodi ei näin tee.

Sisuaski [25.03.2009 14:50:24]

#

eq kirjoitti:

//--
    int koko = 5;
    double vektori[koko];

Ylläoleva olisi väärin, koska koko ei ole (teknisesti) vakio, vaan nimenomaisesti muuttuja. Staattinen, tai automaattinen muistinhallinta vaatii koon tietämistä käännöshetkellä; koko on muistissa sijaitseva muuttuja, ei staattinen vakio. const-attribuuttikaan ei auta, sillä se on vain "vihje".

C:ssä (eli C:n voimassa olevassa standardissa C99:ssä) kyllä muuttujen kokoiset staattiset taulukot ovat ihan sallittuja.

eq [25.03.2009 17:00:43]

#

Sisuaski kirjoitti:

C:ssä (eli C:n voimassa olevassa standardissa C99:ssä) kyllä muuttujen kokoiset staattiset taulukot ovat ihan sallittuja.

Tuli näemmä puhuttua aivan puutaheinää. Ylläoleva pätee siis (jotakuinkin) vain globaalilla tasolla (käsittääkseni myös C90:ssä funktioiden sisäiset "staattiset" taulukot voidaan luoda muuttujien koon mukaan). eq out.

Sisuaski [25.03.2009 18:31:37]

#

eq kirjoitti:

käsittääkseni myös C90:ssä funktioiden sisäiset "staattiset" taulukot voidaan luoda muuttujien koon mukaan

C90:ssä se on kiellettyä, mutta esim. GCC sallii ne.


Sivun alkuun

Vastaus

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

Tietoa sivustosta