Eli minulla on kaksi .cpp tiedostoa jossa toisessa sijaitsee main funktio ynm ja toisessa ovat sitten funktiot ja includet. Nyt koitan kääntää sitä ja se herjaa:
multiple definition of (kaikki funktiot vuorollaan)
first defined here
Siis first defined missä? Siirsin ne funktiot tuohon main.cpp ja toimi kunnolla? Mikä pirhana siinä on vikana? Idenä Dev-c++.
Todennäköisesti sinulla on tälläinen tilanne:
*** foo.c int foo() {return 1;} int foo2() {return 2;} *** main.c #include "foo.c" int main(void) { return 1; }
Ongelma syntyy siinä, että kääntäjä kääntää projektissa mukana olevat tiedostot erikseen ja sitten linkittää nämä tiedostot yhteen. Nyt käännettäessä foo.c tiedostoa määritellään funktiot foo ja foo2 ja käännettäessä main.c:tä ne määritellään toistamiseen, koska include suoraan kopioi kohdetiedoston sisällä haluttuun kohtaan, jolloin main.c näyttää kääntäjälle tältä:
*** main.c esiprosessorin jälkeen int foo() {return 1;} int foo2() {return 2;} int main(void) { return 1; }
Tämän jälkeen sinulla on ohjelmassasi molemmat funktiot kahteen kertaan määriteltynä ja kääntäjä valittaa.
Perusratkaisu tähän tilanteeseen on tehtä header-tiedosto, jossa vain esittelet funktiot, mutta et määrittele niitä.
Eli tyyliin:
***foo.h #ifndef FOO_H #define FOO_H int foo(); int foo2(); #endif /* FOO_H */ *** foo.c #include "foo.h" int foo() {return 1;} int foo2() {return 2;} *** main.c #include "foo.h" int main(void) { return 1; }
Nyt funktiot määritellään ja käännetään vain kerran, ja kääntäjä tietää main.c tiedostossa, että foo ja foo2 funktiot on määritelty jossain muussa modulissa.
Toivottavasti arvasin ongelmasi oikein.
Kyllä kyllä, kiitos. Kuitenkin valittaa vielä noista stringeistä siellä .h tiedostossa. Mitenköhän tämän saisi korjattua?
#include <string> kenties?
Tottakai siellä on mutta ei se auta. :(
Onko sinulla muuttujia/vakiota h-tiedossa? Jos on, niin nillä tulee vastaan samat ongelmat kuin funktiolla eli ne määritellään kahteen kertaan. Jos oikeasti tarvitset kutsua jonkun toisen modulin muuttujaa, voit esitellä sen h-tiedostossa seuraavasti:
extern string foobar;
Ei, mulla on siellä esimerkiksi:
string fooBar();
Joka siis palauttaa stringin. Anteeksi epätarkkuuteni.
Kaikkeen tuollaiseen laitetaan otsikossa extern eteen, jos otsikkoa on tarkoitus käyttää useammassa cpp-tiedostossa tai jos cpp-tiedostosta löytyy myös funktion määrittely. Extern (siis external, käsittääkseni) kertoo kääntäjälle, että sen ei tarvitse huolehtia funktion olemassaolosta. Tällöin on mahdollista kääntää tietyt funktiot erillään. Linkkeri hoitaa sitten niiden liittämisen yhdeksi paketiksi. Jos extern-määrittelyllä käytettyä funktiota ei tässä vaiheessa löydy, ilmoittaa linkkeri virheestä: "Unresolved external symbol".
Onko sulla se
#include <string>
varmasti myös siellä h-tiedostossa?
On #include <string> siellä h-tiedostossa, on extern siinä stringin edessä ja silti sanoo et:
`string' does not name a type
:(
string
=> std::string
tai alkuun (includen jälkeen) using std::string;
(tai hätätapauksessa using namespace std;
)
Kiitos kiitos, nyt se toimii. :)
Yritin kyllä aikaisemminkin tota using namescape std; mut herjas vaan. Tuo using std::string; kuitenkin toimi.
EDIT: Vielä että miten kun haluasin käyttää taulukkoa vaikka tossa stringis niin mitenköhän se onnistuisi?
Ihan samalla tavalla toimii kuin muukin taulukko.
int main(void) { string str_taulu[3] = { "Matti", "Pekka", "Lasse" }; cout << str_taulu[0][0] // 1. rivin 1. merkki = M << str_taulu[1][1] // 2. rivin 2. merkki = e << str_taulu[2][2] // 3. rivin 3. merkki = s << str_taulu[0][3] // 1. rivin 4. merkki = t << str_taulu[1][4] // 2. rivin 5. merkki = a << endl; // Rivinvaihto return 0; }
Joo mut esimerkiksi sillai et joku int funktio palauttais taulukon. Vaikka:
int yhteen(int luku, int luku1){ int Array[2]; Array[0] = luku; Array[1] = luku1; Array[2] = luku+luku1; return Array[]; }
sit jossain:
int toinenArray[2] = yhteen(1, 3);
ps. oon väsynyt joten (jos mahdollista) sekavampaa kuin yleensä tää selitys
Ei onnistu palauttamalla, mutta parametrinä kylläkin:
void Laita_Taulukkoon_Lukuja(int * Taulukko, int Maara, int EkaLuku) { int i; // Kirjoitetaan Taulukko-tauluun Maara lukua alkaen arvosta EkaLuku for (i = 0; i < Maara; i++) Taulukko[i] = EkaLuku + i; } int main() { int Luvut[10]; // 10 lukua alkaen 9:stä, eli 9, 10, ... , 18. Laita_Taulukkoon_Lukuja(Luvut, 10, 9); return 0; }
jonez kirjoitti:
Yritin kyllä aikaisemminkin tota using namescape std; mut herjas vaan.
Niin... Se on namespace, ei namescape.
Itsekin muistelin joskus alkuaikoina tuon juurin noin — väärin :)
Kiitos
Aihe on jo aika vanha, joten et voi enää vastata siihen.