Seuraa 
Viestejä29006

Juu sitä vaan että tässä ihmettelen kouluhommia tehdessä, että eikö c-kielellä kun yrittää saada asioita toimimaan, taulukon palauttaminen aliohjelmasta pääohjelmaan olekaan niin simppeli asia kuin ensiksi ajattelisi.

Tässä on siis kaksi taulukkoa pisteet ja paikat. Pisteidensijoitusfunktiossa pisteet sijoitetaan taulukkoon. Tässä nyt yksinkertaisuuden vuoksi näin. Ongelma on nyt siinä, että paikat-taulukko pitäisi saada sisältöineen pääohjelmaan josta se sitten lähtee lappu-funktioon printattavaksi.
Alla oleva koodi toimii riittävästi muuten paitsi tuon taulukon palauttamisen osalta. Miten sen pitäisi tapahtua? Onko se edes mahdollista kovin suoraviivaisesti?

[code:20fxhgkm]#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"

char lappu(char paikat[2][2]);
char pisteiden_sijoitus(char pisteet[2]);

int _tmain(int argc, _TCHAR* argv[])
{
char pisteet[2];
char paikat[2][2] = {{'q', 0},
{'w', 0}};

pisteet[0] = 2;
pisteet[1] = 3;

paikat[2][2] = pisteiden_sijoitus(pisteet); //????????????????????

lappu(paikat);

return 0;
}

char pisteiden_sijoitus(char pisteet[2])
{

char paikat[2][2] = {{'q', 0},
{'w', 0}};

printf("SIJOITETAAN\n");

paikat[0][1] = pisteet[0];
paikat[1][1] = pisteet[1];

return paikat[2][2]; //?????????????????????
}

char lappu(char paikat[2][2])
{

printf("ykköset %c %d\n", paikat[0][0],paikat[0][1]);
printf("kakkoset %c %d\n", paikat[1][0],paikat[1][1]);

return 0;
}
[/code:20fxhgkm]

Kun en oo ennen tämmöstä tehny ni en tiä.

Sivut

Kommentit (145)

abskissa
Seuraa 
Viestejä3654

Mihin viittaa

[code:3kb6sdo8]paikat[2][2][/code:3kb6sdo8]

jos paikat-taulukko on vain 2*2-mittainen? Etkös nyt ole palauttamassa taulukon alkiota, etkä taulukkoa tai siihen sojoittavaa pointteria?

We're all mad here.

Ertsu
Seuraa 
Viestejä7415

Koita nyt harjoitustyönä suunnitella sähköauto, ettei tarvi Suomessa rakentaa Norjassa suunniteltuja sähköautoja. Suomi on pullollaan insinöörejä, mutta mitään ei osata suunnitella.

Sisältö jatkuu mainoksen alla
Sisältö jatkuu mainoksen alla
Kosh
Seuraa 
Viestejä21228

Sinulla on tuo char paikat[][]-taulukko esitelty funktiossa joten se on voimassa vain siellä (skooppi). Returnlausekkeesi palauttaa puolestaan sen sisällön, joka on/olisi taulukon [2][2] -alkiossa, jota tosin ei ole edes olemassa koska alustus varaa vain kaksi pykälää kummassakin dimensiossa ja nollan ollessa ensimmäinen, tuo viittaa kolmanteen molempien suhteen.

Pikku googletus auttaa: http://stackoverflow.com/questions/8144 ... array-in-c

Se oli kivaa niin kauan kuin sitä kesti.

abskissa
Seuraa 
Viestejä3654

Niin, ilmeisesti olisi tarkoituksena palauttaa se taulukko:

[code:1x4wc7bt]return paikat;[/code:1x4wc7bt]

ja sijoittaa palautettu taulukko muuttujaan:

[code:1x4wc7bt]paikat = pisteiden_sijoitus(pisteet);[/code:1x4wc7bt]

Paikat-taulukon alustus pääohjelmassa näyttää tuon sijoituksen jälkeen aikas turhalta.

Pisteiden sijoitus -aliohjelman paluutyyppi ei voi olla char. Ethän halua palauttaa yksittäistä merkkiä? Paluutyypin pitäisi kai olla char* tms -- C:ssä ei muistaakseni voi palauttaa taulukkoa.

(Tällä vuosituhannella C:llä ohjelmoineet voivat korjata jos olen pahasti väärässä.)

We're all mad here.

char pisteiden_sijoitus(char pisteet[2])
{

char paikat[2][2] = {{'q', 0},
{'w', 0}};

printf("SIJOITETAAN\n");

paikat[0][1] = pisteet[0];
paikat[1][1] = pisteet[1];

return paikat[2][2]; //?????????????????????
}
[/code:1cig09u4]

Koetat palauttaa taulukon char-muuttujaan?

Eikö funkkarin pitäisi olla char[][] pisteiden_sijoitus(char pisteet[2]) tms.?

Sorry, c-ohjelmoinnista on viitisen vuotta aikaa.

CE-hyväksytty
Seuraa 
Viestejä29006

Joo ei voi näköjään sitten palauttaa taulukkoa suorilta juu. Koshin linkissä oli jotain mitä tarttee sitten koittaa. Pitää vaan vähän ensin opiskella että mitä ne tarkoittaa.

Varsinaisessa koodissa niitä palaitettavia alkioita on 18 niin ajattelin että olis hyvä jos niitä sais kätevästi yhtenä könttinä siirreltyä.

Kosh
Seuraa 
Viestejä21228

Taulukkohan on C-kielessä oikeastaan pseudotietorakenne. Se on koodarille näppärä abstraktio mutta oikeastaan vain pointteriaritmetiikkaa. Niinpä esim. funktio ei voi palauttaa taulukkoa. Sen sijaan pointteri taulukkoon tai mihin tahansa muistialueeseen luonnollisestikin voidaan palauttaa. Toinen vaihtoehto on määritelty tietorakenne, joka voi sisältää myös määritellyn kokoisia taulukoita tai pointtereita taulukoihin.

Pointtereiden kanssa tosin on suhteellisen yksi lysti palauttaako funktio itse varaamansa muistialueen pointteri vaiko annetaanko sille kutsujan suunnasta pointteri jota funktio saa käpälöidä. Hyvien tapojen mukaista ehkä olisi että varaus ja vapautus tehdään samassa koodifilussa/funktiossa/moduulissa/skoopissa jos suinkin mahdollista, niin helpottaa debuggausta. Eli siis paluuarvojen taulukon pointteir tulisi antaa funktiokutsun parametrina. Mutta tarvittaessa funktio voi allkoida uuden muistialueen ja tämä tulee kyseeseen ainakin jos paluuarvon kokoa ei ennalta voida tietää.

Esimerkiksi esittely char[2] merkkitaulukko; on sama asia kuin char* merkkipointteri sillä erotuksella, että ensimmäisessä tapauksessa myös tarvittava kahden slotin muistialue datalle varataan staattisesti jo käännösvaiheessa, kun taas jälkimmäisessä ei, vaan pointteriin voidaan sijoittaa jokin muu muistiosoite tai varata dynaamisesti muisti mallocilla. Sama asia ne ovat siis ohjelman toiminnan kannalta. Koodissa on ok kirjoittaa merkkipointteri[1] tai merkkitaulukko[1]. Tuo []-operaattori kertoo vain että montako varatun perusalkion kokoista pykälää eteenpäin pointterin/taulukon alusta hypätään datan lukemiseksi. Vastaavasti myös voidaan käyttää esim merkkipointteri+1 ja merkkitaulukko+1 jotta saadaan taulukon korkeampien indeksien osoitteet.

Pointterit ovat C-kielen aluksi ehkä hankalin konsepti mutta niistä on myös suurin hyöty jos ne kunnolla osaa. Tässä on hyvä opastus pointtereihin: http://www.eskimo.com/~scs/cclass/notes/sx10b.html

Se oli kivaa niin kauan kuin sitä kesti.

Simplex
Seuraa 
Viestejä3231

Yleinen tapa on käsitellä taulukkoa pointterina (itse asiassa taulukon nimi itsessään on jo pointteri), ja välittää ainoastaan pointteri alkuperäiseen taulukkoon funktion parametrilistassa:

[code:3q2p7d1b]
#include

void sijoitus(int pisteet[2], int paikat[2][2])
{
paikat[0][0] = pisteet[0]+1;
paikat[0][1] = pisteet[0]+2;
paikat[1][0] = pisteet[1]+3;
paikat[1][1] = pisteet[1]+4;
}

int main()
{
int points[2] = {5, 6};
int places[2][2] = {0};
printf("points: %d %d\n", points[0], points[1]);
sijoitus(points, places);
printf("places: %d %d\n", places[0][0], places[0][1]);
printf("places: %d %d\n", places[1][0], places[1][1]);
}
[/code:3q2p7d1b]

CE-hyväksytty
Seuraa 
Viestejä29006

Joo mä oon monta vuotta mikrokontrollereita omiin leluihin ohjelmoidessa onnistunu välttelemään noita pointtereita mutta ehkä se on nyt sitten tullut aika opetella. Toi structi täytyy pitää mielessä myös. Se on varmaan isompien kokonaisuuksien siirtelyyn kätevä? Mutta ei kai hyvä jos muistia on säästeltävä?

abskissa
Seuraa 
Viestejä3654

Struct taitaa olla siinä huono, että sen sisältö todella kopioidaan funktiokutsuissa ("pass by value"). Muistin käytön kannalta se ei ole kovin kamalaa, ellei rakenne ole todella iso, mutta kopiointi syö jonkin verran arvokasta prosessoriaikaa. Pointterit ovat kevyitä.

We're all mad here.

Vierailija
Kosh

Mielestäni aihe, vaikkei minua kosketakaan, on mitä parhain aihe käytäväksi ilman googlettelua koska kuitenkin se on vähän sama kuin neuvoisi opiskelemaan suomen syntaksia googlella.

..Tai kuin pitäisi yhdyssanoja älykkyyden mittarina. Toki niiden puute kertoo sivistyksen tasosta, mutta sivistys on sosiaalista pääomaa.

Kosh
Seuraa 
Viestejä21228
abskissa
Struct taitaa olla siinä huono, että sen sisältö todella kopioidaan funktiokutsuissa ("pass by value"). Muistin käytön kannalta se ei ole kovin kamalaa, ellei rakenne ole todella iso, mutta kopiointi syö jonkin verran arvokasta prosessoriaikaa. Pointterit ovat kevyitä.



Totta. Struct on sopivin jos tietotyyppi aidosti on jonkinlainen yhdistelma natiivitietotyypeista, esim dynaamisesti varattu taulukko ja int joka pitaa kirjaa sen koosta tai useamman taulukon yhdistelma jne. Structiakin voi toki kasitella funktiokutsuissa pointterien avulla jolloin kopioiminen valtetaan. Structin kaytto vain taulukon kasittelyn helpottamiseksi ehka huono idea yleisessa tapauksessa.

Se oli kivaa niin kauan kuin sitä kesti.

Simplex
Seuraa 
Viestejä3231
CE-hyväksytty
Kun sen taulukon vieminen toiseen funkitioon onnistuu kumminkin ilman pointteria niin onko se rumaa olla käyttämättä yhtenäisyyden vuoksi niitä siinäkin?

C-kielessä taulukon nimi on jo itsessään pointteri, joten tuossa postaamassani esimerkissä funktioon itse asiassa annetaan parametrina kaksi pointteria. Samoin funktion sisällä taulukkoja käytetään itse asiassa pointtereina, vaikka se ei ihan äkkiseltään siltä näytäkään. Tiedän, että tämä on hieman sekavaa, mutta taulukot ja pointterit on C-kielessä hieman mustaa magiaa, joiden kanssa tulee ammuttua itseään jalkaan aina silloin tällöin. Tässä alla versio struct-tyylisesti toteutettuna:

[code:1nto4qiv]
#include

typedef struct
{
int pisteet[2];
} piste_t;

typedef struct
{
int paikat[2][2];
} paikka_t;

void sijoitus(piste_t* piste, paikka_t* paikka)
{
paikka->paikat[0][0] += piste->pisteet[0]+1;
paikka->paikat[0][1] += piste->pisteet[0]+2;
paikka->paikat[1][0] += piste->pisteet[1]+3;
paikka->paikat[1][1] += piste->pisteet[1]+4;
}

int main()
{
piste_t points = {5, 6};
paikka_t places = {1,2,3,4};
printf("points: %d %d\n", points.pisteet[0], points.pisteet[1]);
printf("places: %d %d\n", places.paikat[0][0], places.paikat[0][1]);
printf("places: %d %d\n", places.paikat[1][0], places.paikat[1][1]);
sijoitus(&points, &places);
printf("places: %d %d\n", places.paikat[0][0], places.paikat[0][1]);
printf("places: %d %d\n", places.paikat[1][0], places.paikat[1][1]);
return 0;
}
[/code:1nto4qiv]

CE-hyväksytty
Seuraa 
Viestejä29006
Simplex
CE-hyväksytty
Kun sen taulukon vieminen toiseen funkitioon onnistuu kumminkin ilman pointteria niin onko se rumaa olla käyttämättä yhtenäisyyden vuoksi niitä siinäkin?

C-kielessä taulukon nimi on jo itsessään pointteri, joten tuossa postaamassani esimerkissä funktioon itse asiassa annetaan parametrina kaksi pointteria. Samoin funktion sisällä taulukkoja käytetään itse asiassa pointtereina, vaikka se ei ihan äkkiseltään siltä näytäkään. Tiedän, että tämä on hieman sekavaa, mutta taulukot ja pointterit on C-kielessä hieman mustaa magiaa, joiden kanssa tulee ammuttua itseään jalkaan aina silloin tällöin. Tässä alla versio struct-tyylisesti toteutettuna:


Juu ymmärrän kyllä, mutta sinäkin ymmärrät varmaan mitä kysymykselläni tarkoitin. Eli että pitäisikö kaikkien muuttujien siirtelyissä joka suuntaan menetellä esteettisyyssyistä samalla tavalla?

Simplex
Seuraa 
Viestejä3231
CE-hyväksytty
Simplex
CE-hyväksytty
Kun sen taulukon vieminen toiseen funkitioon onnistuu kumminkin ilman pointteria niin onko se rumaa olla käyttämättä yhtenäisyyden vuoksi niitä siinäkin?

C-kielessä taulukon nimi on jo itsessään pointteri, joten tuossa postaamassani esimerkissä funktioon itse asiassa annetaan parametrina kaksi pointteria. Samoin funktion sisällä taulukkoja käytetään itse asiassa pointtereina, vaikka se ei ihan äkkiseltään siltä näytäkään. Tiedän, että tämä on hieman sekavaa, mutta taulukot ja pointterit on C-kielessä hieman mustaa magiaa, joiden kanssa tulee ammuttua itseään jalkaan aina silloin tällöin. Tässä alla versio struct-tyylisesti toteutettuna:


Juu ymmärrän kyllä, mutta sinäkin ymmärrät varmaan mitä kysymykselläni tarkoitin. Eli että pitäisikö kaikkien muuttujien siirtelyissä joka suuntaan menetellä esteettisyyssyistä samalla tavalla?



C-kielessä on vain kaksi tapaa välittää parametreja funktioille: "pass by value" ja "pass by pointer". C++ kielessä on vielä kolmas tapa ts. "pass by reference". Tsekkaa http://www.geekinterview.com/question_details/16844, missä on aika hyvä selitys asiasta.

C-kielessä useampiuloitteisen taulukon välittäminen parametrina on sen verran hankala tapaus, että sitä tulisi välttää viimeiseen asti. Yksiuloitteisen taulukon ts. vektorin käsittely ja välittäminen parametrina on sitävastoin ihan rutiinia ja varsin suoraviivaista.

Mitä tuohon yhteneväisyyteen tulee, niin olen samaa mieltä kanssasi, eli koodissa tulisi pyrkiä yksinkertaisuuteen, selkeyteen, yllätyksettömyyteen ja johdonmukaisuuteen.

MaKo71
Seuraa 
Viestejä1481
CE-hyväksytty
Emmää osaa...



Tuossa tuli jo muilta hyviä vinkkejä, ja lukaisin sitten tuon sun koodin ja koetin ymmärtää, mitä olet tekemässä. Tuota paikat -taulukkoa voit yksinkertaistaa structilla, jolloin saat siitä yksiulotteisen taulukon, koska kuten tuolla aiemmin todettiin, C ja moniulotteiset taulukot voivat olla hankala yhdistelmä.

Yleensä C:ssä taulukoita käsiteltäessä niitä ei palauteta funktiosta, vaan ne lähetetään funktiolle muokattavaksi, eli sun koodin tapauksessa vaikkapa näin:

[code:1pzhubz4]void pisteiden_sijoitus(char paikat[][2], char pisteet[])
{
...
}
[/code:1pzhubz4]

Taulukot toki yleensä lähetetään pointtereina, mutta toisinaan käytetään tuota yllä olevaa tapaa eli päällimmäinen dimensio jätetään tyhjäksi. Lisäksi yleensä lähetetään taulukkojen yhteydessä funktiolle tiedoksi taulukon pituus, C:ssä kun sitä ei saa automaattisesti selville.

Minä korjaisin koodia ensin niin, että tekisin paikat -taulukosta struct:n ja sitten lähettäisin pointtereina käsiteltäväksi:

[code:1pzhubz4]
typedef struct { char nimi; int pisteet; } PAIKKA;
...
int main()
{
PAIKKA paikat[2] = { { 'q', 0 }, { 'w', 0 } };
int pisteet[2] = { 1, 2 };
...
pisteiden_sijoitus(paikat, pisteet, 2);
...
}

void pisteiden_sijoitus(PAIKKA *paikat, int *pisteet, int pituus)
{
...
}
[/code:1pzhubz4]

MaKo71
Seuraa 
Viestejä1481
CE-hyväksytty
Juu sitä vaan että tässä ihmettelen kouluhommia tehdessä, että eikö c-kielellä kun yrittää saada asioita toimimaan, taulukon palauttaminen aliohjelmasta pääohjelmaan olekaan niin simppeli asia kuin ensiksi ajattelisi.



Niin, ja tähän sellainen juttu, että kyllä taulukon palauttaminen C:stä onnistuu. Esimerkiksi näin:

[code:3j41zulx]
int *funktio()
{
int *taulukko = malloc(sizeof(int) * 10);
return taulukko;
}
[/code:3j41zulx]

Mutta näin sitä ei pidä tehdä koskaan:

[code:3j41zulx]
int *funktio()
{
int taulukko[10];
return taulukko;
}
[/code:3j41zulx]

C ei tietenkään tuosta mitenkään valita, mutta tuossa taulukko on nyt varattu pinosta, ja kun funktiosta ollaan palattu, niin sitä ei tavallaan enää ole olemassa. Jos sitä tuon jälkeen käpistelee, niin jos on onnekas, saa segfaultin melko nopeasti, jos on epäonnekas, joutuu debuggaamaan tunteja, päiviä tai viikkoja etsiessään kaikenlaisia mystisiä vikoja.

Sivut

Suosituimmat

Uusimmat

Sisältö jatkuu mainoksen alla

Suosituimmat