Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: Miksi cout ei toimi toisessa funktiossa?

Sivun loppuun

Mande [16.09.2009 18:59:51]

#

Okei, eli koitan täs pistää vanhaa peliä uuteen kuosiin. Ongelma on nyt seuraava:

Olen tehnyt pelin logon tiedostoon fTittle.cpp ja sille headerin fTittle.h. Kyseisessä tiedostossa on funktio fTittle() (joo, en oo hyvä nimeämään...). Nyt kun sitten kutsun fTittle() funktiota, saan virheilmoituksen "cout undecleared (first use in function)". Käytän Dev-C++.

Ainiin, ja koodi:

fTittle.h/.cpp

//Tämä tiedosto sisältää pää ruudun sisällön ja funktiot. Sitä käytetään kun peli käynnistetään.
//Tulostetaan logo, jonka jälkeen kysytään haluaako pelaaja pelata vai sammuttaa

void fTittle()
{

    cout << "    NN    NN  UU    UU  KK  KK  EEEEE  SSSSSS  II  MM         MM  UU    UU"<< endl
         << "    NNNN  NN  UU    UU  KK KK   EE     SS      II  MMMM     MMMM  UU    UU"<< endl
         << "    NN NN NN  UU    UU  KKKK    EEEEE  SSSSSS  II  MM MM   MM MM  UU    UU"<< endl
         << "    NN  NNNN   UU  UU   KK KK   EE         SS  II  MM  MM MM  MM   UU  UU "<< endl
         << "    NN    NN    UUUU    KK  KK  EEEEE  SSSSSS  II  MM   MMM   MM    UUUU  "<< endl
         << "                             __________________ " << endl
         << "                            |__    _    _    __|" << endl
         << "                               |  | |  | |  |   " << endl
         << "                               |  | |  | |  |   " << endl
         << "                               |  | |  | |  |   " << endl
         << "                             __|  |_|  |_|  |__ " << endl
         << "                            |__________________|" << endl;


}

ja sitten main.ccp

#include <cstdlib>
#include <iostream>
#include "ftittle.cpp"

using namespace std;

int main()
{

     fTittle();     //kutsustaan funktiota fTittle() joka piirtää logon

     system("PAUSE");
     return EXIT_SUCCESS;
}

Kuten varmaa näette, koitan ny eka ratkaista mitä hel*****ä kone nyt herjaa ennen kuin teen itse käyttöliittymän. Oma tyylini on "tee toiminto->testaa->korjaa->tee seuraava toiminto". Täs tapaukses tää "logo" toiminto ei nyt toimi.

P.S: Ennen kuin unohdan, tän olis tarkoitus toimii tuolla DOS ympäristössä, eli konsolissa tai jotain sinne. Sori huono selostus, ohjelmointi onnistuu muttei termit.

*edit*
Ja koiton jo lisätä #include <iostream> fTittle.h/.cpp, siirtää sen main:tä fTittle:leen, jne. Herja tulee vaikka mikä olis.

MIB [16.09.2009 19:11:12]

#

Jos nyt oikein ymmärsin, niin tuota namespacea pitää kutsua myös tuolla toisessa tiedostossa.

nomic [16.09.2009 19:12:02]

#

Otat std:n käyttöön myöhemmin kuin sitä tarvitaan.

Eli joko siirrät sen tuonne ftittle.cpp-tiedoston alkuun tai sitten cout:n eteen kirjoitat std::cout << "tekstiä"; ... jolloinka et tarvitse std-nimiavaruutta, mutta joudut aina kirjoittamaan alkuun tuon std::-pätkän.

Viisaammat osaavat varmasti paremmin neuvoa.

edit. pahus, MIB ehti ensin!

temu92 [16.09.2009 19:12:06]

#

Protip: toisia projektiin kuuluvia .c/.cpp tiedostoja ei #includetata vaan kääntäjälle annetaan ne parametreinä (ilmeisesti) tai antamalla IDE:n hoitaa se (jos sellaista käyttää).

MIB [16.09.2009 19:12:42]

#

Jeps, testasin tuota mitä sanoin ja hyvin toimii ;)

Mande [16.09.2009 19:40:57]

#

Kokeilin MIB:in neuvoa.

Kiitti! Nyt pelittää! </huono sanaleikki>

Itse en ole tottunut tuohon namespace, koska kun aikoinani opettelin c++ siitä ei puhuttu mitään. Kai siihen oppii tätä projektia tehdessä :)

@temu92: Kuinkas tuo toimii? Luin kans et toisia .ccp tiedostoja ei kuulu #include, mutta en kyl keksiny miten ne muuten saa toimimaan main funkiossa.

Metabolix [16.09.2009 21:24:23]

#

Lue C++-oppaasta asian teoriapuoli ja tutustu koodivinkkeihin 1901 ja 1770.

Mande [16.09.2009 22:25:57]

#

Hmm... mistähän tällä kertaa kiikastaa? namespace on mukana mutta silti sama virhe. Tällä kertaa tiedostona on fGame.cpp/.h (teen ton .h tiedoston aina varmuuden varalta ku ei koskaa tiedä mitä herjaa).

täs on tän hetken main.ccp

//NukeSimu III, aplha 0.1



#include <cstdlib> //ei muista enää... ei tainnut olla tarvetta mutta antaa olla vielä. Testaan myöhemmin.
#include <iostream> // perus sisääntulo/ulostulo
#include <conio.h> //ruudun tyhjennystä varten
#include "fTittle.cpp" //päävalikko
#include "fGame.cpp" //itse peli

using namespace std;

int main()
{
     int vMode = 0;

     vMode = fTittle();     //kutsustaan funktiota fTittle() joka piirtää logon ja asettaa pelin tilan

    if (vMode == 1)
    {
              system("cls"); // tyhjentää ruudun
              fGame();
    }

     else
     {
         system("cls"); // tyhjentää ruudun
         cout << "loser..." << endl;
     }



     system("PAUSE");
     return EXIT_SUCCESS;
}

ja sitte tämä fGame.ccp, jossa fGame() sijaitsee. Koodia on lisää mutta laitan tän ensimmäisen kohdan esille. Lopussa on viellä tuo int fSide() jossa valitaan osapuoli. Se palauttaa arvon 1,2 tai 0 joka tulkitaan virheeksi. En viitsi laittaa sitä, koska se on käytännössä vain isoläjä ASCII kuvaa.

//tämä on nyt se varsinainen "peli", jossa aluksi valitaan puoli (IHAN UUS! Ennen piti pelata
//vain USA:lla... :D
//kuitenkin, meillä on tuo fgame(), jossa varsinaiset tapahtumat ovat ja sitte fSide() jossa
//valitaan ollaako jenkki vai neukku.

using namespace std;



void fGame() //varsinainen peli
{
    int vStatus = 0;
    cout << "In main mode" << endl;
    vStatus = fSide();

    if (vStatus == 1 || vStatus == 2)
    {
       cout << "This section of the game is still under work. Please be patient." << endl;
    }

    else
    {
       cout << "There was a somekind of error there. Dunno what you did, but it was something " << endl
       << "that you weren't supposed to do. Jerkass." << endl;
    }
    //return 1;
} //fGame päättyy

jos ihmettelette miks fGame() on erillisessä teidostossa, tarkoitus on vielä tehdä fOption() ja fLoad(), jotka taas vievät oman osansa teidostosta. Hajauttamalla tietyt "yläfunktiot" (no, oikeesti alifunktiot) pysyy tuo main() selkeämpänä kun siellä ei ole useaa funktiota yhdessä rytäkässä. Plus vielä luokat jotka on vielä suunnittelun alla.

Metabolix [16.09.2009 22:30:56]

#

Et näköjään ymmärrä tuosta monen tiedoston jutusta yhtikäs mitään. Mikset lukenut linkittämiäni neuvoja, tai mikset ottanut niistä opiksesi?

Mande [16.09.2009 22:32:14]

#

Koska en ymmärtänyt antamiasi linkkejä ja edellinen neuvo ei toimi. Lisään tuon namespace, mutta virhe on sama. Nyt vain eri tiedosto.

Jaska [16.09.2009 22:37:35]

#

Virhe taitaa olla rivillä

vMode = fTittle();

fTittle() on void-tyyppinen, joten se ei palauta mitään. Nyt kuitenkin yrität sijoittaa tyhjää int-muuttujaan.

Mande [16.09.2009 22:46:14]

#

Ei ole, ikävä kyllä. Koodi on muuttunut :) fTittle() on tätä nykyää int, joka palauttaa int arvon. En ole vielä tehnyt ns. "backup" komentoa, joka antaa virhe ilmoituksen jos sieltä tulee jotain muuta kuin mitä pyydetään. Eli peli kysyy käyttäjältä haluaako hän pelata vai ei.
(ASCII logo jätetty pois tilan säästämiseksi)

int fTittle()
{
    int vValinta = 1; //alustetaan vValinta muuttuja ja annetaan sille oletusarvoksi 1, joka aloittaa pelin

// Tähän tulee alun logo

    cout << "Welcome to NukeSimu III. Please enter your choice: " << endl //Pyydetään pelaaja tekemään valinta
         <<"1: Beging new game " << endl
         <<"2: Quit" << endl;
    cin >> vValinta;

    return vValinta; //palautetaan pelaajan valinta



} //fTittle() päättyy

mutta huomasimpa tämän: myöhemmin tulee ilmoitus kohdassa

vStatus = fSide();

virhe: fSide() undecleared
ja jotain fSide() used prior declared

Jos joku osaisi suomeksi selittää, mitä tällä "declare" tarkoitetaan ja MINNE sen on tarkoitus mennä, olisin erittäin tyytyväinen :D

*edit*

Kappas, sain cout virheen pois kun lisäsin rivit

int fTittle();
void fGame();
int fSide();

tuon using namespace std; jälkeen. Nyt tulee vain ilmoitus fSide() undecleared. Osaako kukaan auttaa?

vehkis91 [16.09.2009 22:53:52]

#

EDIT: olitkin laittanut jo uutta koodia... no anyway, toivottavasti tämä auttaa
ymmärtämään metabolixin koodivinkkejä...

EDIT2: tuo virhe johtuu siitä, että et ole määrittänyt funktiota
int fSide(); missään. Eli laitettu sisältöä tyyliin:

int fSide()
{
  int x = 1;
  return x;
}

Sää teet väärin... pitäis olla #include "xxx.h"
eikä #include "xxx.cpp"

esim.

xxx.cpp

#include "xxx.h"

void moi()
{
   std::cout<<"moi!!"<<std::endl;
}

xxx.h

#ifndef _XXX_H
#define _XXX_H 1

#include <iostream>

extern void moi();

#endif

main.cpp

#include "xxx.h"

int main()
{
   moi();

   std::cin.get();
   return 0;
}

Mande [16.09.2009 23:01:07]

#

anteeksi nyt tyhmyyteni, mutta en nyt ymmärtänyt täysin. Eli <iostream> tulee toisen , esim. fGame.h sisään? Tuleeko sinne myös "using namespace std; "? Ja sitte nuo #ifndef _XXX_H ja #define _XXX_H 1. Tiedän, että suurin osa porukasta osaa lukea tuon kuin joisivat vettä, mutta itse koodasin viimeksi 5 vuotta sitten ja nyt yritän taas kehittyä (kertasin kyllä perusteet, et ihan nollasta en lähtenyt). Kieli vaan on menny eteenpäin.

vehkis91 [16.09.2009 23:05:29]

#

EDIT: Katso Metabolixin ohje alempaa... :D

//Tarkistetaan onko määritetty (#define...) _XXX_H
#ifndef _XXX_H
//jos ei ole, niin määritetään se. Tämä estää sen, ettei samaa tiedostoa
//vahingossa sisällytetä montaa kertaa samaan projektiin.
#define _XXX_H 1

//Koodia....

//lopetetaan ehto
#endif

temu92 [16.09.2009 23:19:18]

#

Mande kirjoitti:

anteeksi nyt tyhmyyteni, mutta en nyt ymmärtänyt täysin. Eli <iostream> tulee toisen , esim. fGame.h sisään?

Header tiedosto (.h/.hpp) on nimensä mukaisesti otsikkotiedosto eli sinne voi ja yleensä laitetaankin itse varsinaisen koodin #include rivit ja tärkeiden muuttujien ja funktioiden esittely, ehkä struct rakenteet, luokat (niiden funktiot kannattaa taas pistää omaan .cpp tiedostoonsa). Periaatteessa perussääntönä voitaisiin pitää, että header tiedosto on esittelyä kun varsinainen kooditiedosto on sitten valmis käyttämään esim. juuri iostreamin esittelemiä asioita. Sitten ei tarvitse muuta kuin pistää #include "xxx.h" joka kooditiedoston alkuun.

Mande kirjoitti:

Ja sitte nuo #ifndef _XXX_H ja #define _XXX_H 1..

Tuo #ifndef .. #endif systeemi estää tiedoston lisäyksen kahteen kertaan. Rivi tarkistaa onko jo tiedostossa käyty kertaalleen ja jos ei niin määritellään _XXX_H ilmaisemaan että nyt ollaan käyty. Juurikin siksi esimerkiksi ei haittaa vaikka rivin #include <iostream> laittaisikin useammin kuin kerran koska se ei käännösvaiheessa ole koskaan useampaan kertaan sisällytetty samaan koodinpätkään.

Disclaimer: en ole vastuussa jos jokin meni väärin :P Itsellä toimii silti koodit näillä keinoilla.

Metabolix [16.09.2009 23:25:08]

#

vehkis91 selitti pari kohtaa väärin.

#include <iostream> kuuluu kaikkiin niihin tiedostoihin, joissa sitä tarvitaan, siis kaikkiin, joissa esiintyy std::cin tai std::cout. Jos et jostain erikoisesta syystä tarvitse sitä .h-tiedostossa, laita se vain .cpp-tiedostoihin ja vain, jos sitä tarvitaan.

using namespace std; kuuluu niihin tiedostoihin, joissa tarvittaisiin muuten std::-etuliitettä mutta et halua sitä käyttää. Jos tämän rivin sijoittaminen oikeaan paikkaan tuottaa ongelmia, ota se kokonaan pois ja käytä std::-etuliitettä, kunnes olet viisastunut riittävästi, jotta ymmärrät oppaasta, mitä rivi tekee ja milloin sitä on järkevää käyttää vai onko koskaan.

Kaipaamasi suomennokset:
declare, esitellä, ja declaration, esittely;
define, määritellä, ja definition, määrittely.
Lisätietoa näiden merkityksistä on oppaassa, jonka jo linkitin. Et ilmeisesti yrittänyt juurikaan lukea sitä, nimittäin myös nämä käännökset esiintyvät siinä.

Mande [16.09.2009 23:50:40]

#

*edit*
Okei, eli fiksattu versio
*edit*

En tiedä tarkalleen ymmärsinkö oikein, mutta ainakin virheet vähenee.

eli täl hetkel:

fGame.cpp

//tämä on nyt se varsinainen "peli", jossa aluksi valitaan puoli (IHAN UUS! Ennen piti pelata
//vain USA:lla... :D
//kuitenkin, meillä on tuo fgame(), jossa varsinaiset tapahtumat ovat ja sitte fSide() jossa
//valitaan ollaako jenkki vai neukku.


#include <iostream> // perus sisääntulo/ulostulo





int fGame() //varsinainen peli
{
    int vStatus = 0;
    std::cout << "In main mode" << std::endl;
    vStatus = fSide();

    if (vStatus == 1 || vStatus == 2)
    {
       std::cout << "This section of the game is still under work. Please be patient." << std::endl;
    }

    else
    {
       std::cout << "There was a somekind of error there. Dunno what you did, but it was something " << std::endl
       << "that you weren't supposed to do. Jerkass." << std::endl;
    }
    return 1;
}

int fSide()
{
    int vSelection;
    //USAn lippu: Joan Stark, http://www.geocities.com/soho/7373/july4.htm#vertflag
    std::cout << "============;===========;()      " << std::endl //vasara ja sirppi  From: Dave Bird---St Hippo of Augustine http://punkabbestia.com/punkabbestia/ascii-art/docs/ascii-art_de_collection/s/sickle%2Bhammer.html
         << "            # # # #::::::                          |\\',      \\." << std::endl
         << "            # # # #::::::                       .' \\\\|       \\'." << std::endl
         << "            # # # #::::::                     __|   |~         \\ :" << std::endl
         << "            # # # #::::::                    /\\ \\_. \\  /\\      : |" << std::endl
         << "            # # # # # # #                   \\ \\|  \\ \\/  \\     / /" << std::endl
         << "            # # # # # # #                    \\/    \\ \\/\\ '._.' /" << std::endl
         << "            # # # # # # #                          /\\ \\ '.___.'" << std::endl
         << "            # # # # # # #                        / /\\ \\" << std::endl
         << "            # # # # # # #                        / /  \\ \\" << std::endl
         << "            # # # # # # #                       / /    \\ \\" << std::endl
         << "                                                \\/      \\/" << std::endl;
    std::cout << "            1:USA                                  2:USSR " <<  std::endl;
    std::cin  >> vSelection;

    if (vSelection == 1 || vSelection == 2)
    {
     return vSelection;
    }

    else
    {
        return 0;
    }
} //fSide päättyy

fGame.h

#ifndef _fGame_h
#define _fGame_h


extern int fGame();
extern int fSide();

#endif

main.ccp

//NukeSimu III, aplha 0.1



#include <cstdlib> //ei muista enää... ei tainnut olla tarvetta mutta antaa olla vielä. Testaan myöhemmin.
#include <iostream> // perus sisääntulo/ulostulo
#include <conio.h> //ruudun tyhjennystä varten
#include "fTittle.h" //Valikko
#include "fGame.h" //itse peli


int fGame();
int fSide();

int main()
{
     int vMode = 0;

     vMode = fTittle();     //kutsustaan funktiota fTittle() joka piirtää logon ja asettaa pelin tilan

    if (vMode == 1)
    {
              system("cls"); // tyhjentää ruudun
              fGame();
    }

     else
     {
         system("cls"); // tyhjentää ruudun
         std::cout << "loser..." << std::endl;
     }



     system("PAUSE");
     return EXIT_SUCCESS;
}

ja Dev-C++ ilmoittaa että funktio fSide() on esittelemätön. Kuinka korjata?

Ja P.S: Kiitos Metabolixelle kun jaksaa vastailla tällaisen tollon kysymyksiin :) ja teille muillekkin :)

Metabolix [16.09.2009 23:56:09]

#

Lue vielä edellisen viestini kappale iostream-otsikon sijoittelusta.

Mande [17.09.2009 00:12:58]

#

Ai p*****e, nyt huomasin. Oli jäänyt tuo #include "fGame.h" pois fGame.cpp tiedostosta. Nyt alkoi taas toimia.

Kiitos paljon kun jaksoit auttaa. Uskoisin et kyl se tästä eteenpäin (toivottavasti) osaa itse etsiä virheet ja korjata. Kiitti viel kerran.


Sivun alkuun

Vastaus

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

Tietoa sivustosta