Skocz do zawartości


Zdjęcie

[C++] Dev-C++ - błędy linkera


  • Zaloguj się, aby dodać odpowiedź
14 odpowiedzi w tym temacie

#1 magic385

magic385

    Nowy

  • 4 postów

Napisano 03 05 2010 - 17:11

Hej.
Mam taki problem: Napisałam program który ma tworzyć prostą bazę danych w c++. Pisałam w devie 4.9.9.2. Jeśli chodzi o zastosowanie programu to ma to być dodawanie usuwanie i modyfikowanie rekordów w bazie. Postać bazy jest wczytywana z pliku. I warunkiem jest że program ma wykorzystywać listę jednokierunkową. Dodatkowo ma to być podzielone na moduły. I właśnie tu jest mój główny problem. Występują błędy linkera podczas kompilacji. Wyswietla mi się
[Linker error] undefined reference to `Dodaj()' .I tak przy kazdej funkcji.
Zrobiłam tak. Mam main.cpp, modMenu.cpp, modMenu.h, modFunkcje.cpp i modFunkcje.h. W module Menu mam funkcje oparta na switchu ktora pozwala wybrac co chcemy z baza robic.
W module Funkcje mam funkcje które wywołuje switch czyli np Dodawanie elementu do bazy albo usuwanie. Wszystkie funkcje działaja zlepione razem ale przy podziale na moduły juz nie. Dodałam we wszystkich modułam dyrektywy żeby się łączyły i nie wiem z czym może być problem. Proszę o szybką pomoc.

  • 0

#2 Kazeeny

Kazeeny

    Stały użytkownik

  • 209 postów

Napisano 03 05 2010 - 19:48

Tworzysz to jako projekt? Wydaje mi się, że pewnie tworzysz nowy plik źródłowy (main.cpp) i w nim umieszczasz dyrektywy. Tak w Devie tego nie można zrobić - trzeba utworzyć projekt. I tutaj taka mała rada -> jeżeli tworzysz projekty, to nie używaj do tego Dev-cpp tylko ściągnij sobie MS Visual Studio C++ Express Edition (to jest darmowa wersja, do ściągnięcia ze strony Microsoftu), jest to o wiele lepsze środowisko

BTW. Pokaż kawałek kodu z tymi dyrektywami, bo może się okazać, że jest jeszcze jeden błąd (który można popełnić tworząc projekt)

Użytkownik Katarina edytował ten post 03 05 2010 - 19:55

  • 0

#3 magic385

magic385

    Nowy

  • 4 postów

Napisano 03 05 2010 - 20:50

Tak mam projekt stworzony na bank.
#include <iostream>
#include <cstdlib>

#include "modMenu"
#include "modFunkcje"

using namespace std;

int main(int argc, char *argv[])
{PokazMenu();
system("PAUSE");
return EXIT_SUCCESS;
}
]
To jest w mainie.
a funkcja PokazMenu wyglada tak:

void PokazMenu()
{system("cls");
cout<<"MENU"<<endl;
cout<<"Aby wykonac wybrane operacje wybierz numer:"<<endl;
cout<<"1-Wyswietl pelna baze danych"<<endl;
cout<<"2-Dodaj nowy rekord do bazy"<<endl;
cout<<"3-Usun rekord o wybranym numerze Id"<<endl;
cout<<"4-Modyfikuj rekord o wybranym numerze Id"<<endl;
cout<<"5-Sprawdz ilosc rekordow w bazie"<<endl;
cout<<"6-WYJSCIE z programu"<<endl;

char numer;
numer = getch();

switch (numer)
{case '1':PokazWszystko();break;
case '2':Dodaj();break;
case '3':UsunElement();break;
case '4':Modyfikuj();break;
case '5':Rozmiar_bazy();break;
case '6':exit(0);break;
default: PokazMenu();break;}; };


i jest umieszczona w innym module. Natomiast pozostałe funkcje ktore wywoluje switch sa w kolejnym module.

Użytkownik Katarina edytował ten post 03 05 2010 - 22:22

  • 0

#4 Kazeeny

Kazeeny

    Stały użytkownik

  • 209 postów

Napisano 03 05 2010 - 22:21

A no właśnie - jednak przewidziałam błędzik :omg:
#include "modMenu.h"
#include "modFunkcje.h"

Mam nadzieję, że w tych wszystkich plikach cpp i nagłówkach są poprawne dyrektywy #include. Czyli:
w pliku modFunkcje.cpp masz dyrektywę #include "modFunkcje.h"
w pliku modMenu.cpp masz dyrektywę #include "modMenu.h"

i pewnie modMenu.cpp odwołuje się do tych funkcji, więc i w nim musisz mieć jeszcze dyrektywę #include "modFunkcje.h" - mam nadzieję, że kompilator nie zapiszczy o wielokrotne includowanie nagłówków, bo może być taka możliwość (w Visualu można łatwo się przed tym zabezpieczyć, w Dev troszkę więcej kodu trzeba napisać)

Użytkownik Katarina edytował ten post 03 05 2010 - 22:31

  • 0

#5 magic385

magic385

    Nowy

  • 4 postów

Napisano 03 05 2010 - 23:15

No poprawiłam tamten głupi błąd z h. Miałam go na szczęście tylko w mainie. Ale błąd wciąż występuje. Program się kompiluje ale nadal wyrzuca błąd linkera. Moje pliki wyglądają tak:
main.cpp

#include <iostream>
#include <cstdlib>



using namespace std;

struct Sosoba
{int numer;
string imie;
string nazwisko;
bool plec;
int wiek;
Sosoba *nastepny;};

#include "modMenu.h"
#include "modFunkcje.h"

extern const string plik="bazadanych.txt";

void PokazMenu();

int main(int argc, char *argv[])
{Sosoba *glowka;
Przepisuj(plik,glowka);
PokazMenu();
system("PAUSE");
return EXIT_SUCCESS;
}]


modMenu.cpp

#include <cstdlib>
#include <iostream>
#include <string> //Dodanie podstawowych bibliotek.
#include <windows.h>
#include <conio.h>
#include <fstream>
#include <sstream>

#include "modFunkcje.h"
#include "modMenu.h"

using namespace std;

void PokazMenu();
void Kolorki();

void PokazMenu()
{system("cls"); //Funckcja wyświetlająca menu i umozliwiająca wybór opcji.
cout<<"MENU"<<endl;
cout<<"Aby wykonac wybrane operacje wybierz numer:"<<endl;
cout<<"1-Wyswietl pelna baze danych"<<endl;
cout<<"2-Dodaj nowy rekord do bazy"<<endl;
cout<<"3-Usun rekord o wybranym numerze Id"<<endl;
cout<<"4-Modyfikuj rekord o wybranym numerze Id"<<endl;
cout<<"5-Sprawdz ilosc rekordow w bazie"<<endl;
cout<<"6-WYJSCIE z programu"<<endl;

char numer;
numer = getch();

switch (numer)
{case '1':PokazWszystko();break;
case '2':Dodaj();break;
case '3':UsunElement();break;
case '4':Modyfikuj();break;
case '5':Rozmiar_bazy();break;
case '6':exit(0);break;
default: PokazMenu();break;}; };

int Kolorki(int i) //Funkcja zmieniajaca kolor wyswietlanego tekstu
{SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),i);};
]


modMenu.h

void PokazMenu();
int Kolorki(int i);
]


modFunkcje.cpp
#include <cstdlib>
#include <iostream>
#include <string>
#include <windows.h>
#include <conio.h>
#include <fstream>
#include <sstream>



using namespace std;

const string plik="bazadanych.txt";

struct Sosoba
{int numer;
string imie;
string nazwisko;
bool plec;
int wiek;
Sosoba *nastepny;};

#include "modFunkcje.h"
#include "modMenu.h"

int s2i(string n) {
stringstream sstr(n);
int m;
sstr >> m;
return m;};

void Przepisuj(string nazwa,Sosoba *&glowa)
{
string numer1,imie1,nazwisko1,plec1,wiek1;
ifstream plk_we;
plk_we.open(nazwa.c_str());

if ( !plk_we. is_open() ) {
cerr << "Blad otwarcia pliku \n";}
else {
cout<<"Udalo sie otworzyc"<<endl;};

Sosoba *aktualny;
glowa=NULL;
while(!plk_we.eof())
{
aktualny= new Sosoba;

plk_we>>imie1;aktualny->imie=imie1;
plk_we>>nazwisko1;aktualny->nazwisko=nazwisko1;
plk_we>>plec1; if (plec1[0]=='0'){ aktualny->plec=0;}else {aktualny->plec=1;};
plk_we>>wiek1;aktualny->wiek=s2i(wiek1);
aktualny->nastepny=glowa;
glowa=aktualny;
};

plk_we.close();};

void PokazWszystko( Sosoba *glowa)
{
cout <<"BAZA DANYCH"<<endl;
cout<<endl;
cout << "+----+--------------------------+----------+--------------+"<<endl;
cout << "| Nr | Nazwisko, Imie\t | Plec\t | Wiek\t |"<<endl;
cout << "+----+--------------------------+----------+--------------+"<<endl;
Sosoba *aktualny;
aktualny=new Sosoba;
aktualny=glowa;int numerek=1;
while (aktualny!=NULL)
{aktualny->numer=numerek;numerek++;
cout<<"|"<<aktualny->numer<<" "<<" |";
cout<<" "<<aktualny->imie<<" ";
cout<<aktualny->nazwisko<<"\t\t"<<"|";
cout<<"\t"<<aktualny->plec<<" |";
cout<<" "<<aktualny->wiek<<"\t\t"<<" |"<<endl;
cout << "+----+--------------------------+----------+--------------+"<<endl;
aktualny= aktualny->nastepny;};};


int Rozmiar_bazy(string nazwa)
{
int ile = 0;
ifstream plk_we;
plk_we.open(nazwa.c_str());
string linia;
while (!plk_we.eof())
{ getline(plk_we,linia);
ile++; };
plk_we.close();
return ile; };


void UsunElement(Sosoba *glowa)
{Sosoba *aktualny,*poprzedni;
aktualny=new Sosoba;
aktualny=glowa;
poprzedni=NULL;

int znak;

cout<<"Podaj numer rekordu:"<<endl;
cin>>znak;

while(aktualny!=NULL)
{if(aktualny->numer==znak)
{
if(aktualny==glowa)
{glowa=glowa->nastepny;}

else
poprzedni->nastepny=aktualny->nastepny;

Sosoba *temp;
temp = new Sosoba;
temp=aktualny;
aktualny=aktualny->nastepny;
delete temp; }
else{
poprzedni=aktualny;
aktualny=aktualny->nastepny;};

};
};

void Dodaj(string nazwa)
{Kolorki(11);
//cout<<"DODAWANIE NOWEGO REKORDU"<<endl://wsadz opis gdzie indziej, bo z tej fuunkcji korzystasz w modyfikuju
int n= Rozmiar_bazy(plik);
Kolorki(7);
cout<<"Podaj imie:"<<endl;
string imie;
cin>>imie;
cout<<"Podaj nazwisko:"<<endl;
string nazwisko;
cin>>nazwisko;
cout<<"Podaj płeć( 0-kobieta, 1-mezczyzna)"<<endl;
string plec;
cin>>plec;
cout<<"Podaj wiek:"<<endl;
int wiek;
cin>>wiek;

ofstream plk;
plk.open(nazwa.c_str(), ios::app);
plk<<endl;
plk<<imie<<" ";
plk<<nazwisko<<" ";
plk<<plec<<" ";
plk<<wiek<<" ";
plk.close();}

void Modyfikuj(string nazwa, Sosoba *glowa)
{UsunElement (glowa);
cout<<"podaj zmodyfikowane dane:"<<endl;
Dodaj(nazwa);
}:D


modFunkcje.h

void Przepisuj(string nazwa, Sosoba *&glowa);
void PokazWszystko( Sosoba *glowa);
int Rozmiar_bazy(string nazwa);
void UsunElement(Sosoba *glowa);
void Dodaj(string nazwa);
void Modyfikuj(string nazwa,Sosoba *&glowa):P


A postać pliku który wykorzystuje jest mniej więcej taka

Imie Nazwisko 0 19
Jan Kowalski 1 23

czyli najpierw imię potem nazwisko pleć (0-kobieta, 1-mężczyzna) i na końcu wiek.

Użytkownik Katarina edytował ten post 03 05 2010 - 23:19

  • 0

#6 Kazeeny

Kazeeny

    Stały użytkownik

  • 209 postów

Napisano 03 05 2010 - 23:22

Dwie rady:
1. wszelkie dyrektywy dołączaj na początku plików (zrobiłaś w dwóch miejscach, o ile się nie mylę, dyrektywy include, potem jakaś struktura, a potem znowu include - popraw to)
2. W plikach nagłówkowych umieść coś takiego:
#ifndef __nazwanaglowka_h
#define __nazwanaglowka_h
//tu reszta kodu (poczynajac od #include

//za kodem wpisz cos takiego:
#endif
To powinno wyeliminować problemy związane z wielokrotnym dołączaniem nagłówków. I nie wiem, czy nie ma przypadkiem problemów ze strukturą Sosoba - bo w dwóch plikach masz coś takiego zdefiniowanego

Użytkownik Katarina edytował ten post 03 05 2010 - 23:24

  • 0

#7 magic385

magic385

    Nowy

  • 4 postów

Napisano 03 05 2010 - 23:32

No teraz nie mam faktycznie tamtego błędu bo nie dochodzi do linkowania bo się jeszcze nawet nie kompiluje.Skoro już zainkludowałam je po dwa razy i nie było akurat z tym błędów to zostawię chyba bez #indef. Nie wiem w ogóle czy tego typu podział na moduły jest sensowny. Może można to jakoś lepiej rozplanować?
  • 0

#8 Kazeeny

Kazeeny

    Stały użytkownik

  • 209 postów

Napisano 04 05 2010 - 15:12

A możesz podać, co to za błąd? Bez tego trudno cokolwiek powiedzieć. Przypadkiem nie wywala Ci błędu w definicjach nagłówków funkcji?

Osobiście, w programowaniu strukturalnym nigdy nie robiłam podziału na żadne moduły. Dopiero przy zabawie z obiektowym C++ bawię się w projekty.
  • 0

#9 Pakrys

Pakrys

    Początkujący

  • 31 postów

Napisano 19 07 2010 - 06:10

A możesz podać, co to za błąd? Bez tego trudno cokolwiek powiedzieć. Przypadkiem nie wywala Ci błędu w definicjach nagłówków funkcji?

Osobiście, w programowaniu strukturalnym nigdy nie robiłam podziału na żadne moduły. Dopiero przy zabawie z obiektowym C++ bawię się w projekty.


Moja odpowiedź jest trochę spóźniona ale może się przydać.
Pliki nagłówkowe w Dev-Cpp przy pisaniu w języku C++ mają taką postać:
#include "jakaśnazwa_hpp.cpp" w funkcji main().

Własny plik nagłówkowy wygląda tak:

#ifndef jakaśnazwa_hpp
#define jakaśnazwa_hpp

int Statystyka(); //deklaracja funkcji

#endif
  • 0

#10 izaw

izaw

    Początkujący

  • 97 postów

Napisano 19 07 2010 - 12:47

A to coś nowego. Napisałeś nowy standard języka?
  • 0

#11 Pakrys

Pakrys

    Początkujący

  • 31 postów

Napisano 19 07 2010 - 19:12

Moja odpowiedź jest trochę spóźniona ale może się przydać.
Pliki nagłówkowe w Dev-Cpp przy pisaniu w języku C++ mają taką postać:
#include "jakaśnazwa_hpp.cpp" w funkcji main().

Własny plik nagłówkowy wygląda tak:

#ifndef jakaśnazwa_hpp
#define jakaśnazwa_hpp

int Statystyka(); //deklaracja funkcji

#endif



To nie jest nowy standard.
Jeśli się tworzy własne pliki nagłówkowe to przy ich dołączaniu należy wpisać go dodając rozszerzenie _hpp.cpp przy stosowaniu języka C++ np. #include "nazwa_hpp.cpp".
Takie ma właściwości IDE Dev-Cpp.
A jeśli dołącza się pliki nagłówkowe które są w katalogu include to podaje się nazwę tak jak w katalogu include np. #include <cstdlib>
#include <iostream>

  • 0

#12 Kazeeny

Kazeeny

    Stały użytkownik

  • 209 postów

Napisano 19 07 2010 - 21:04

#include "jakaśnazwa_hpp.cpp" w funkcji main().

Ciekawe... Z reguły dołącza się pliki nagłówkowe, a nie .cpp (przynajmniej tego mnie uczyli na programowaniu)
I dla porządku programu powinno się dołączać dyrektywy na samym początku programu, a nie w żadnych funkcjach.

Jeśli się tworzy własne pliki nagłówkowe to przy ich dołączaniu należy wpisać go dodając rozszerzenie _hpp.cpp przy stosowaniu języka C++ np. #include "nazwa_hpp.cpp".
Takie ma właściwości IDE Dev-Cpp.

Dosyć długo pracowałam w Dev-C++ i w trybie tworzenia projektu czegoś takiego nie stosowałam. Podejrzewam, że wiem, co robisz...
Tworząc projekt w Dev-C++ trzeba wykonać następujące czynności:
1. Klikamy Plik | Nowy | Projekt
2. Wybieramy Console Application oraz wpisujemy nazwę projektu; zapisujemy projekt
3. W tej chwili nam się otwiera w zakładce szablon pliku main.cpp, który możemy dowolnie modyfikować
4. Z lewej strony mamy okienko, w którym znajduje się ikonka i nazwa naszego projektu (np. Projekt1) - rozwijamy to i widzimy, jakie pliki są dołączone do projektu
5. Klikamy PPM na Projekt1 i wybieramy opcję "Nowy plik", jeżeli chcemy pisać od początku nagłówki (*.h lub *.hpp) i pliki implementacyjne (*.cpp), w przeciwnym razie klikamy na "Dodaj do projektu" (zwracając uwagę na to, gdzie dokładnie zapisane są te pliki, żeby potem nie było problemów z ich dołączaniem i linkowaniem)
6. Po ukończeniu pisania poszczególnych modułów/programu dopisujemy dyrektywy #include "nazwaheadera.h" (ale dołączamy tylko nagłówki!)
7. Budujemy i kompilujemy program (Uruchom | Kompiluj i uruchom; ew. klawisz F9) - jeżeli program poprawnie się skompiluje, to program będzie działać

Więc moje pytanie brzmi... Czy tworzysz projekt w ten sposób? Czy po prostu piszesz poszczególne pliki oddzielnie (nie w trybie projektu) i wszystko dołączasz w pliku main?

Użytkownik Katarina edytował ten post 19 07 2010 - 21:06

  • 0

#13 Pakrys

Pakrys

    Początkujący

  • 31 postów

Napisano 20 07 2010 - 07:48

Jeśli tworzę projekt wielopilkowy to postępuję wg. podanego opisu. Ale wpierw na dysku tworzę katalog do którego zapiszę projekt.
Głos w tej sprawie zabrałem dlatego że piszę programy w IDE Dev-Cpp i początkowo pliki nagłówkowe pisałem z rozszerzeniem .hpp dla języka C++. Kompilator wyrzucał błędy i nie mogłem się zorientować co to jest bo komunikaty błędów były dla mnie nie zrozumiałe,ale doszedłem do tego.
Dev-Cpp ma swoją specyfikę i jeśli tworzę projekt wieloplikowy to pliki nagłówkowe dołączam podając rozszerzenie _hpp.cpp.
Przykładowo wygląda to tak:

#include<cstdlib>
#include<iostream>
#include<iomanip>
#include "funkcja1_hpp.cpp"

using namespace std;





int main(int argc, char *argv[])
{

linijki kodu

system("PAUSE");
return EXIT_SUCCESS;
}

Tak napisany program kompiluje mi się bez błędów.

Istniej też inny sposób tworzenia projektu wieloplikowego bez tworzenia plików nagłówkowych.
Dyskusja w tej sprawie nie powinna iść w kierunku Ty głupi a Ja mądry tylko przedstawiać jak problem rozwiązać.
Opis jak tworzyć programy wieloplikowe opisane są na stronie http://kursy.ddt.pl

Użytkownik Pakrys edytował ten post 20 07 2010 - 08:00

  • 0

#14 Kazeeny

Kazeeny

    Stały użytkownik

  • 209 postów

Napisano 20 07 2010 - 20:08

Mały offtop:

Dev-Cpp ma swoją specyfikę i jeśli tworzę projekt wieloplikowy to pliki nagłówkowe dołączam podając rozszerzenie _hpp.cpp.

Dev-C++ jest prostym środowskiem, już nierozwijanym (i posiadającą starą wersję kompilatora) - dla mnie służył głównie do pisania jednoplikowych programów. W ostatnim czasie raz lub dwa razy potrzebowałam go do stworzenia projektu i opierałam się na schemacie, który wcześniej podałam. Nagłówki były typu *.h, dlatego mnie zdziwiło, że dla *.hpp jest inaczej. I dlatego zdecydowanie preferuję MS Visual Studio :D
//edit: oho, nawet zniknęła z internetu oficjalna strona producenta środowiska
/end of offtop/

Użytkownik Katarina edytował ten post 20 07 2010 - 20:12

  • 0

#15 Pakrys

Pakrys

    Początkujący

  • 31 postów

Napisano 21 07 2010 - 06:13

Swoje IDE Dev-Cpp zmodyfikowałem. Kompilator MinGw zastąpiłem nowszą wersją.
Można ze strony http://nuwen.net/mingw.html pobrać kompilator rozpakować go i zastąpić katalogi bin,include,lib,libexec nowszą wersją tą z podanej strony.

  • 0

Zobacz więcej tematów z tagiem: język C++



Użytkownicy przeglądający ten temat: 0

0 użytkowników, 0 gości, 0 anonimowych