Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[C++]Program sprawdzający słówka z języka angielskiego.

Gaatt 20 Maj 2011 22:36 2511 18
  • #1 20 Maj 2011 22:36
    Gaatt
    Poziom 10  

    Witam! Oto fragment programu C++ , który najpierw losuje słówka, a następnie sprawdza naszą wiedzę (na razie tylko wyświetla słówka). Nie jestem pewien czy właściwie użyłem tablicy, która zapisuje otrzymane wyniki w losowaniu. Kompilator wyświetla następujące błędy:

    Error 1 error LNK2001: unresolved external symbol "enum WYBOR g_Wybor" (?g_Wybor@@3W4WYBOR@@A) C:\Documents and Settings\mariusz\moje dokumenty\visual studio 2010\Projects\Słówka\Słówka\functions.obj

    Error 2 error LNK1120: 1 unresolved externals C:\Documents and Settings\mariusz\moje dokumenty\visual studio 2010\Projects\Słówka\Debug\Słówka.exe
    Nie wiem jak to poprawić.
    Pliki:

    plik functions.h

    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    plik main.cpp

    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    plik functions.cpp
    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    Proszę o pomoc.

    0 18
  • #2 21 Maj 2011 02:20
    lolcio
    Poziom 16  

    Jeżeli nie masz wprawy w używaniu tablic to ich nie używaj :) Bezpieczniejszym mechanizmem będzie tutaj vector oraz biblioteka string. Użycie tych klas znacznie ułatwi Ci pisanie kodu i zmniejszy ilość kodu.

    Kodu dość dużo napisałeś i widzę tam biblioteke conio.h (mam linuxa) więc nie będe przerabiał tego na linuxa, a na pierwszy rzut oka nie widze błedu. Może spróbój zastąpić enumeratory zmiennymi boolowskimi?

    W załączniku słownik który napisałem z użyciem obiektowośći. Może coś Ci w czymś pomoże ten kod.

    Pozdrawiam

    0
  • #3 21 Maj 2011 13:17
    Gaatt
    Poziom 10  

    Właśnie o to chodzi, że muszę się nauczyć tablic. Jednak wrócę do pytania: Co mam zmienić, aby program dał się skompilować?

    0
  • Pomocny post
    #4 21 Maj 2011 15:22
    lolcio
    Poziom 16  

    Na początku pliku functions.cpp masz deklaracje obiektu STAN
    (STAN g_Stan = S_POCZATEK) natiomiast g_wybor był zdefiniowany ale nie zadeklarowany. Wystarczyło dopisać na początku pliku deklaracje WYBOR g_Wybor;

    W załączniku masz ten plik, u mnie się kompiluje. Pozbyłem się ostrzeżeń (a było ich 8 :P ) ale nie testowałem poprawności programu, poprostu skompilowałem :)

    0
  • #5 21 Maj 2011 15:46
    Gaatt
    Poziom 10  

    Udało mi się rozwiązać problem.
    Wpisałem w pliku functions.cpp formułę:

    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    Dodano po 6 [minuty]:

    Pojawił się jednak kolejny problem. Po otwarciu pliku exe następuje otworzenie oraz natychmiastowe zamknięcie konsoli. Oto tekst skopiowany z "Output":

    'Słówka.exe': Loaded 'C:\Documents and Settings\mariusz\Moje dokumenty\Visual Studio 2010\Projects\Słówka\Debug\Słówka.exe', Symbols loaded.
    'Słówka.exe': Loaded 'C:\WINDOWS\system32\ntdll.dll', Cannot find or open the PDB file
    'Słówka.exe': Loaded 'C:\WINDOWS\system32\kernel32.dll', Cannot find or open the PDB file
    'Słówka.exe': Loaded 'C:\WINDOWS\system32\msvcp100d.dll', Symbols loaded.
    'Słówka.exe': Loaded 'C:\WINDOWS\system32\msvcr100d.dll', Symbols loaded.
    The program '[2540] Słówka.exe: Native' has exited with code 0 (0x0).

    Myślę, że problem tkwi w "Cannot find or open the PDB". Jednak nie wiem jak to naprawić. Za wszelką pomoc z góry dziękuję.

    0
  • Pomocny post
    #6 21 Maj 2011 15:51
    lolcio
    Poziom 16  

    Ta "formuła" to deklaracja zmiennej typu enum. :)

    U mnie Twój program nie wyrzuca błedów...takie uroki linuxa :P
    Jakiego środowiska używasz? Może pora nauczyć się korzystać z debugera?
    Postaw kilka pułapek w programie i zobacz do którego momentu sie wykonuje...
    pułapkami debugera szybko znajdziesz błędną linijke kodu.

    0
  • #7 21 Maj 2011 21:03
    Gaatt
    Poziom 10  

    Korzystam z Microsoft Visual Studio C++ Express 2010. Nie zamieszczał bym pytania na forum, gdybym sam uprzednio nie spróbował go rozwiązać. Sprawdzałem działanie programu w trybie krokowym. Oto niedziałający pierwszy fragment programu:

    plik functions.h

    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    plik main.cpp
    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    plik functions.cpp
    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    Do case 0 i default jeszcze nic nie napisałem, ale to nie ma wpływu na działanie programu.Moim zdaniem wszystko jest w porządku, a jednak nie działa. Proszę o pomoc.

    Dodano po 30 [minuty]:

    I jeszcze jedno: kompilacja przebiega prawidłowo, lecz program nie działa poprawnie.

    0
  • #8 21 Maj 2011 22:37
    Xitami
    Poziom 29  

    Code:
    char * t[]={"cat","dog","hamster","mouse"};
    

    main(){
       int i;
       for(i=0; i<sizeof(t)/sizeof(t[0]); i++)
          puts(t[i]);
    }

    0
  • #9 22 Maj 2011 16:21
    Gaatt
    Poziom 10  

    Znalazłem błąd. W pliku main.cpp należało nie pisać "bool".

    Dodano po 4 [godziny] 4 [minuty]:

    Pojawiły się kolejne błędy, które nie wiem jak mam naprawić.
    Oto całe pliki:
    functoins.h

    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    main.cpp
    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    functoins.cpp
    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    A oto błędy w 10 i 11 linijce pliku main.cpp:
    function does not take 0 arguments 10
    function does not take 0 arguments 11
    too few arguments in function call 10
    too few arguments in function call 11

    Proszę o pomoc.

    0
  • Pomocny post
    #10 22 Maj 2011 18:05
    lolcio
    Poziom 16  

    W załączniku poprawiony kod, który się kompiluje.

    Takie drobne uwagi odemnie:
    1. Wywal te conio.h, biblioteka iostream ma wszystko czego potrzebujesz, a conio nie jest przenośne na inne systemu.

    2. NIGDY nie pisz deklaracji zmiennych w taki sposób:
    unsigned zmienna;
    Unsigned nie jest typem! Jest to słowo zastrzeżone przez kompilator i oznacza że dana zmienna jest beznakowa, czyli jest dodania. Ale wypadałoby powiedzieć kompilatorowi jakiego typu będzie ta zmienna beznakowa i napisać:
    unsigned int zmienna;


    3. Jeżeli piszesz nagłowek funkcji która ma parametry, to gdy piszesz definicje tej funkcji to argumenty są takie same, stąd miałeś teraz błedy w kodzie. Otóż nagłówek Twojej funkcji powinien być:

    bool SlowkaANG(unsigned int* aLiczby=NULL);

    Gdzie parametrem tej funkcji jest wskaźnik na tablice przechowującom beznakowe INTY. Parametr ten ma wartość domyślną (nie wiem czy w Twojej funkcji to ma sens, mówie jak powinna wyglądać składnia) adres na który nic nie może wskazywać, (wcale nie jest to 0 :P .
    Ale jaka jest wartość domyślna parametru piszesz tylko raz, w nagłówku funkcji jeżeli taki masz, natomiast ciało funckji wygląda tak:

    bool SlowkaANG(unsigned int* aLiczby)
    {
    ble ble...
    }

    Jak widzisz parametry zawsze są takie same (o ile nie przeciążasz oczywiście) ale wartości domyślnej parametru już nie musisz pisać, bo już ją kompilator zna.

    0
  • #11 22 Maj 2011 21:30
    Gaatt
    Poziom 10  

    Dziękuję Ci za rozwiązanie problemu.

    To mam kolejne pytanie dlaczego nie mogę zmienić

    Kod: cpp
    Zaloguj się, aby zobaczyć kod
    na
    Kod: cpp
    Zaloguj się, aby zobaczyć kod
    oraz
    Kod: cpp
    Zaloguj się, aby zobaczyć kod
    na
    Kod: cpp
    Zaloguj się, aby zobaczyć kod
    I jeszcze nie do końca rozumiem
    Kod: cpp
    Zaloguj się, aby zobaczyć kod
    Czy mógłbyś wytłumaczyć mi kolejno wszystkie użyte słowa?

    0
  • Pomocny post
    #12 22 Maj 2011 22:25
    lolcio
    Poziom 16  

    Wyrażenie unsigned aLiczby[ILOSC_LICZB] jest poprawne w nowszym standardzie języka. Jeżeli tylko ILOSC_LICZB jest zadeklarowana to powinno wszystko śmigać :)
    Natomiast kod:

    Code:
    return aLiczby[3] && true ;

    jest błedny! Funkcje w c++ mogą zwracać przez nazwe tylko jedną zmienną, może to być tablica danych,bądz cokolwiek innego ale nigdy nie można zwrócić dwóch lub więcej zmiennych przez nazwe funkcji tak jak Ty to robisz.
    Nie rozumiem czemu kompilator pozwala na takie wyrażenie, zawsze jest ono równe 1. Więc Twoja funkcja zwraca zawsze true, zauważ że jest ona typu bool a Ty chcesz zwrócić liczbe int.
    (unsigned kompilator traktuje jako unsigned int, ale nie jest to dobrym zwyczajem tak pisać )
    Musisz zdecydować czy ta funkcja ma zwracać bool, czy int...bądz też może tablice int-ów?
    Jeżeli unsigned aLiczby[ILOSC_LICZB] jest przyczyną błędów kompilacji to sprawdz czy ILOSC_LICZB jest zadeklarowana wcześniej.

    Code:
    bool SlowkaANG(unsigned int* aLiczby = NULL)


    bool - funkcja zwraca prawda, albo fałsz, nic więcej.

    SlowkaANG - nazwa funkcji :P :P

    unsigned int* aLiczby - parametrem funkcji jest wskaźnik do beznakowej liczby całkowitej.
    Pod tym wskaźnikiem może siedzieć jakaś dodatnia liczba, bądz adres tablicy unsigned int.

    =NULL - oznacza że jeżeli wywołamy funkcje zapominajać o argumencie to kompilator podstawi sobie w to miejsce tą wartość którą wpisałeś jako argument domniemany.

    np.
    unsigned int liczba=12;
    SlowkaAng(&liczba);

    np.
    SlowkaAng();

    np.
    unsigned int tabInt[2];
    tabInt[0]=12;
    tabInt[1]=11;
    SlowkaAng(tabInt); //nazwa tablicy to jednocześniej jej adres

    np.
    int* wskInt;
    SlowkaAng(wskInt);

    0
  • #13 23 Maj 2011 18:32
    Gaatt
    Poziom 10  

    Pierwszy raz się spotykam z * w C++. Jak i gdzie dokładnie się jej używa?
    Jak zwrócić całą tablicę liczb, a następnie w kolejnej funkcji z niej korzystać?
    Oto proste dwie funkcje. Co mam zmienić aby działały?

    Kod: cpp
    Zaloguj się, aby zobaczyć kod

    Co mam wpisać w return oraz w () funkcji? Za odpowiedź na którekolwiek z pytań , dziękuję.

    0
  • Pomocny post
    #14 23 Maj 2011 19:13
    beluosus
    Poziom 25  

    Gaatt napisał:
    Pierwszy raz się spotykam z * w C++. Jak i gdzie dokładnie się jej używa?

    To wręcz śmietanka w C/C++. ;) Operator wyłuskania może nie jest obszernym tematem do opisania, ale na pewno ciężkim do zrozumienia dla początkujących. Tutaj temat ten jest bezpośrednio związany ze wskaźnikami, a co za tym idzie również i z operatorami new, delete. Musisz poczytać o tym i zrobić sporo przykładów. W grę wchodzi bezpośrednia manipulacja pamięcią więc trzeba być ostrożnym. * zwraca obiekt/wartość pod danym adresem, a & pobiera adres danego obiektu/zmiennej.

    Kod: cpp
    Zaloguj się, aby zobaczyć kod

    0
  • #15 23 Maj 2011 20:20
    Gaatt
    Poziom 10  

    Proszę także o odpowiedzi do pozostałych zadanych przeze mnie pytań.

    0
  • #16 23 Maj 2011 20:46
    lolcio
    Poziom 16  

    Bardzo prosto wytłumaczone są wskaźniki w książce "symfonia c++" Grębosza. Ogólnie bardzo dobry podręcznik dla początkujących, warto troche z niego poczytać ;)

    Wskaźnik to jak sama nazwa wskazuje obiekt który może wskazywać na inny obiekt, a konkretnie przechowuje jego adres np.

    Code:

    int x; //nasza zmienna, na ktora ma pokazywac wskaznik

    int* wsk; //wskaznik na obiekt typu int, jeszcze na nic nie pokazuje

    wsk=&x;


    &-ampersant operator wyluskania adresu, wyciąga informacje gdzie jest w pamięci ukrywa się dana zmienna (w tym przypadku x) czyli jaki jest adres zmiennej. Dobrze to pokaże prosta linijka:
    Code:
    std::cout<<"wartosc zmiennej:"<<x<<"adres zmiennej:"<<&x; 

    Ładnie pokaże Ci się najpierw wartość x, a potem jego adres czyli jakaś dlugaśna liczba szesnastkowa.
    Wracając do przykładu... int* wsk jest zmienna wskaźnikową, czyli taką w której siedzi adres., i instrukcją wsk=&x; pobieramy adres x i wkładamy go do zmiennej wsk :) czyż to nie jest piękne? :P Język wysokiego poziomu a pozwala nam grzebać w pamięci ;)

    Od kiedy przypiszemy adres iksa zmiennej wsk, możemy wskaźnikiem zmieniać x. W końcu pokazuje na niego. np.
    Code:

    *wsk=12; 


    Teraz pojawiło się inne użycie "gwiazdki". Otóż * raz służy do tworzenia wskażników, a raz służy do odwoływania się do wartości ukrytej pod wskażnikiem. Grębosz w swojej książce bardzo fajną metaforą wyjaśnił o co chodzi...było to coś w tym stylu:
    "Wskaźnik to informacja o tym w jakiej konstelacji leży jakaś planeta, natomiast * to statek kosmiczny który nas tam zabiera abyśmy mogli coś zrobić na tej planecie"
    Tak więc *wsk=12 to lot statkiem do miejsca gdzie jest zmienna i nadanie jej wartości 12 ;)
    Code:

    cout<<*wsk<<x;

    Odkąd wsk zaczął wskazywać na x oba wyrażenia są równoważne. No to tyle w telegraficznym skrócie :) Radzę poczytać o tym i zacząć tego używać, bo to jest szalenia ważna rzecz w c++. Jeżeli zrozumiałeś co napisałem bez problemu powiesz co pokaże taka instrukcja:




    Code:
    cout<<&wsk;
    ;) :P

    Dodano po 22 [minuty]:

    Sorki że tak jedno pod drugim ale nie zauważyłem że odpisałeś a nie chciałem mieszać w tamtym.

    Jak zwrócić tablice przez nazwe funkcji? Tak:
    Code:

    int* funkcja(){
        int ile;
        std::cin>>ile; //wczytujemy ile elementow ma miec tablica
        int tab[ile]; //tworzenie tablicy, chodz powinno to inaczej wygladac, ale nie bede CI mieszac
        for(int i=0; i<ile; ++i)
        std::cin>>tab[i]; //wczytujemt elementy tablicy

    return tab;  //nazwa tablicy to jednoczesnie wskaznik na jej poczatek, wiec tyle wystarczy zwrocic
    }

    int main()
    {
    int *dane; //tworzymy wskaznik ktory pokazuje na inty. Moze pokazywac zarowno na int x jak i na int tab[cos tam]

    dane=funkcja(); //nasza funkcja zwraca tablice intow, i przypisujemy jej adres to wskaznika na int, tak mozna :)

    std::cout<<dane[1]; // i od tej pory wskaznik dane to tablica, i mozemy się nią normalnie posługiwać

    }


    Twoj przykład poprawiony składniowo:
    Code:
    int*  /* funcja ma zrwacac wskaznik na tablice int*/  funkcja_1()
    
    {
         int Liczby[3];
         srand (static_cast<unsigned int>(time(NULL)));
         for(int i=0 ; i<3 ; ++i)
         {
             Liczby[i] = rand() % MAKSYMALNA_LICZBA + 1;
         }
         return Liczby; //zwracanie tablicy liczb
    }

    void funkcja_2(int *aLiczby/*adres tablicy na ktorej mamy pracowac
                  jezeli nie chcesz przypadkiem cos w niej zmienic to dopisz const*/
                   , int ILOSC_LICZB/*to chyba zbedne jezeli jest globalne*/)
    {
         for (unsigned int /*ech...*/ i = 0; i < ILOSC_LICZB; ++i)
         std::cout << aLiczby[i] << " ";
         std::cin.get();
         
         //funkcja jak rozumiem ma tylko wyswietlac? jesli tak to powinna byc void
    }


    Chyba na wszystkie pytanie odpowiedziełem :)

    0
  • #17 24 Maj 2011 20:43
    Gaatt
    Poziom 10  

    Niestety nie mogę sobie dalej poradzić z tym programem :( . Kompiluje się, ale nie działa poprawnie. Czy mógłby Pan wprowadzić takie zmiany w kodzie, aby program pracował właściwie? Pliki są w załączniku.

    0
  • #18 24 Maj 2011 20:54
    beluosus
    Poziom 25  

    Nie patrzyłem na całość, ale problem wydaje się być oczywisty:

    Kod: cpp
    Zaloguj się, aby zobaczyć kod

    Adres tablicy (a nie tablica jako całość) jest zwracany jako wynik funkcji, ale jest to tablica lokalna. Oznacza to, że po wyjściu z zakresu (czyli poza nawiasy {} klamrowe) zmienne/obiekty są niszczone. Powoduje to zwrócenie adresu pamięci, która jest już zwolniona i nie znajduje się już tam nic konkretnego (i najczęściej nie mamy dostępu do tego fragmentu pamięci). Popatrz na kod z mojego poprzedniego postu - przekazuję tablicę w argumencie.

    0
  • #19 24 Maj 2011 21:41
    lolcio
    Poziom 16  

    Troszkę Ci dopisałem i słownik wyświetla albo polskie albo angielskie wyrazy :)
    Faktycznie było małe niedomówienie odnośnie tego adresu zwracanego przez funkcje...
    Beluosus ma racje że są to obiekty lokalne i są usuwane, chodz mi pare razy działało takie rozwiązanie :P Ale usunąłem na wszelki wypadek to, i dane są zwracane prze wskaźnik a nie przez nazwe. Chyba napisałem Ci to co chciałeś :P :)

    Spociłem się przerabiając te Twoje if-y..naprawde jest to bardzo niepoważne rozwiązanie. W drugim poscie w załączniku masz mój słownik wraz z interefejsem graficznym w qt. Zobacz sobie pliki dictionary.h i dictionary.cpp to jest biblioteka słownika, zrobiona na vectorach (takie intligentne tablice ;) ) polecam takie rozwiązanie, jest bardzo wygodne.

    0