Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C: Koulutehtävä: Yksinkertaiset tietorakenteet (Puhelinluettelo)

Sivun loppuun

Shooter99 [30.10.2012 23:32:33]

#

Moi!

Ok koulutehtäviä olen tässä mennyt taas eteenpäin ja seuraava olisi edessä.
Eli kyseessä on hitusen pidempi osainen tehtävä eli eka osa koostuu tästä ja ilmeisesti seuraavat kaksi tehtävää liittyy myös tähän samaan hommaan...

Eli loin c koodin kansioon tiedosto kokeilu.txt näin aluksi ja sinne lisäsin seuraavat tiedot.

4
Etunimi Sukunimi 050-3500980
Matti Meikäläinen 041-3478924
Brian Kottarainen 040-3980982
Brita Kottarainen 05-4567393

Nyt tilanne on se että minun pitäisi lisätä ko. tiedostoon etunimi sukunimi ja puhelinnumero.

Aloin kirjoittamaan koodia aloin miettimään että miten tuo olisi fiksuinta tehdä?

Kannattaisiko ekana avata tämä kokeilu.txt read moodiin ja tallentaa se koneen muistiin ja tämän jälkeen luoda kokonaan uusi tiedosto samalla nimellä periaatteessa ja lisätä sinne nämä tallennetut tiedot + uusi tieto ?

toinen kysymys liittyy koodin pätkään.

fgets(etunimi, 21, lue_data);
printf("%s", etunimi);

Olenko ymmärtänyt oikein että fgets hakee tiedostosta "etunimen" eli 21 ensimmäistä merkkiä mitä löytyy? vai tarkoittaako 21 että se lukee 21 ensimmäistä riviä ?

21 saan kaiken datan ulos mutta jos isonnan tai pienennän lukuarvoa niin kaikki menee ihan mössöksi...

Että tälläisiä kysymyksiä tällä kertaa.

User137 [30.10.2012 23:45:57]

#

Googlen eka tulos haulla fgets antaa tämmösen, toivottavasti englannin kieli ei ole ongelma:
http://www.cplusplus.com/reference/clibrary/cstdio/fgets/

lainaus:

Reads characters from stream and stores them as a C string into str until (num-1) characters have been read or either a newline or the end-of-file is reached, whichever happens first.

lainaus:

num
Maximum number of characters to be copied into str (including the terminating null-character).

Toisin sanoen sun pitäis kirjoittaa etunimi, sukunimi ja puhelinnumero omille riveilleen. On olemassa sukunimiä ja etunimiä jotka sisältää myös välilyönnin, joten et pysty sitä mitenkään erittelemään kaikki yhtenä pötkönä. Rivinvaihtomerkki on tuossa se avain.

edit: Tai no tietysti voi katkoa vaikka näin: Etunimi|sukunimi|puhelin

Othnos [31.10.2012 00:44:41]

#

Voitko User antaa esimerkin etu- tai sukunimestä, jossa olisi välilyönti?

Ohjelmointiputkan C-oppaassa on kohta, jossa on hieman sivuttu asiaa. Kyseinen rajoitus on varmaan syötetty samasta syystä, kuin oppaassa, ettei rivin pituus mene taulukon ylitse.

User137 [31.10.2012 02:59:59]

#

Suomenkielessä on vähemmän, ja useimmin nimet erotetaan viivalla. Kuitenkin joku saattaa kirjottaa "Ari - Pekka" ja silti tulla ymmärretyks. Tai ehkä kysytään kaikkia etunimiä. Ulkomaisia nimiä on ainakin tuolla listattu (tokihan Suomessa asuu ulkomaalaisiakin):
http://answers.yahoo.com/question/index?qid­=20090106050801AATRsWE

Hah, samalla sivulla linkattiin tuokin:
http://www.geekologie.com/2008/11/british-boy-legally-changes-na.php

Shooter99 [31.10.2012 09:25:53]

#

Ohjelmointiputkan c-oppaasta tämän fgets esimerkin löysinkin.
mutta eikö fscanf:llä voi periaatteessa tehdä saman homman ?

Lisäys:

Jaa no tämä taitaa olla oleellinen etu kumminkin fgetsissä..

Putkan c-oppaasta lainattu...
Kun käytetään funktiota gets, merkkijono luetaan kokonaan rivin loppuun asti, vaikka siinä olisi välilyöntejä.

jalski [31.10.2012 09:33:08]

#

Ehkäpä kannattaisi lukea ja kirjoittaa tietue kerrallaan rivin sijasta?

Aloittaisin tutustumalla fread() ja fwrite() funktioihin...

Joku C:n syntaksia ja standardikirjaston toiminnallisuutta minua paremmin muistava voisi ehkä antaa yksinkertaisen esimerkin?

Grez [31.10.2012 10:42:18]

#

Othnos kirjoitti:

Voitko User antaa esimerkin etu- tai sukunimestä, jossa olisi välilyönti?

Miksi juuri User137 pitäisi sellainen antaa?

Muutama suomalaisen julkisuuden henkilön sukunimi, jossa on välilyönti:
af Grann
von Hetrzen
von Bell

Shooter99 [31.10.2012 11:52:02]

#

Olen aloittanut nyt tätä koodia kirjoittamaan ja tälläistä olen tähän mennessä tehnyt.

#include <stdio.h>

int main(void){
    char etunimi[19+1], sukunimi[30+1], puhelinnumero[11+1];
    int i;
    FILE *lue_data;
    FILE *tall_data;

//    printf("Anna etunimi:");
//    scanf("%s", &etunimi[0]);
//    printf("Anna sukunimi:");
//    scanf("%s", &sukunimi[0]);
//    printf("Anna puhelinnumero:");
//    scanf("%s", &puhelinnumero[0]);

    lue_data = fopen("kokeilu.txt", "r");
    if(lue_data !=NULL){
        while (!feof(lue_data)){
        fgets(etunimi, 21, lue_data);
        printf("%s" , etunimi);
        //fgets(sukunimi, 31, lue_data);
        //printf("%s", sukunimi);
        //fgets(puhelinnumero, 12, lue_data);
        //printf("%d", puhelinnumero);
        }
        fclose(lue_data);
    }else{
        printf("Tää meni reisille!");
    }
    return 0;
}

Mitä tässä olen tarkoittanut tapahtuvan / olettanut.

1. Aluksi pyydetää etunimi, sukunimi ja puhelinnumero, sekä tallennetaa.
2. Mikä poistin käytöstä jotta voi tarkastella toimiiko tiedoston luku.
3. Sitten ajattelin että tiedosto luettaisiin ja tallennettaisiin muistiin.
4. Aluksi tein joka taulukolle oman fgetsin mutta poistin ne käytöstä.
5. Nyt siis mietin että miten saisin tämän koneen tietämään että monta riviä
tekstiä minun .txt tiedostossa jotta osaa lisätä seuraavalle vapaalle riville
uuden nimen. Kuten ekassa postissa ilmoitin niin tekstitiedoston alussa on
lukuarvo mikä vastaa rivien määrää, joten ajattelin että jos sen lukemalla
voisin ilmoittaa olemassa olevat rivit ja lisätä sitä lukuarvoa aina uuden
tallennuksen yhteydessä.

6. Koska .txt rivi siltää seuraavan tiedon
4
etunimi sukunimi puh.nro
etunimi sukunimi puh.nro
etunimi sukunimi puh.nro
etunimi sukunimi puh.nro
Niin mietin että pitääkö tässä nyt sitten tehdä homma niin että jos tuon
lukuarvon ottaa rivimäärälaskuriksi niin onko se 4+1 vai alkaako c-kieli
näissäkin laskemaan arvoja 0, 1, 2, 3, 4 jollain 4 olisi suoraan oikea luku.

fscanf komenolla varaman saisin tuon lukuarvon otettua tuolta tiedostosta ja
annettua sille jonkin arvon joka kasvaa ajojen mukaan tallentuu ekalle
riville aina kasvatettuna lukuna.

7. Kannattaisiko vaihtaa koodin fgetsin tuohon fread toimintoon.

Että tälläisiä mietteitä... Kertokaa nyt seuraavaksi että olenko jo pelkällä ajattelu tasolla menossa mettään pahasti, koodi saattaa olla menossa mutta sen voi korjata kuhan saa ajatuksen oikeaan suuntaan...

Grez [31.10.2012 12:32:37]

#

Eiköhän toi 4 oo tarkoitettu kertomaan, monenko henkilön tiedot siinä tiedostossa on - ei tiedoston kokonaisrivimäärää.

Shooter99 [01.11.2012 06:27:40]

#

Mutta eikö se ole sama asia loppupeleissä...
Riviä tai nimeä, kun uusi nimi tulee uudelle riville niin luku kasvaa...

Grez [01.11.2012 08:21:10]

#

No lähinnä kommentoin tuohon pohdintaasi
"jos tuon lukuarvon ottaa rivimäärälaskuriksi niin onko se 4+1 vai alkaako c-kieli
näissäkin laskemaan arvoja 0, 1, 2, 3, 4 jollain 4 olisi suoraan oikea luku."

Eli siis rivimäärälaskuriksi ajateltuna se on 4+1.

En tiedä yhtään ohjelmointikieltä joka laskisi (count, length tms) viisi riviä "neljäksi". Numerointi toki voidaan aloittaa mistä tahansa numerosta. Toki jos nuo rivit luettaisiin sellaisenaan taulukkoon, niin rivien numerot olisi 0-4, mutta silti niiden määrä olisi 5.

Shooter99 [01.11.2012 17:12:20]

#

Olipa tullut näköjään typo...
kyllähän jo sokeakin näkee paitsi minä että 0,1,2,3,4 = 5 lukua...

Pohdin siis sitä että onko 4 = 1,2,3,4 (4 riviä).
vaiko 0, 1, 2, 3, 4 = 5 riviä ( 4+1 ).

User137 [01.11.2012 20:38:02]

#

Jos taulukko on tyyliin luvut[5], niin siinä on 5 indeksiä 0, 1, 2, 3, 4. Jos tiedostoon on kirjoitettu 4 rivinvaihtoa, siinä on 5 riviä, joista viimeinen on tyhjä.

Sanottiinko tehtävänannossa että nimenomaan pitää samalle riville yhden henkilön tiedot kirjoittaa? Tiedostohan voi näyttää vaikka tältä:

2
Etunimi
Sukunimi
050-3500980
Matti
Meikäläinen
041-3478924

Luku onnistuu lukemalla ensin tuo määrä ekalta riviltä, ja sitten suunnilleen:

for (i=0; i<maara; i++) {
  fgets(etunimi, 20, lue_data);
  fgets(sukunimi, 31, lue_data);
  fgets(puhelinnumero, 12, lue_data);
  printf("%s %s %s\n", etunimi, sukunimi, puhelinnumero)
}

jalski [01.11.2012 23:19:55]

#

Mielestäni merkkijonojen huono toteutus on yksi C:n suurimpia puutteita. Nollatavu loppuisen char taulukon käyttäminen merkkijonon tallentamiseen oli käytännön syistä huono valinta.

Tämän tyyliseen työhön sopisivat paljon paremmin tarvittaessa tyhjillä merkeillä täytetyt kiinteän mittaiset merkkijonot.


Esimerkiksi PL/I:llä stream IO:lla lukisi tiedostosta yhden tietueen:

get file(tiedosto) edit(sukunimi, etunimi, puh)(A(16),A(16), A(12));

Record IO:lla voisi suoraan lukea tietue kerrallaan:

read file(tiedosto) into(tietue);

Kokeilin huvikseni toteuttaa puhelinluettelon (tosi ruman näköinen), jossa nimi toimii avaimena. Mukana oli tietueiden lisäys, etsiminen, poisto ja listaaminen aakkosjärjestyksessä. Tuohon sain uppoamaan hiukan alle 170 väljää riviä PL/I-koodia. C:llä rivimäärä olisi varmaan ollut ainakin viisinkertainen...

Metabolix [02.11.2012 07:58:15]

#

C-kieli ei tiedä riveistä sinänsä yhtään mitään (paitsi fgets-funktio osaa pysähtyä rivin loppuun). Toisin sanoen tiedoston rivejä ei ole C-kielessä millään tavalla numeroitu; jos saat tiedoston, et voi mitenkään automaattisesti tietää, montako riviä siinä on tai montako riviä on jo luettu, vaan molemmat pitää jotenkin itse selvittää.

Tässä tehtävässä tiedostosta on järkevää lukea fscanf-funktiolla ensin yksi luku ("%d") ja sen jälkeen for-silmukalla niin monta henkilöä ("%s %s %s", kolme sanaa). Siis ei pidä välittää riveistä vaan henkilöistä.

Shooter99 [03.11.2012 02:18:52]

#

Tätä mietinkin että pitäisi käyttää se eka luku looppien tekemiseen mutta miten ilmoitan ohjelmalle että eka rivi ei tule mukaan looppiin.

lue_data = fopen("kokeilu.txt", "r");
if(lue_data !=NULL){
   fscanf("%d", &ekaluku);
   for(i=0; i<ekaluku; i++){
      fscanf("%s, %s, %s", &enimi, &snimi, &numero);
   .
   .
   .

kun fscan alkaa siis toisen kerran keräämään näitä enimi, snimi, numero tietoja niin osaako se jättää tämän ekaluku rivin pois laskuista kun se on jo kerran haettu ?

Grez [03.11.2012 02:31:33]

#

No eihän sille tarvi mitään erikseen sanoa. Kun olet lukenut sen luvun, niin se on luettu ja seuraava lukuoperaatio jatkaa sitten seuraavasta kohdasta.

Shooter99 [03.11.2012 12:51:49]

#

Osaisko joku valottaa millä saisin tuon tiedoston luvun / tallentamisen toimiin?
Joudunko siis tekeen ensinnä tiedoston lukemisen

lue_data = fopen("kokeilu.txt", "r");
 if(lue_data !=NULL){
     }
     fclose(lue_data);

Ja sen jälkeen päälle kirjoittamisen

lue_data = fopen("kokeilu.txt", "w");
 if(lue_data !=NULL){
     }
     fclose(lue_data);

vai pystyisikö sen tekemään yhdessä w modessa ?

Grez [03.11.2012 13:36:59]

#

Yhdessä w -modessa ei voi lukea tiedostoa, koska siellä ei ole w-modessa avaamisen jälkeen yhtään mitään (luettavaa).

Jos olet varma, että tiedostosta tulee isompi kuin vanha, niin voit toki avata "r+" modessa ja luettuasi sanoa

fseek(tiedosto, 0, SEEK_SET);

ja sen jälkeen kirjoittaa.

Mielestäni "lue_data" on huono muuttujan nimi, siksi laitoin tilalle "tiedosto"


Koska tiedostoa ei tuolla keinolla voi pienentää on erillinen avaaminen lukemiseksi ja kirjoittamiseksi mielestäni kuitenkin perusteltua.

User137 [03.11.2012 17:02:41]

#

Shooter99 kirjoitti:

fscanf("%s, %s, %s", &enimi, &snimi, &numero);

Laitoit taas pilkut sisään, niitä ei tarvitse koska teksti "Matti Meikalainen 0401234567" ei sisällä pilkkuja. "%s %s %s" riittää siis.

Aina kun luet tai kirjoitat tiedostosta/tiedostoon jotain, niin sen osoitin siirtyy käsittelemäsi pätkän loppuun. Seuraava operaatio tehdään siellä missä osoitin on. Seek-toiminnoilla voi siirtää tuota osoitinta manuaalisesti jos haluaa skipata tiettyjen arvojen yli esim.

Jos aiot kirjoittaa samaan tiedostoon mistä luet, helpointa on lukea koko sisältö ensin taulukkoon.

Shooter99 [03.11.2012 17:57:21]

#

Joo korjasin virheen jo koodiin...

Kuinkas toi r+ toimii jos tiedosto pysyy saman kokoisena ?

Käytännössä tiedoston koko kasvaa joka ajon yhteydessä mutta toi saattaa olla haitaksi myöhemmin kun käsittääkseni tähän kuuluu vielä jossain vaiheessa tehtävä että pitää olemassa olevia nimiöitä pystyä poistamaan....

Metabolix [03.11.2012 19:13:06]

#

Älä käytä r+:aa, vaan kirjoitusvaiheessa avaa tiedosto uudestaan. Kuten Grez sanoi, tiedostoa ei voi r+:lla pienentää, joten vanhan datan loppuosa jää tiedostoon. Esimerkiksi jos tiedostossa lukee "ABCD" ja tallennat alkuun sitten r+-tilassa "12", lopputuloksena on "12CD".

Shooter99 [04.11.2012 11:03:10]

#

Auttakaas nyt vähän tän alun kanssa, toi uusien tietojen kirjoittaminen kyllä toimii mutta alku kusee ja pahasti...

#include <stdio.h>
#define ETUNIMI_KOKO 20
#define SUKUNIMI_KOKO 31
#define PUHELINNUMERO_KOKO 12
int main(void){
char etunimi[ETUNIMI_KOKO], sukunimi[SUKUNIMI_KOKO], puhelinnumero[PUHELINNUMERO_KOKO];
int i, ekaluku;

FILE *tiedosto_lue;
tiedosto_lue = fopen("koetus.txt", "r");
if(tiedosto_lue == NULL){
  printf("Tiedostoa ei ole olemassa.");
  return 0;
  } else {
    fscanf("%d", ekaluku);
//  printf("%i", ekaluku); //Luvun löytymisen tarkistaminen.
    for(i<0; i<ekaluku; i++){
      fscanf("%s %s %s", &etunimi, &sukunimi, &puhelinnumero);
      return tallenne;
      }
    }
}
/*
printf("Ohjelma tallentaa tiedot.\n");
printf("Syötä etunimi:");
scanf("%s", &etunimi[0]);
printf("Syötä sukunimi:");
scanf("%s", &sukunimi[0]);
printf("Syötä puhelinnumero:");
scanf("%s", &puhelinnumero[0]);

FILE *tiedosto_tallenna;
tiedosto_tallenna = fopen("koetus.txt", "w");
if(tiedosto_tallenna == NULL){
  printf("Tiedostoa ei voitu luoda.");
  return 0;
  } else {
    fprintf(tiedosto_tallenna, "%s %s %s", etunimi, sukunimi, puhelinnumero);
    fclose(tiedosto_tallenna);
    }
  printf("\n\nTallennus onnistui!");
  return 0;
}
*/

jalski [04.11.2012 12:03:03]

#

Shooter99 kirjoitti:

...mutta alku kusee ja pahasti...

Olet taas laittanut ihan käsittämättömän koodin, mikä ei varmasti käänny millään kääntäjällä.

Jos kokeilisit tuon oikeasti kääntää, niin saisit varmasti ainakin seuraavat ilmoitukset:

Compiling and linking file: Csource1.c
C:\USERS\X\DOCUMENTS\CSOURCE1.C(15) : error 139 - Argument no 1 of 'fscanf' must be of type '<ptr>_file', not 'char[3]'
C:\USERS\X\DOCUMENTS\CSOURCE1.C(15) : warning 215 - The result of this statement is not used
C:\USERS\X\DOCUMENTS\CSOURCE1.C(18) : error 139 - Argument no 1 of 'fscanf' must be of type '<ptr>_file', not 'char[9]'
C:\USERS\X\DOCUMENTS\CSOURCE1.C(18) : warning 215 - The result of this statement is not used
C:\USERS\X\DOCUMENTS\CSOURCE1.C(19) : error 79 - 'tallenne' has not been declared
*** Compilation failed
Compilation failed.

Mistä tuon return tallenne rivin olet silmukkaan kehittänyt? Jos tuo jollain ihmeellä kääntyisikin niin silmukan ja koko ohjelman suoritushan loppuisi tuohon silmukan ensimmäiseen kierrokseen.

Shooter99 [04.11.2012 12:51:21]

#

Johan mainitsin että koodi kusee... ja sen takia pyysin apua...

jalski [04.11.2012 14:17:40]

#

Shooter99 kirjoitti:

Johan mainitsin että koodi kusee... ja sen takia pyysin apua...

Kokeile korjata kääntäjän huomauttamat puutteet askel kerrallaan:

error 139 - Argument no 1 of 'fscanf' must be of type '<ptr>_file', not 'char[3]'

Kertoo suoraan, että funktiokutsu ei vastaa määrittelyä: eli ensimmäisen parametrin pitäisi olla tiedosto-osoitin, eikä merkkijono.

error 79 - 'tallenne' has not been declared

Muuttujaa ei ole määritelty. Lisäksi return käsky tässä kohtaa ei ole järkevä, kommentoi rivi vaikka pois.

Jos nyt käännät, saat varmaan jotakin allaolevan kaltaista:

Compiling file: Csource1.c
C:\USERS\X\DOCUMENTS\CSOURCE1.C(15) : warning 508 - Data of type 'int' supplied where a pointer is required
C:\USERS\X\DOCUMENTS\CSOURCE1.C(18) : warning 511 - Character pointer expected to satisfy %s format
C:\USERS\X\DOCUMENTS\CSOURCE1.C(7) : warning 286 - 'ekaluku' has been used, but never given a value
C:\USERS\X\DOCUMENTS\CSOURCE1.C(7) : warning 286 - 'i' has been used, but never given a value

Tämä purettuna:

 warning 508 - Data of type 'int' supplied where a pointer is required

Pitäisikö olla muuttujan osoite, eikä sisältö?

 warning 511 - Character pointer expected to satisfy %s format

Mainitsin joskus aiemmin merkkijonojen ja osoittimien yhteydestä, joten merkkijonojen nimet sellaisenaan käyvät tälle riville.

warning 286 - 'ekaluku' has been used, but never given a value

Tämä korjautui jo.

Jos korjaat nuo ja käännät, niin jäljellä on enää:

Compiling and linking file: Csource2.c
C:\USERS\X\DOCUMENTS\CSOURCE2.C(7) : warning 286 - 'i' has been used, but never given a value
C:\USERS\X\DOCUMENTS\CSOURCE2.C(17) : warning 215 - The result of this statement is not used

Yksi huolimattomuus virhe on vielä jäljellä, löydätköhän sen?

Shooter99 [04.11.2012 17:45:26]

#

error 139 - Argument no 1 of 'fscanf' must be of type '<ptr>_file', not 'char[3]'

tämän kanssa olikin vähän ongelmia ku ei mistään oikein löytynyt mitä se tarkoittaa...

mietinvaan [04.11.2012 21:39:50]

#

Sinulla on myös virhe tuossa silmukassa:

for(i<0; i<ekaluku; i++){

Korjattuna:

for(i=0; i<ekaluku; i++){

jalski [04.11.2012 21:44:37]

#

mietinvaan kirjoitti:

Sinulla on myös virhe tuossa silmukassa:

Taisinpa tuosta jo hienovaraisesti vihjaista, mutta oli tarkoituksena jättää harjoitukseksi... :-)

mietinvaan [05.11.2012 00:21:06]

#

Niinpäs olitkin, en huomannut. Pahoittelut :) No, tuli nyt harjoitus sitten palautteen muodossa.

PS. Kysyjän kannattaisi ehtiessään opiskella myös hieman koodinsa sisentämistä. Selkeä esitysmuoto auttaa sekin virheiden esiin tuonnissa.

Shooter99 [05.11.2012 07:31:19]

#

Mitenkäs ihmees oon se onnistunut vaihtaa ku kumminkin alunperin on ollut oikein... Noh... Onneksi huomautit koska oon varmaan vahingossa vaihtanut ton ja vissiin en olisi ihan heti osannut etsiä virhettä siitä...

Lisäys:

Muokkasin koodia seuraavan näköiseksi mutta jostain syystä aluksi palautti lukua 69 vaikka alustin i:n 0:ksi ja sitten kun lisäsin fscanf:n & merkin ekaluku eteen ohjelma palautti lukua 0.

#include <stdio.h>
#define ETUNIMI_KOKO 20
#define SUKUNIMI_KOKO 31
#define PUHELINNUMERO_KOKO 12
int main(void){
    char etunimi[ETUNIMI_KOKO], sukunimi[SUKUNIMI_KOKO], puhelinnumero[PUHELINNUMERO_KOKO];
    int i, ekaluku;

FILE *tiedosto_lue;
tiedosto_lue = fopen("koetus.txt", "r");
if(tiedosto_lue == NULL){
  printf("Tiedostoa ei ole olemassa.");
//return 0;
//} else {
//rewind(tiedosto_lue);
  fscanf (tiedosto_lue, "%d", &ekaluku);

//for(i=0; i<ekaluku; i++){
//fscanf(tiedosto_lue, "%s %s %s", &etunimi, &sukunimi, &puhelinnumero);
  fclose (tiedosto_lue);
//    }
  }
printf("%d", ekaluku); //Luvun löytymisen tarkistaminen.
}

vesikuusi [05.11.2012 09:27:29]

#

Mikä osa koodistasi menee if-lohkon sisään? ;)

jalski [05.11.2012 09:39:34]

#

vesikuusi kirjoitti:

Mikä osa koodistasi menee if-lohkon sisään? ;)

Jeps...

Annetaan vihjeenä ;-)

Shooter99 [05.11.2012 13:03:54]

#

Näköjään koko pirun koodi...

Lisäys: Kiitos... Ootte parhautta....

Lisäys:

Ja uusi kysymys...
For looppi toistaa ekaa riviä nyt 4 kertaa, joten mitäs pitäis tehdä ?

Muuttaa tekstitiedosto taulukoksi vai jotain muuta...

vesikuusi [05.11.2012 13:24:54]

#

Kokonaisen tiedoston lukemiseen on käytettävä fread-funktiota, jolloin homma meneekin vähän monimutkaisemmaksi, kuten linkin takaa paljastuu.

jalski [05.11.2012 14:26:26]

#

vesikuusi kirjoitti:

Kokonaisen tiedoston lukemiseen on käytettävä fread-funktiota...

Ei tarvitse, voit lukea henkilö kerrallaan. Kyllähän tuon vähän korjatun ohjelmapätkäsi pitäisi jokseenkin toimia...

#include <stdio.h>

#define ETUNIMI_KOKO 20
#define SUKUNIMI_KOKO 31
#define PUHELINNUMERO_KOKO 12

int main(void){
	char etunimi[ETUNIMI_KOKO], sukunimi[SUKUNIMI_KOKO], puhelinnumero[PUHELINNUMERO_KOKO];
	int i, ekaluku;
	FILE *tiedosto_lue;

	tiedosto_lue = fopen("koetus.txt", "r");
	if(tiedosto_lue == NULL){
  		printf("Tiedostoa ei ole olemassa.");
  		return 0;
	}

    fscanf(tiedosto_lue,"%d", &ekaluku);
	printf("tietoja: %d\n", ekaluku);

    for(i=0; i<ekaluku; i++){
		fscanf(tiedosto_lue,"%s %s %s", etunimi, sukunimi, puhelinnumero);
        printf("%s %s %s\n", etunimi, sukunimi, puhelinnumero);
	}

	return 0;
}

vesikuusi [05.11.2012 15:04:46]

#

Mielenkiintoista, tuota en tiennytkään :o fscanf siis siirtää get pointeria eteenpäin lukiessaan?

Edit. Niin tietysti, taitavat kaikki scan-funktiot tehdä saman :D Ei vaan ole tullut mieleen että onnistuu näinkin.

User137 [05.11.2012 15:14:02]

#

Then i come again and mess the mind.

Jos tiedostossa olisi näin:

4
Jean-Claude Van Damme 050-3500980
Matti Meikäläinen 041-3478924
Brian Kottarainen 040-3980982
Brita Kottarainen 05-4567393

Niin se mitä tulostuu on:

Jean-Claude Van Damme
050-3500980 Matti Meikäläinen
041-3478924 Brian Kottarainen
040-3980982 Brita Kottarainen

Shooter99 [05.11.2012 17:54:16]

#

Okei en usko että menee noin...
Ainakaan mulla ku en tunne Jean Claudea niin hyvin...

Tuossa on totta kai ongelma... jos nimessä siis on joku Van, Von, Di, Da, tai vastaava välissä...

Pitäisikö sittenkin käyttää tuota fgetsiä...
Vai pitääkö vetää varuiks tunsina %s ottaan arvoja talteen...

Macro [05.11.2012 20:33:53]

#

Parempi tapa olisi käyttää jotain erotinta, esimerkiksi puolipistettä, jolloin nimessä voi olla niin monta osaa kuin siinä vain voi olla, ja ohjelma toimisi oikein.

Shooter99 [06.11.2012 12:48:24]

#

Koitin marcon ehdottamaa tapaa mutta:

fscanf(tiedosto_lue,"%s %s %s", etunimi, sukunimi, puhelinnumero);

muuttaminen

fscanf(tiedosto_lue,"%s; %s; %s;", etunimi, sukunimi, puhelinnumero);
tai
fscanf(tiedosto_lue,"%s %s %s;", etunimi, sukunimi, puhelinnumero);

aiheuttaa for loopille sen että se tekee 4 kertaa ensimmäisen rivin.
Eli jotain ilmeisesti minulta puuttuu tai oon tunkenut puoli pisteet väärään paikkaan...

Kysymys, onko tuosta REWIND komennosta mitään hyötyä tässä ohjelmassa loppujen lopuksi ?

vesikuusi [06.11.2012 15:10:25]

#

Laitat ne puolipisteet ainoastaan kirjoittaessasi tiedostoon, luet tieoston normaalisti ja parsit nimet puolipisteiden ympäriltä.

Edit. Siis kaikki nimen osat pötköön tähän tapaan

Jean-Claude;Van;Damme 050-3500980
Matti;Meikäläinen 041-3478924
fscanf (tiedosto_lue, "%s %s", kokonimi, puhelinnumero);
// parsi kokonimestä etu- ja sukunimet

Lisäys:

Voit myös käyttää erilaisia erottimia tunnistamaan sukunimen, esim.

Jean-Claude+Van;Damme 050-3500980
Matti;Sakari+Meikäläinen 041-3478924

Tässä tapauskessa + -merkki erottaa etunimet sukunimestä.

Macro [06.11.2012 15:28:38]

#

Mitähän vesikuusen esimerkissä mahtaa tapahtua?

Etunimeksi tulee Jean-Claude, sukunimeksi Van ja numeroksi Damme 050-3500980?

Joku tämmöinen viritelmä voisi olla ihan hyvä.

tiedosto = lueData("osoitekirja.txt")

osoitekirja = new Lista<Henkilö>

while((rivi = tiedosto.seuraavaRivi()) != null) {
	henkilö = new Henkilö()
	tiedot = rivi.pilko(";")

	henkilö.asetaNimi(tiedot[0])
	henkilö.asetaNumero(tiedot[1])

    osoitekirja.lisää(henkilö)
}

tulosta osoitekirja[0].annaNimi()

vesikuusi [06.11.2012 15:42:16]

#

Macro kirjoitti:

Mitähän vesikuusen esimerkissä mahtaa tapahtua?

Etunimeksi tulee Jean-Claude, sukunimeksi Van ja numeroksi Damme 050-3500980?

Parsitko ollenkaan tiedoston sisältöä? Miten sovelsit esimerkkiäni?

Tässä ei parsita:

#include <stdio.h>

int main () {
	const int ETUNIMI_MAX = 30;
	const int SUKUNIMI_MAX = 30;
	const int PUH_MAX = 12;

	FILE* tiedosto_lue;
	char kokonimi[ ETUNIMI_MAX + SUKUNIMI_MAX ], puhelinnumero [ PUH_MAX ];

	tiedosto_lue = fopen ( "numerot.txt", "r" );

	if ( !tiedosto_lue ) {
		perror ("Tiedosto ei aukea!");
		return 1;
	}

	fscanf ( tiedosto_lue, "%s %s", kokonimi, puhelinnumero );
	fclose ( tiedosto_lue );

	printf ("Nimi: %s\nPuh: %s", kokonimi, puhelinnumero);

	return 0;
}

Ohjelma tulostaa

Nimi: Jean-Claude+Van;Damme
Puh: 050-3500980

Edit. Tuossa pitää vielä parsia nimet erottimien ympäriltä, niin hyvin toimii.

Macro kirjoitti:

Joku tämmöinen viritelmä voisi olla ihan hyvä.

Tässä koodataan nyt C-kielellä, ja pyritään pysymään aika helpoissa jutuissa, kukaan ei halua tähän ketjuun oliopohjaisia taidonnäytteitäsi.

Macro [06.11.2012 15:50:14]

#

lainaus:

Jean-Claude+Van;Damme 050-3500980
Matti;Sakari+Meikäläinen 041-3478924

Jos ; erottaa nimen ja puhelinnumeron ja + erottaa etu- ja sukunimen, niin minusta tuloksena on, että Jean-Claude Vanin puhelinnumero on Damme 050-3500980.

Mitä olioihin tulee, niin sanonpahan vain, että kukin voi tehdä niin kuin parhaakseen näkee.

vesikuusi [06.11.2012 15:52:57]

#

; Erottaa nimen osat toisistaan. Etkö itsekin puhunut samasta tyylistä?

Macro kirjoitti:

Parempi tapa olisi käyttää jotain erotinta, esimerkiksi puolipistettä, jolloin nimessä voi olla niin monta osaa kuin siinä vain voi olla, ja ohjelma toimisi oikein.

Siltä ainakin minulle näyttää. Eikä siinä olisi tässä tapauksessa mitään järkeä, että erottaisi nimen ja puhelinnumeron toisistaan puolipisteellä.

Macro [06.11.2012 15:57:28]

#

Ainakin minusta taulukon osat tulisi erottaa sillä puolipisteellä, eikä korvata nimen välejä sillä.

Jean-Claude Van Damme;050-3500980
Matti Sakari Meikäläinen;041-3478924

vs.

Jean-Claude;Van;Damme 050-3500980
Matti;Sakari;Meikäläinen 041-3478924

Shooter99 [06.11.2012 17:46:51]

#

Okei!

aloitetaan tästä.

1. Tämä on koulutehtävä mikä palautetaan koulun verkossa olevalle kääntäjälle.
2. En pääse kyseiselle koneelle muokkaamaan tuota tektitiedostoa mitenkään, paitsi tekemällä ohjelman joka syöttää eka kaikki 4 nimeä eriteltyina eri merkeillä missä vaiheessa kääntäjä huutaisi jo erroria.

Eli ei ruveta txt tiedostoa mitenkään muokkaan sen pitää olla tuollainen ja toimia sellaisena, ikävä kyllä.

Mulle on ihan sama vaikka kirjotettais 5000 riviä koodia kunhan saan vähän ohjausta kun sitä tarvitsen (eli) lähes aina.

Tärkeintä on että ohjelma toimii !

Ja jos jatketaan vaikka siitä että Van Damme ja kumppanit ei tuu tälle listalle vaan pelkkiä Virtasia, Jokisia, Mäkisiä etc...

User137 [06.11.2012 18:37:32]

#

2) Sulla on täydet oikeudet tiedostoon, joten ohjelmasi voi tehdä sille mitä vaan. Esim tämä vois nollata puhelinluettelon kokonaan:

    FILE* tiedosto;
    tiedosto = fopen ("numerot.txt", "w");
    if (tiedosto) {
        fprintf(tiedosto, "0");
    }
    fclose (tiedosto);

Kun eihän siellä tarvitse välttämättä olla mitään alussa. Pystyt ohjelmallasi kirjoittamaan sinne kaikki testi-nimet ja numerot. Kääntäjä ei huuda erroria missään vaiheessa ellet tee sille vääryyttä.

Mutta kuten jossain vaiheessa tuli ilmi, sinun tulee tallentaa koko puhelinluettelo muistiin, mikäli haluat pystyä poistamaan nimiä (jos tarvitsee vain ja ainoastaan lisätä maksimissaan 9 puhelinnumeroa, niin voit skipata mitä sanon). Avaa lopussa tiedosto uudestaan kirjoitusta varten. Tarvitset taulukon merkkijonoja nimille jne, ellei struct-tyyppiä ole opetettu.

Eli 2-ulotteinen taulukko

char etunimi[MAARA_MAX, ETUNIMI_MAX];

Siis tuo max 9 puhelinnumeroa tulee siitä, että jos tiedoston alussa oleva numero esitetäänkin kahdella merkillä niin se ylikirjoittaa rivinvaihdon ja näinollen sekoittuu ensimmäiseen etunimeen.
... joka tietysti ei olisi mikään ongelma jos koko luettelo luetaan muistiin ja tallennetaan kokonaan lopuksi. Tai jos ei tulosteta alkuun numeroa laisinkaan, vaan käytetään EOF:ää.

Shooter99 [06.11.2012 20:22:09]

#

Se mitä itse olen tässä ajatellut nyt on se että jos nämä 4 jo olemassa olevaa nimeä ja numeroa voisi ajaa taulukon 4 ekaan paikkaan.

[0][0] 4
[0][1] Puhelinnumero Etunimi Sukunimi
[0][2] 041-3478924 Matti Meikäläinen
[0][3] 041-3478924 Brian Kottarainen
[0][4] 040-3980982 Brita Kottarainen

tämän jälkeen taulukkoon lisättäisiin x määrä tietoja minkä jälkeen koko taulukko tallennettaisiin vanhan tiedoston päälle.

vesikuusi [06.11.2012 22:29:55]

#

Mihin tuota nelosta käytetään?
Jätän sen nyt huomiotta.

Tässä jotain jelppiä tiedoston lukemiseen ja tietojen järjestämiseen.
Luodaan ensin taulukot.

const int ETUNIMI_MAX = 30;
const int SUKUNIMI_MAX = 30;
const int PUH_MAX = 12;
const int HENKILOITA = 4;

char etunimi [ ETUNIMI_MAX ];
char sukunimi [ SUKUNIMI_MAX ];
char puh [ PUH_MAX ];

char* henkilo [ HENKILOITA ][ 3 ];

henkilo-taulukon ensimmäisissä hakasulkeissa on henkilön id/rivi.
Seuraavissa hakasulkeissa on rivin kentät eli taulun sarakkeet.
Niitä on kolme kappaletta:

Näin voimme laittaa riville henkilo[0] vaikkapa Matti Meikäläisen.
Matti Meikäläisen kentissä on tiedot seuraavasti:

Koodina

henkilo [0][0] == "041-3478924"; // tosi
henkilo [0][1] == "Matti"; // tosi
henkilo [0][2] == "Meikäläinen"; // tosi

Samalla tavalla voimme lisätä toisen henkilön riville 1:

henkilo [1][0] = "041-3478924";
henkilo [1][1] = "Brian";
henkilo [1][2] = "Kottarainen";

Ja ohjelmassa jotain tällaista:

// Taulukot
const int ETUNIMI_MAX = 30;
const int SUKUNIMI_MAX = 30;
const int PUH_MAX = 12;
const int HENKILOITA = 4;

char etunimi [ ETUNIMI_MAX ];
char sukunimi [ SUKUNIMI_MAX ];
char puh [ PUH_MAX ];

char* henkilo [ HENKILOITA ][ 3 ];
// --Taulukot loppuu

FILE* luettava_tiedosto;

// Tähän koodi, jossa avataan tiedosto yms.

// Tallennetaan henkilöiden tiedot tauluun
for ( int i = 0; i < HENKILOITA; ++i ) {
    // nyt käsitellään henkilöä, jonka id on i,
    // aka. henkilo[i]

    // Tähän tulee koodi, jolla tiedostosta luetaan
    // tiedot merkkijonoihin etunimi, sukunimi ja puh

    // Tähän koodi, jossa etunimi, sukunimi ja puh
    // kopioidaan henkilo-tauluun riville i
}

Pahoittelen aiheesta poikkeamista aiemmin. Toivottavasti tämä auttaa jotain :)
Selvennän toki tarvittaessa, ja niin tekevät varmasti muutkin.

Lisäys: Taulun kirjoittaminen tiedostoon tapahtuu samantyyppisellä for-loopilla ja fprintf:llä. Loopissa käydään kaikki henkilöt läpi ja kirjoitetaan niiden tiedot tiedostoon yksi kerrallaan.

User137 [07.11.2012 00:19:24]

#

Sulta jäi huomiotta että kyseessä on merkkijono, tuosta henkilo-taulusta. Toiseks kokonaista merkkijonoa ei voi kerralla kopioida = -operaattorilla, eikä tässä tapauksessa pointteriakaan saa/voi siirtää. Ja lopuksi henkilöiden määrä 4 ei kai ollut tarkoitettu vakioksi, vaan se luetaan ja kirjoitetaan tiedoston ekalle riville (mistä jo mainitsin ettei väkisin tarviis).

Oletan nyt että hälle on annettu tehtäväksi koodata puhelinluettelo. Mihinkään tiedostorakenteeseen tuskin tehtävässä on otettu kantaa. Numero ekalla rivillä kuulostaa omalta keksinnöltä.

Shooter99 [07.11.2012 07:21:05]

#

/*
YKSINKERTAISET TIETORAKENTEET C-KIELESSÄ

Anna palautetta
Puhelinluettelo - tietojen lisääminen ohjelmointitehtävä 1/3
Tässä luvussa tehdään itsenäisiä ohjelmia, jotka kuitenkin liittyvät läheisesti toisiinsa.
Kaikki ohjelmat ovat osia puhelinluettelo-ohjelmasta. Tarkoituksena on, että voit jatkaa
puhelinluettelon ohjelmointia jatkaaksesi ohjelmoinnin harjoittelua. Luvun harjoitustehtävät
on helposti muunnettavissa funktioiksi suurempaan kokonaisuuteen.

Puhelinluettelon nimi- ja puhelintiedot sijaitsevat tiedostossa "luettelo.txt",
joka on muodoltaan seuraava:

4
Etunimi Sukunimi 050-3500980
Matti Meikäläinen 041-3478924
Brian Kottarainen 040-3980982
Brita Kottarainen 05-4567393

Tiedoston ensimmäinen rivi ilmaisee kokonaislukuna kuinka monta nimeä luetteloon on lisätty.
Sekä etunimi, sukunimi että puhelinnumero käsitellään tekstimuotoisena. Edelliset tiedot on
eroteltu tiedostossa toisistaan välilyönnein ja yksittäisen tiedon (esim. etunimi) pituus
voi olla korkeintaan 20 merkkiä. Yhdellä rivillä on vain yhden henkilön tiedot. Luettelossa
voi olla korkeintaan 50 henkilöä. Ensimmäinen tehtäväsi on tehdä ohjelma, jolla voi lisätä
uuden puhelinnumeron luetteloon. Käynnistettäessä ohjelman tulee kysyä ensin etunimeä, jonka
jälkeen kysytään sukunimi ja lopuksi puhelinnumero. Tallennettaessa tietoja, tiedoston
ensimmäisen rivin arvon on kasvettava yhdellä. Huomaa, että tehtävän yksikertaistamiseksi
syötettävät tiedot eivät saa sisältää esim. välilyöntimerkkiä. Henkilötiedot tulevat kukin
omalle rivilleen. (Muista rivinvaihtomerkki.)

Esimerkkitulostus

Anna etunimi:Esko
Anna sukunimi:Esimerkki
Anna puhelinnumero:123-4567890
Tietojen tallennus onnistui. */

Lisäys: Tässä on tehtävän anto joten 4 ei ole itse keksimä juttu

Lisäys: Tämä Vesikuusen ratkaisumalli näyttää mielestäni aika pitkälti siltä mitä aluksi ajattelin...

vesikuusi [07.11.2012 08:48:11]

#

User137 kirjoitti:

Sulta jäi huomiotta että kyseessä on merkkijono, tuosta henkilo-taulusta.

Totta. Korjasin sen, lisäsin yhden ulottuvuuden (tai oikeastaan tein henkilo-taulusta char-osoitintyyppisen):

char* henkilo [ HENKILOITA ][ 3 ];

User137 kirjoitti:

Toiseks kokonaista merkkijonoa ei voi kerralla kopioida = -operaattorilla, eikä tässä tapauksessa pointteriakaan saa/voi siirtää.

Tätä en ymmärrä. Mulla ainakin onnistuu noiden tietojen kopoiminen taluun.

Lisäys: Shooter99, mihin osaan tehtävässä tarvitset nyt erityisesti apua?

User137 [07.11.2012 10:37:50]

#

vesikuusi kirjoitti:

User137 kirjoitti:

Toiseks kokonaista merkkijonoa ei voi kerralla kopioida = -operaattorilla, eikä tässä tapauksessa pointteriakaan saa/voi siirtää.

Tätä en ymmärrä. Mulla ainakin onnistuu noiden tietojen kopoiminen taluun.

Kun tiedot mistä kopioit on tuolleen:

char etunimi [ ETUNIMI_MAX ];
char sukunimi [ SUKUNIMI_MAX ];
char puh [ PUH_MAX ];

Niin pointteri kuhunkin ei ohjelman aikana muutu. Eli luvun lopuksi tilanne olis se että kaikkien henkilöiden tiedot osoittaa viimeisen henkilön tietoihin.

Mutta on vaihtoehtoja, esim strcpy
http://www.cplusplus.com/reference/clibrary/cstring/strcpy/

Shooter99 [07.11.2012 11:21:54]

#

Moi!

Tota en tie vielä / enään...

Mä lähden koittaan tätä hommaa nyt tuolla array periaatteella kasata ja ehkäpä tuossa iltapäivätllä olen jo niin kovissa tuskissa että tulen kyseleen taas apuja...

vesikuusi [07.11.2012 11:44:33]

#

User137 kirjoitti:

Kun tiedot mistä kopioit on tuolleen:

char etunimi [ ETUNIMI_MAX ];
char sukunimi [ SUKUNIMI_MAX ];
char puh [ PUH_MAX ];

Niin pointteri kuhunkin ei ohjelman aikana muutu. Eli luvun lopuksi tilanne olis se että kaikkien henkilöiden tiedot osoittaa viimeisen henkilön tietoihin.

Mutta on vaihtoehtoja, esim strcpy
http://www.cplusplus.com/reference/clibrary/cstring/strcpy/

Totta turiset :D Täytyy käyttä strcpy-funkkaria.

Teuro [07.11.2012 15:46:58]

#

Tässä tarvittavien funktioiden prototyypit ja toimiva pääohjelma testausta varten. Tietojen tulostaminen ei tainnut kuulua tehtävän antoon, mutta ihan mukava lisä se silti on. Tiedoston alussa olevan luvun tarvertta voisi aavistuksen kritisoida, koska sille ei oikein löydy järkeviä perusteita.

#include <stdio.h>
#include <stdlib.h>

/** Henkilöiden käsittely on parasta selkeällä rakenteella **/
typedef struct henkilo {
    char etunimi[20];
    char sukunimi[20];
    char numero[20];
} henkilo;

/** Uuden henkilön tietojen kysyminen palauttaa henkilön. Voidaan tallentaa suoraan taulukkoon **/
henkilo kysy_tiedot();
/** Luetaan tiedoston sisältö palauttaa tiedostossa olevien olioiden (rivien) määrän **/
int lue_tiedosto(const char* nimi);
/** Tallentaa datan tiedostoon pyyhkien ensin vanhat tiedot pois. Epäonnistuessaan tiedosto voi jäädä tyhjäksi **/
void tallenna_tiedot(const char* nimi, henkilo taulu[], int kpl);
/** Tulostaa kaikkien taulukossa olevien tietojen tiedot **/
void tulosta_luettelo(henkilo taulu[], int kpl);

/** Globaali henkilötaulukko ei kauhean tyylikäs ratkaisu **/
henkilo taulu[50];

int main(int argc, char** argv) {
    int kpl;
    const char* luettelo = "luettelo.txt";

    kpl = lue_tiedosto(luettelo);

    taulu[kpl] = kysy_tiedot();

    printf("Henkilon %d tiedot %s, %s, %s \n", kpl, taulu[kpl].etunimi, taulu[kpl].sukunimi, taulu[kpl].numero);

    tulosta_luettelo(taulu, kpl);

    tallenna_tiedot(luettelo, taulu, kpl);

    return 0;
}

Shooter99 [07.11.2012 17:07:28]

#

Moi!

Numeroa ekalla rivillä saa kritisoida mutta kun tehtävä on annettu tehtäväksi sillain... Ilmeisesti tässä on haettu takaa juuri sitä että eka luku kertoo rivien määrän ja samalla se kertoo monta kertaa i kasvaa ennen kuin se tulee ohjelman viimeisen rivin loppuun...

Muuta käyttöä en itse sille keksi.

Lisäys:

Mietin itse yhdessä välissä myös jos rakentaisi 2 structuuriia jotenkin näin

struct Nimi
{
char etunimi[21];
char sukunimi[31];
};

struct Numero
{
struct Name;
char puhnumero;
};

Jolloin jos tulee nimi haku niin voi käyttää structuuria nimi ja muuten Numeroa.

No joo

Teuro [07.11.2012 17:41:27]

#

Mitä etua tuosta kahdesta rakenteesta sitten oikein on? Lisäksi se taitaa olla melko pahasti rikki. Rakenteen tarkoituksena on koota yhteen kuuluvat asiat yhteen. Ainahan voit hakea rakenteen eri kenttien perusteella, joten se ei ainakaan ole fiksu peruste. Opetajalle voisit mainita tuosta luvusta tiedoston alussa.

Shooter99 [08.11.2012 10:02:18]

#

Ei varmaan yhtään mitään, kuten sanoin että aluksi ajattelin vain tälläistä vaihtoehtoa ja nyt mä en tie enään mitä teen tai haluan tai miten, koska, milloin...

Suoraan sanottuna tässä ketjussa on tullut todella paljon apua mutta kun kaikki tekee erilailla asian ja nyt oon siinä tilanteessa että mulla 17 eri alkua miten tehdä ko. ohjelma mutta ei yhtään ainutta minkä olis kokonaan oppinut.

Please ottakaa huomioon että minun koodaus taitoni on vasta jollain tasolla 1kk joista aktiivista aikaa varmaan yhteensä viikko.

Joten päätokseni on tämä.
Koska Teuron antama malli näyttää kaikista helpomoimmalta niin jatkan sen pohjalta, toivon että kun pyydän apua niin kaytetään sitä pohjana eikä heitetä taas täysin uutta koodin alkua.

Jos vain saisin tämän toimiin niin kaikki olis ok...

Mitä muuten tämä asterix tähti meinaa char* perässä ?

Teuro [08.11.2012 11:38:55]

#

Shooter99 kirjoitti:

Please ottakaa huomioon että minun koodaus taitoni on vasta jollain tasolla 1kk joista aktiivista aikaa varmaan yhteensä viikko.

Mikäli emme ottaisi, niin vastaukset olisivat oleellisesti eri tasoisia.

Shooter99 kirjoitti:

Koska Teuron antama malli näyttää kaikista helpomoimmalta niin jatkan sen pohjalta, toivon että kun pyydän apua niin kaytetään sitä pohjana eikä heitetä taas täysin uutta koodin alkua.

Tämä selvä malli ei ole paras mahdollinen, mutta tällä päässet helpohkosti alkuun.

Shooter99 kirjoitti:

Jos vain saisin tämän toimiin niin kaikki olis ok...

Tarkenna vielä mitä tarkoitat tällä. Koko tehtävääkö vai jotakin muuta.

Shooter99 [08.11.2012 13:33:45]

#

En tarkoita vielä mitään...
Kattotaan sitten kun pääsen / kerkiän tänään koodia testaileen...

User137 [08.11.2012 17:38:37]

#

Shooter99 kirjoitti:

Mitä muuten tämä asterix tähti meinaa char* perässä ?

Onko teidän opetusmateriaalissa käyty läpi osoittimet ja struktuurit, ehkä myös dynaaminen varaus? Jos, niin kannattaa ainakin vilkasta sieltä päin, tai tuntiharjoituksista apuja.

Shooter99 [08.11.2012 20:45:02]

#

Seuraava harjoitus näyttää olevan osoittimet...

Shooter99 [09.11.2012 18:30:17]

#

Ei tuu mitään...
En saa tätä ohjelmaa enään edes liikahtaan mihinkään suuntaan...

Plaah...

En saa noita kutsuja toimiin aliohjelmasta...

Teuro [09.11.2012 18:36:07]

#

Mihin tilaan olet ohjelmasi saanut? Oletko tehnyt esimerkissä olevien funktioiden toteutukset?

Shooter99 [09.11.2012 22:37:18]

#

Pitää kattoo huomenna... nyt rupee tippuun silmät päästä...

Shooter99 [10.11.2012 09:22:32]

#

En tie nyt on olo niin ku pohjanmaalaisella supersankarilla eli Vituxmän...

#include <stdio.h>
#include <stdlib.h>

typedef struct henkilo {
    char etunimi[21];
    char sukunimi[31];
    char numero[15];
} henkilo;

henkilo kysy_tiedot();
int lue_tiedosto(const char* nimi);
void tallenna_tiedot(const char* nimi, henkilo taulu[], int kpl);
void tulosta_luettelo(henkilo taulu[], int kpl);

henkilo taulu[50];

int main(int argc, char** argv) {
    int kpl;
    const char* luettelo = "luettelo.txt";

    kpl = lue_tiedosto(luettelo);

    taulu[kpl] = kysy_tiedot();

    printf("Henkilon %d tiedot %s, %s, %s \n", kpl, taulu[kpl].etunimi, taulu[kpl].sukunimi, taulu[kpl].numero);

    tulosta_luettelo(taulu, kpl);

    tallenna_tiedot(luettelo, taulu, kpl);

    return 0;
}
henkilo kysy_tiedot(){

    printf("Anna etunimi:");
    scanf("%s", &etunimi[taulu]);
    printf("Anna sukunimi:");
    scanf("%s", &sukunimi[taulu]);
    printf("Anna puhelinnumero:");
    scanf("%s", &numero[taulu]);
}

int lue_tiedosto(const char* nimi){

}
void tallenna_tiedot(const char* nimi, henkilo taulu[], int kpl){
    fopen("kokeilu.txt", "w");
    if(lue_data !=NULL){
        fprintf("\n", henkilo taulu[]);
    }
}

void tulosta_luettelo(henkilo taulu[], int kpl){
    printf("\n", henkilo taulu[kpl]);
}

Metabolix [10.11.2012 10:28:05]

#

Lue nyt tuota ohjelmaasi rivi kerrallaan ja mieti, mitä ihmettä ne rivit muka mielestäsi tarkoittavat. Ei ole mitään järkeä koodata rivejä, joita ei ymmärrä. Vielä vähemmän järkeä on koodata rivejä, joita kukaan muukaan ei ymmärrä. Jokainen rivi pitää ymmärtää, ja pitää tietää, miksi se on juuri niin ja juuri siinä kohdassa.

Miettisit nyt ohjelmointia edes niin kuin matematiikkaa: ethän voi siinäkään piirrellä satunnaisia numeroita, kirjaimia ja muita merkkejä pitkin paperia ja kysyä sitten opettajalta, mikä meni pieleen. Jokaisessa asiassa pitää olla jotain järkeä, ja jos et tiedä, otat ensin selvää ja teet vasta sitten.

Tämäkin ohjelma on oikein helppo tehdä, kun vain mietit asia kerrallaan, mitä pitää tapahtua.

  1. Tiedot ovat tiedostossa. Pitää siis avata tiedosto luettavaksi.
  2. Tiedoston alussa on luku, joka kertoo rivimäärän. Pitää siis lukea tiedostosta luku muuttujaan nimeltä rivimaara. Katsotaan kurssimateriaalista, miten luetaan tiedostosta yksi luku, ja vaihdetaan esimerkkiin oikeat muuttujat.
  3. Tiedostossa on seuraavaksi ensimmäisen henkilön etunimi. Pitää siis lukea tiedostosta yksi sana henkilötaulukon ensimmäisen (0) kohdan etunimeksi. Katsotaan kurssimateriaalista, miten tehdään struct henkilo ja taulukollinen niitä. Sitten katsotaan kurssimateriaalista, miten luetaan tiedostosta yksi sana, ja sovelletaan tätä henkilötaulukon ensimmäisen (0) kohdan etunimeen.
  4. Tiedostossa on seuraavaksi ensimmäisen henkilön sukunimi. Tehdään siis sama kuin äsken mutta sukunimelle.
  5. Tiedostossa on seuraavaksi ensimmäisen henkilön puhelinnumero. Tehdään siis sama kuin äsken mutta puhelinnumerolle.
  6. Tiedostossa on seuraavaksi toisen (1) henkilön etunimi, sukunimi ja puhelinnumero. Tässä vaiheessa otetaan kolme edellistä kohtaa (etunimi, sukunimi ja puhelinnumero) ja tehdään niistä for-silmukka, jossa numero 0 on korvattu indeksillä i. Näin saadaan toinen henkilö ja kaikki loputkin henkilöt luettua samalla koodilla.
  7. Tiedot on luettu, joten tiedoston voi sulkea.
  8. Jatka samaan malliin.

Teuro [10.11.2012 13:20:02]

#

Otetaan nyt esimerkiksi vaikka tämä funktio tarkasteluun.

Shooter99 kirjoitti:

henkilo kysy_tiedot(){

    printf("Anna etunimi:");
    scanf("%s", &etunimi[taulu]);
    printf("Anna sukunimi:");
    scanf("%s", &sukunimi[taulu]);
    printf("Anna puhelinnumero:");
    scanf("%s", &numero[taulu]);
}

Tuossa ilmaistaan aivan selvästi, että funktion paluuarvo pitää olla henkilö-tyyppinen. Nythän olet implementoinut sen void-tyyppiseksi, eli ihan väärin. Funktiossa pitää luoda paikallinen muuttuja vaikka henkilo h, jolle kysytään tiedot ja lopuksi palautetaan kyseinen olio.

Oma toteutukseni oli tällainen:

henkilo kysy_tiedot(){
    henkilo h;

    printf("Anna etunimi sukunimi puhelinnumero \n");
    scanf("%s %s %s", h.etunimi, h.sukunimi, h.numero);

    return h;
}

Ei ihan tehtävän mukainen, koska siellä kai piti kysyä tiedot erikseen. Tämä tallennetaan henkilötauluun seuraavasti.

taulu[kpl] = kysy_tiedot();
++kpl;

Samanlaista kummallisuutta löytyy toki kaikista muistakin funktioista.


Sivun alkuun

Vastaus

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

Tietoa sivustosta