![Zdjęcie](https://www.forum.tweaks.pl/public/style_images/master/profile/default_large.png)
[C++] Dev-C++ - błędy linkera
#1
Napisano 03 05 2010 - 17:11
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.
#2
Napisano 03 05 2010 - 19:48
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
#3
Napisano 03 05 2010 - 20:50
To jest w mainie.#include <iostream>
#include <cstdlib>
#include "modMenu"
#include "modFunkcje"
using namespace std;
int main(int argc, char *argv[])
{PokazMenu();
system("PAUSE");
return EXIT_SUCCESS;
}
]
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
#4
Napisano 03 05 2010 - 22:21
![:omg:](/public/style_emoticons/default/biggrin.gif)
#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
#5
Napisano 03 05 2010 - 23:15
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);
}
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)
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
#6
Napisano 03 05 2010 - 23:22
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: #endifTo 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
#7
Napisano 03 05 2010 - 23:32
#8
Napisano 04 05 2010 - 15:12
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.
#9
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
#10
Napisano 19 07 2010 - 12:47
#11
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>
#12
Napisano 19 07 2010 - 21:04
Ciekawe... Z reguły dołącza się pliki nagłówkowe, a nie .cpp (przynajmniej tego mnie uczyli na programowaniu)#include "jakaśnazwa_hpp.cpp" w funkcji main().
I dla porządku programu powinno się dołączać dyrektywy na samym początku programu, a nie w żadnych funkcjach.
Dosyć długo pracowałam w Dev-C++ i w trybie tworzenia projektu czegoś takiego nie stosowałam. Podejrzewam, że wiem, co robisz...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.
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
#13
Napisano 20 07 2010 - 07:48
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
#14
Napisano 20 07 2010 - 20:08
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 StudioDev-Cpp ma swoją specyfikę i jeśli tworzę projekt wieloplikowy to pliki nagłówkowe dołączam podając rozszerzenie _hpp.cpp.
![:D](/public/style_emoticons/default/biggrin.gif)
//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
#15
Napisano 21 07 2010 - 06:13
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.
Użytkownicy przeglądający ten temat: 1
0 użytkowników, 1 gości, 0 anonimowych