logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[C++] Jak przechowywać i wyszukiwać ciągi znaków w tablicy?

pol102 10 Sty 2011 01:48 3754 12
REKLAMA
  • #1 8984881
    pol102
    VIP Zasłużony dla elektroda
    Posty: 3085
    Pomógł: 163
    Ocena: 369
    Witam! To, że jestem moderatorem optoelektroniki nic nie znaczy :)
    Jestem w trakcie uczenia się programowania i za cel postawiłem sobie przeszukiwanie tablicy o stałym rozmiarze, wypełnionej dowolnym wyrazem, i wyświetlanie ile razy dany wyraz w niej występuje.

    Problemy, których nie umiem przeskoczyć:
    - zdefiniowanie tak tablicy oraz zmiennej 'szukana' by mogły przechowywać więcej niż jedną literę (char to raczej złe rozwiązanie)
    - jeśli program znajdzie zdefiniowaną zmienną ma wyświetlić cały wiersz (nie mam pomysłu jak można to zrealizować)
    - co oznacza błąd z tytułu?

    Wskazówki czego nie robić w kodzie też mile widziane.

    Kod: text
    Zaloguj się, aby zobaczyć kod
  • REKLAMA
  • Pomocny post
    #2 8985028
    Terminator
    Poziom 23  
    Posty: 392
    Pomógł: 65
    Ocena: 12
    Kod: text
    Zaloguj się, aby zobaczyć kod
    zamień na
    Kod: text
    Zaloguj się, aby zobaczyć kod
    dla pojedyńczych znaków.

    Cytat:
    zdefiniowanie tak tablicy oraz zmiennej 'szukana' by mogły przechowywać więcej niż jedną literę (char to raczej złe rozwiązanie)

    to zainteresuj się tablicą tablic znaków :) np tutaj mały tutorial
    Do porównywania ciągów znaków możesz wykorzystać strcmp albo napisać swoją.
  • REKLAMA
  • #3 8985642
    szelus
    Poziom 34  
    Posty: 1508
    Pomógł: 315
    Ocena: 53
    pol102 napisał:

    - zdefiniowanie tak tablicy oraz zmiennej 'szukana' by mogły przechowywać więcej niż jedną literę (char to raczej złe rozwiązanie)

    To podobno C++ - bardziej interesująca (od propozycji Terminatora) będzie klasa string - http://www.cplusplus.com/reference/string/string/
    Cytat:

    - co oznacza błąd z tytułu?

    Typy char i char* (wskaźnik na char, używany również w C do napisów) nie są ze sobą bezpośrednio kompatybilne. Tutaj
    Kod: text
    Zaloguj się, aby zobaczyć kod

    usiłujesz je porównać bezpośrednio. Przez == możesz porównać dwa znaki, przez funkcję strcmp() i jej odmiany - dwa napisy. Porównywanie pojedynczego znaku z napisem jest raczej bez sensu - chyba, że chcesz porównać konkretną literę z napisu. Z tym, że jeżeli użyjesz klasy string, to strcmp() nie będzie Ci potrzebne.
  • REKLAMA
  • Pomocny post
    #4 9003211
    wlw_wl
    Poziom 38  
    Posty: 4327
    Pomógł: 208
    Ocena: 148
    Jeżeli jest to program na komputer ogólnie pojętej klasy PC, użyj string j/w.

    Jeżeli to program na mikrokontroler 8bitowy to zostań przy char'ach. :)

    Twoja tablica tab wygląda tak:
    tab[0] - dwie liczby (znaki) (tab[0][0] i tab[0][1])
    tab[1] - dwie liczby

    Wyraz w zmiennej typu char możesz zapisać na dwa sposoby.
    Kod: text
    Zaloguj się, aby zobaczyć kod

    Inaczej się możesz do nich odwołać:
    Kod: text
    Zaloguj się, aby zobaczyć kod

    Ta gwiazdka to operator wyłuskania, czyli "wyciągnięcia" tego, co się kryje pod adresem, na który wskazuje (tablica + 2), czyli literka "l". Jest to dokładnie to samo, co tablica[2].

    Co Ci to daje? Prostsza pętla:
    Kod: text
    Zaloguj się, aby zobaczyć kod


    Pytanie: po co w ogóle te wskaźniki?
    Ano dzięki nim możemy sobie w prosty sposób zapisać zdanie jako wyrazy i mieć do nich dostęp "w całości":
    Kod: text
    Zaloguj się, aby zobaczyć kod


    Więc do rzeczy - jak porównywać wyrazy? Tak:
    Kod: text
    Zaloguj się, aby zobaczyć kod

    Wynik:
    Nasze zdanie to: 'Budujemy zdanie bardzo ale to bardzo ciekawe'.
    
    Szukam w nim wyrazu 'bardzo'.
    
    Znalazlem wyraz 'bardzo' na pozycji nr. 3
    
    Znalazlem wyraz 'bardzo' na pozycji nr. 6
    


    ed: dodałem const - pisałem to tak na szybko jako przykład tutaj ;)
  • Pomocny post
    #5 9003213
    azra
    Poziom 17  
    Posty: 108
    Pomógł: 26
    Ocena: 2
    Cytat:
    Kod: text
    Zaloguj się, aby zobaczyć kod

    Raczej:
    Kod: text
    Zaloguj się, aby zobaczyć kod
    W C++ string literals ("costam") są typu const char[n], a próba ich modyfikacji (np przez wskaźnik do nich) wykopie nas do świata niezdefiniowanego zachowania, nie mówiąc już o tym, że na nowszych kompilatorach nareszcie dostaje się przynajmniej ostrzeżenie za taki kod, więc... Po prostu dodaj const. ;)

    Ponieważ C również ma już "const" tam też powinno się je dodawać. Nawet pomimo, że nie ma obowiązku, bo literały mają typ char[n]... To jednak próba ich modyfikacji wyrzuci nas w to samo miejsce co w C++. ;)
  • #6 9007719
    pol102
    VIP Zasłużony dla elektroda
    Posty: 3085
    Pomógł: 163
    Ocena: 369
    Zasadniczo gotowca nie oczekiwałem ale mimo wszystko tak wyjaśniona sprawa rozwiewa wątpliwości :)
    Wrzuciłem w Bulidera2009, skompilowałem bez błędów ale jest tak zwane zdarzenie nieoczekiwane.
    [C++] Jak przechowywać i wyszukiwać ciągi znaków w tablicy?

    Czyli nie wykonuje drugiej pętli. Pytanie dlaczego? Wskaźnik i jest zerowany więc powinno inkrementować wartość i sprawdzać...
  • #7 9007782
    azra
    Poziom 17  
    Posty: 108
    Pomógł: 26
    Ocena: 2
    Kod: text
    Zaloguj się, aby zobaczyć kod

    możesz uprościć do
    Kod: text
    Zaloguj się, aby zobaczyć kod
    (położenie * nie ma większego znaczenia, ja daję przy typie, ponieważ myślę raczej w kategoriach "silnych" typów C++, Tutaj możesz o tym poczytać.) i w odpowiednich miejscach opuścić operator dereferencji. ;)

    Co do samego problemu, jest on dość oczywisty, c-stringi (ich zawartość) porównuje się za pomocą strcmp() i rodzinki, to co teraz robisz, to porównywanie wskaźników - co jak się domyślasz w tym przypadku nie ma sensu. :)

    edit: Swoją drogą, te kody to wyglądają raczej jak C niż C++. Czy Borland w swoim Studio ma jeszcze kompilator C? Czy kompilowałeś po prostu jako C++?
  • #8 9008563
    wlw_wl
    Poziom 38  
    Posty: 4327
    Pomógł: 208
    Ocena: 148
    Czemu nie wszedł w drugą pętlę?
    Widocznie *(zdanie+i) było równe zero.
    Dlaczego? Nie wiem. Jakiś psikus kompilatora.
    Chwilę wcześniej w takiej samej pętli wypisuje całe zdanie i problemu nie ma.

    Ja * daję przy nazwie zmiennej, bo bardziej spójnie i zrozumiale wygląda przy deklaracji wielu zmiennych:
    Kod: text
    Zaloguj się, aby zobaczyć kod


    Żeby nie było wątpliwości, program ten sam, ale przy użyciu strcmp():
    Kod: text
    Zaloguj się, aby zobaczyć kod

    Ja to kompiluję na dev-cpp, alternatywą jest VS2008, wolałem go do tego nie mieszać ;)
  • REKLAMA
  • #9 9009488
    pol102
    VIP Zasłużony dla elektroda
    Posty: 3085
    Pomógł: 163
    Ocena: 369
    Założyłem, że chociażby przez podobieństwo powinno działać - skompilowane jako C++.

    Czyli można by to zrobić tak:

    w pętli while inkrementować wskaźnik 'i'
    w wyrażeniu warunkowym sprawdzać co zwraca funkcja strcmp
    jeśli zwraca zero to wyświetlić napis i podbić ponownie 'i' o jeden(?)

    Z tym pisaniem w C++ trzymając się zachowań z czystego C, jest tak, że teraz muszę nauczyć się i zaliczyć 1 semestr, a C wchodzi od 2 i nie chcę się "skrzywić" ;)

    Na czym polega wyższość printf nad cout?
  • #10 9010634
    wlw_wl
    Poziom 38  
    Posty: 4327
    Pomógł: 208
    Ocena: 148
    strcmp zwraca 0 kiedy oba stringi są takie same.
    Indeks i jest używany tutaj do odliczania kolejnych elementów w tablicy, w naszym wypadku kolejnych wyrazów.
    W moim przykładzie program wypisuje gdzie znalazł, równie dobrze może liczyć ile razy znalazł, ale wtedy potrzebujesz osobną zmienną do zliczania. Wtedy zamiast wypisywania zwiększasz tę zmienną.

    Trudno mówić o wyższości cout nad printf.
    cout jest obiektem klasy ostream i reprezentuje strumień wyjścia standardowego. Strumienie to całkiem osobna historia.
    Z Twojego punktu widzenia upraszcza to kod programu, bo nie musisz się troszczyć o to, jakiego typu zmienną wypisujesz. W ogólności strumieniem wyjściowym może być konsola, ale może też równie dobrze być nim plik, i w taki sam sposób będziesz pisał do pliku.
    Można powiedzieć, że printf to bardziej C, a cout to bardziej C++ ;)
  • #12 9012224
    wlw_wl
    Poziom 38  
    Posty: 4327
    Pomógł: 208
    Ocena: 148
    I tak jak tam dostałeś odpowiedź - zależy.
    Wiadomo, jak z każdym benchmarkiem, odpowiednio przygotowany test zawsze pokaże wyższość tego, co chcemy. Sam to w zasadzie udowodniłeś swoimi testami.
  • Pomocny post
    #13 9014846
    Dariusz Bismor
    Poziom 18  
    Posty: 150
    Pomógł: 35
    Ocena: 16
    Oj, szkoda, że tu nie zaglądałem od pewnego czasu.
    Kolego Moderatorze pol102 (nigdzie nie znalazłem imienia)!
    Przede wszystkim musisz zdecydować, jakiego stylu programowania chcesz się uczyć.

    Jeżeli jest Ci potrzebne programowanie blisko sprzętu (sterowniki dedykowane, mikrokontrolery, moduły jądra), z dwóch powodów doradzam programowanie proceduralne w języku C. Po pierwsze, do urządzeń niskiego poziomu często nie ma bibliotek języka C++. Po drugie C i programowanie proceduralne pozwala na pisanie bardziej optymalnego kodu, gdzie mamy nad wszystkim większą kontrolę. Oczywiście, możesz to dalej kompilować kompilatorem C++ i używać cout zamiast printf, ale po co? Jedyną chyba przewagą printf nad cout jest szybkość (trudno znaleźć przykład gdzie cout jest szybsze od printf).

    Jeżeli idziesz bardziej w programowanie wysokiego poziomu, np pisanie aplikacji okienkowych w Win, Qt, czy czym tam jeszcze, lub nawet aplikacji terminalowych, ale przetwarzających jakieś obiekty, wybierz styl orientowany obiektowo - złap się go mocno, trzymaj, nie puszczaj, i wyrzuć szybko do kosza wszystkie te fragmenty kodu, gdzie masz char*, czy jakikolwiek inny wskaźnik. Na wskaźniki przyjdzie czas, ale później. A teraz ćwicz obiekty: pojemniki standardowe, string-i, algorytmy standardowe, itd. Nie ulegaj pokusie nauki obydwu stylów na raz! Jednak przestrzegam: styl o.o. jest trudniejszy, często nie do przejścia bez mentora. Niemniej moim zdaniem warto.

    Ach, i jeszcze o przewadze cout: jest nią bezpieczeństwo typów. printf to funkcja o zmiennej liczbie argumentów, więc kompilator nie jest w stanie sprawdzić, czy jej wywołanie jest poprawne (dzieje się to dopiero podczas wykonania programu). Użycie cout pozwala sprawdzić już podczas kompilacji, czy użyto właściwych typów. Ponadto możliwe jest przeładowywanie funkcji operatora "<<" (wstawiania do strumienia) w celu dostosowania do swoich klas (typów), pisanie własnych manipulatorów, itd.

    HTH,
    Dariusz

Podsumowanie tematu

✨ W dyskusji poruszono problem przechowywania i wyszukiwania ciągów znaków w tablicy w języku C++. Użytkownik zmagał się z definiowaniem tablicy oraz zmiennych do przechowywania wyrazów, a także z wyświetlaniem wyników wyszukiwania. Odpowiedzi sugerowały użycie typu `std::string` zamiast `char` dla lepszej obsługi ciągów znaków oraz funkcji `strcmp()` do porównywania napisów. Wskazano również na różnice między `printf` a `cout`, podkreślając, że `printf` może być szybsze, ale `cout` oferuje większą elastyczność w kontekście typów danych. Użytkownik został zachęcony do nauki programowania proceduralnego w C, zwłaszcza w kontekście programowania bliskiego sprzętu.
Wygenerowane przez model językowy.
REKLAMA