Siis sellainen pulma, että haluan tehdä ohjelman, jossa syötetään arvoja taulukkoon siten, että käyttäjä ensin aluksi määrittelee, montako arvoa syötetään.
Ohjelman siis tulisi kysyä esim "Montako arvoa annetaan?", jolloin käyttäjä voi antaa haluamansa luvun kuvaamaan syötettyjen arvojen määrää.
Mutta miten saan tuon annetun luvun taulukon alkioiden määräksi? Onko se yleensä mahdollista?
Ohjelman siis tulisi kysyä esim "Montako arvoa annetaan?", jolloin käyttäjä voi antaa haluamansa luvun kuvaamaan syötettyjen arvojen määrää.
Mutta miten saan tuon annetun luvun taulukon alkioiden määräksi? Onko se yleensä mahdollista?
Vastaukset 13
Vanhimmat
Tuo tarkoittaa sitä, että ois varmaankin käytettävä jotain malloc:in tapaista.
int*pi;
pi=malloc(arvoja*koko);
koko riippuu mitä lukuja tallennat:
- int/long/float -> 4
- double,int64 -> 8
Kannattaa tehdä tsekkaus ettei käyttäjä anna liian suurta/pientä lukua. Hyvät rajat varmaanki ois 0
"- int/long/float -> 4
- double,int64 -> 8 "
Tämä *ei* pidä yleisesti paikkaansa. Oikea tapa on käyttää sizeof()-funktiota koon selvittämiseksi (vai onko se makro, en tiedä).
"Kannattaa tehdä tsekkaus ettei käyttäjä anna liian suurta/pientä lukua. Hyvät rajat varmaanki ois 0
>- int/long/float -> 4
>- double,int64 -> 8
>Tämä *ei* pidä yleisesti paikkaansa
Ei pidäkään. int ja long ovat ennen muinoin olleet 2 -tavuisia. Mutta silti jaksan väittää, että veikatut koot pitävät paikkansa tämän harkkatyön tekijälle. Itse en käyttele sizeof -operaattoria C:n tietotyypeille. Kun kokoihin tulee muutoksia, lähes 100% kirjoittamistani pätkistä on muutenkin tarpeettomia. Täytyyki testailla nyt ku Vistan eka versio on ilmestyny X64 ohjelmii.
>Kannattaa tehdä tsekkaus ... 0
En jaksa edes rueta inttämään näin selvästä asiasta. Minä antaisin rankalla kädellä miinuksia esittämistäsi rajoituksista. Tällaiset harjoituksen tarkoitus on opettaa pärjäämään tilanteissa, joissa ei voida tehdä mitään oletuksia vaan joudutaan varaamaan tilat dynaamisesti.
"niin varmasti se joka arvostelee harkkatyön, ymmärtää jo pienemmälläki määrällä toimiiks koodi vai ei."
Luuletko tosiaan, että harkkatyöt arvostellaan ja testataan käsin? Esim. yliopistoissa voi kurssilla olla useita satoja opiskelijoita ja on selvää, että tällöin ohjelmat testataan koneella ja voit olla varma, että syötettä tuupataan tällöin runsaasti.
Kieltämäti tuli kärjistettyä vähän. Mut ku oon tehny parille koululle semmoisen tarkistussoftan, niin tiiän ettei tuu kateltua päätyyppien kokoja läpi. Tavallinen oppilas ku menee lankaan jo osoittimissa, ym. perusjutuissa.
Mitä tohon syötteen tarkasteluun tulee, ni oon yrittäny toitottaa, et tekisivät tehtävänannot niin, ettei kaikkia rajoituksia annettais valmiiks. Sillä selvii paremmin osaaks ajatella ite laisinkaan. Esim. jos kysytään määrää ja syöte on -1 ja koodi on malloc(-1*4), niin muistihan loppu heti. Toinen on, et annetaan tarpeeks suuri luku. Ainaki versiossa, jonka väänsin, oli varmistukset kaikenlaisille syötteille. Tietty, jos koulun taso on niin heikko, ettei huippupisteitä saa tarpeeks moni, jotain täytyy jättää huomioimatta.
Täytyy varmaanki seuraavaan versioon panostaa, ja katella semmonen 16 bittinen kääntäjäpaketti. Kiitti vinkistä ;)
Taulukon koko pitää määritellä käännösaikana C-kielessä, jos sen haluaa laittaa []-merkkien väliin. (On joitain tapauksia, missä ei tarvitse.)
Sen sijaan malloc-nimisellä funktiolla voi varata haluamansa määrän muistia ajon aikana. Halusta riippumaton on se, paljonko koneella sitä on tarjota. Jokin yläraja on.
Myöhemmin käytetty muisti pitää vapauttaa free-kutsulla, jos ei tee ihan lyhyttä kerran ajettavaa ohjelmaa. Luepa siis oppaastasi free- ja malloc-funktioiden kuvaus ja etsi ohjeita niiden käytöstä. Voit kysyäkin lisää.
C :lla voit käyttää valmista tietorakennetta STL-kirjastosta. Vector tai List on hyvä tähän käyttöön ja eron huomaa vasta isommilla aineistoilla kuin yhdellä istumalla syötettävillä.
Dynaaminen muistinvaraus on tärkeä tekniikka. Se kannattaa opetella hyvin.
/*olet paattanyt kutsua taulukkoasi Taulukoksi*/
/*taulukko pitaa ensin esitella, etta sita voi kayttaa*/
int* Taulukko;
/*nykyaikaisessa windows-ymparistossa ei pitaisi olla*/
/*mitaan syyta kayttaa komentorivia kayttoliittymana*/
/*mutta siita huolimatta olet tata ennen lukenut*/
/*kayttajan komentoriville syottaman yksiulotteisen*/
/*taulukon koon muuttujaan TauKoko*/
/*seuraavaksi alustetaan taulukko ilmoitettuun kokoon*/
Taulukko=new int[TauKoko];
/*alustetaan ihan huvikseen taulukon kaikki alkiot nolliksi*/
for(int TauIndeksi=0; TauIndeksi < TauKoko; TauIndeksi )
Taulukko[TauIndeksi]=0;
/*taulukon alkioon Taulukko[TauKoko] ei kannata koskaan osoittaa*/
Joo, noihan sen voi C :lla tehdä. Mitähän kieltä tässä haettiin.
Kiitos kaikille tähän saakka kommentoineille. :) Hieman täsmällisemmin tarkoittamastani määrittelystä:
Ohessa on pätkä ohjelmaa:
------------------------------------
void main(void)
{
int taulu[], num = 0 ;
printf("Montako tapahtumaa?\n\n:");
scanf("%d", & num);
---------------------------------------
Tarkoituksena siis on saada tuo int-tyypin muuttuja num taulukon "taulu" koon määreeksi.
Tiedän, että vakion voi liittää suoraan koon määreeksi kun kirjoittaa vakion nimen taulukon hakasulkeiden sisään. Tuollaisten muuttujien kanssa en ole onnistunut vastaavassa.
Olen aika vähän ohjelmoinut joten en tunne kovin kaksisesti mallocia. Joka tapauksessa tuossa siis täsmällisempi ongelmamäärittely.
Kuten tässä on jo useamman toimesta vastailtu:
C -kielellä, jonka harkkatyötä teet, ei tuohon pysty. Hakasulkujen sisään kirjoittaminen vaatii, että annat koon jo ennakkoon.
Muuta siis:
int taulu[] -> int*taulu ja muuta num -muuttaja etumerkittömäksi (malloc vaatii etumerkittömän kokonaisluvun). Joudut muuntamaan myös scanf:n %d -> %u
Koodissa muistinvaraus:
taulu=malloc(num*sizeof(int));
.
:
free(taulu);//ja varauksen poisto
Kiitos vastauksesta! :) Pari uutta kysymystä tuli mieleeni siitä:
"Kuten tässä on jo useamman toimesta vastailtu:
C -kielellä, jonka harkkatyötä teet, ei tuohon pysty."
Aha! Taisi jäädä tajuamatta tuo aiemmin.
"int taulu[] -> int*taulu "
Tarkoittaako tuo, että taulukkomuuttuja "taulu" tulee osoittimeksi?
"Koodissa muistinvaraus:
taulu=malloc(num*sizeof(int));
.
:
free(taulu);//ja varauksen poisto "
Tuossa vähän on toiminta jäänyt itseltä ymmärtämättä. Siksipä kysynkin vielä: Mikä tuo int-määritelmä on tuon sizeof-funktion parametrina? Onko se jokin arvo jonka määrittelen itse ohjelmassa? Muu?
Entä miten kauan (ohjelman koko suorituksen ajan?) tuo varaus on voimassa ennen kuin ohjelma poistaa sen?
""int taulu[] -> int*taulu "
Tarkoittaako tuo, että taulukkomuuttuja "taulu" tulee osoittimeksi? "
Osoitinaritmetiikka on vähän hankala sisäistettävä. Periaatteessa int taulu[] ja int *taulu ovat melkein sama asia, mutta eivät aivan. Jos teet määrittelyn "int taulu[5]", niin taulu on periaatteessa constant muuttuja, joka osoittaa muistipaikkaan, josta alkaa viiden alkion pituinen int-rivi. Jos taas määrittelet "int *taulu", niin taulu on muuttuja, joka osoittaa johonkin muistipaikkaan.
Määrittelyssä "int *taulu" voi sitte varata muistia malloc:lla ja laittaa taulu-muuttujan osoittamaan siihen kohtaa mistä mallocin muistinvaraus alkaa. Näin saat käyttöösi dynaamisesti varattua muistia.
Määrittelyssä "int taulu[5]" et voi asettaa taulu:lle mitään arvoa, se osoittaa aina samaan muistipaikkkaan. Eli operaatiot "taulu=toinentaulu" ja "taulu " eivät ole sallittuja.
[piti oikein luntata K&R:stä miten se menikään :) jos kirja on saatavilla, niin kurkkaa kappaletta 5.3]
"Mikä tuo int-määritelmä on tuon sizeof-funktion parametrina? Onko se jokin arvo jonka määrittelen itse ohjelmassa? "
Se int on tyyppi. Aivan kuin voit määritellä muuttujan "int k", niin voit käyttää int-sanaa sizeof:n parametrina. Kyseessä on eräs C:n varattu sana, eikä sitä tarvitse, eikä saakaan, esitellä tai mitään.
sizeof(int) palauttaa int-tyypin (tyyppisen muuttujan tarviman muistin määrän) koon sillä alustalla, missä olet koodailemassa.
"Entä miten kauan (ohjelman koko suorituksen ajan?) tuo varaus on voimassa ennen kuin ohjelma poistaa sen?"
Kunnes se poistetaan tai ohjelman ajo loppuu. Erityisesti jos teet muistivarauksen funktiossa, mutta et poista sitä vaan palautat suorituksen kutsujalle, niin se varaus jää ja tulee muistivuoto. Jos teet
void funktio(int k,..) {
int *t;
t = malloc(k*sizeof(int));
if(..
return;
}
free(t);
return;
}
Jossa on vain yksi free-kutsu, niin jos suoritus palautuu aiemmalla return:lla, niin tapahtuu muistivuoto. Seuraavalla funktion kutsulla malloc varaa taas uuden muistialueen jne.
Jos haluat osoittaa taulukkoon käytä int*taulu. Jos taas haluat perustaa taulukon käytä int taulu[5] tai int taulu[]={0,1,2,3,4}. Tuo int taulu[] -tapausta ilman alustusta ei kannata sotkea minnekään, kun se vaan mutkistaa liikaa ajatusten kulkua.
'Kiva tietää' -osastolta:
sizeof,cast ja erikoismerkkejä (esim.aritmeettiset ja vertailumerkit) nimitetään C:ssä operaattoreiksi. Lisäksi C:ssä on #define -direktiivillä (esiprosessorikäskyllä) määriteltyjä makroja, joita ei kutsuta funktioiksi vaikka ovatkin samannäköisiä.
Aiemmin tässä keskustelussa oikasin vähän mutkia, kun annoin muuttujien päätyyppien koot valmiiksi (en viitsi laittaa tähän keskustelupalstalle sotkemaan miten koodi pitäisi kirjoittaa, jotta sitä voisi käytellä useammassa ympäristössä). Yksi tapa saada edes osa koodista toimivaksi monessa ympäristössä, on käytellä aina suoran koon sijaan operaattoria sizeof. int -tyypille sizeof(int) kääntäjä saattaa antaa lopputuloksena 4. Operaattoreiden ja makrojen tulokset ovat siis c-kääntäjäohjelmien työ.
Muistivaraus pysyy voimassa niin kauan kunnes vapautat varauksen. Joissain ympäristöissä muistivaraukset eivät poistu, vaikka ohjelma loppuisikin. Siksi on tärkeätä muistaa käyttää sitä free -toimintoa.
Jos tekisit ohjelmaasi hyötykäyttöön, suosittelisin että:
- varmistaisit, ettei käyttäjä anna liian suurta määrä tilavaraukseksi
- ettei malloc palauta nollaa (muisti loppu) if(taulu==NULL)...