Seuraa 
Viestejä29006
Liittynyt30.4.2005

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
Liittynyt9.10.2008

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ä6888
Liittynyt8.11.2007

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.

Kosh
Seuraa 
Viestejä21228
Liittynyt16.3.2005

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
Liittynyt9.10.2008

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
Liittynyt30.4.2005

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
Liittynyt16.3.2005

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ä3033
Liittynyt26.1.2010

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
Liittynyt30.4.2005

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
Liittynyt9.10.2008

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
Liittynyt16.3.2005
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ä3033
Liittynyt26.1.2010
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]

Sivut

Suosituimmat

Uusimmat

Uusimmat

Suosituimmat