• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

[C++] - Działanie pętli z warunkiem tablicy oraz problem z getchar().

Object Storage Arubacloud
+1 głos
709 wizyt
pytanie zadane 8 stycznia 2016 w C i C++ przez xCodezaur Bywalec (2,850 p.)
edycja 4 lutego 2016 przez xCodezaur

Witam,

Poproszę o wyjaśnienie działania pętli (jej warunku) zamieszczonej poniżej w kodzie:

#include <iostream>
#include <stdio.h>

using namespace std;

string wyraz;

int main()
{
    cout << "Napisz program ktory rozbroi wyraz na litery." << endl << endl << endl;

    cout << "Podaj wyraz: ";
    cin >> wyraz;

    cout << endl << endl;

    for (int i=0; i<wyraz[i]; i++)
    {
        cout << "Litera " << i+1 << ": " << wyraz[i] << endl;
    }




    getchar(); getchar();

    return 0;
}

Program ten oczywiście działa poprawnie, lecz nie wiem dlaczego. Postawiłem taki warunek w pętli z ciekawości, a okazał się rozwiązaniem problemu. Teraz wiem, że można użyć funkcji ".length()", lecz pisząc ten program jeszcze o niej nie wiedziałem. Proszę o wyjaśnienie, jestem początkujący w nauce C++.

Proszę również o wyjaśnienie, dlaczego w tym programie musiałem użyć funkcji getchar(); 2 razy, a w innych programach używać tej funkcji trzeba tylko raz. Myślę, że jest jakieś rozwiązanie, ponieważ skąd programiści wiedzieli by ile razy użyć ją w swoim kodzie, a raczej nikt by nie chciał bawić się w strzelanie.

Z góry dziękuje za poświęcenie czasu na odpowiedź smiley

2 odpowiedzi

+2 głosów
odpowiedź 8 stycznia 2016 przez Patrycjerz Mędrzec (192,320 p.)
wybrane 8 stycznia 2016 przez xCodezaur
 
Najlepsza

Program działa, ponieważ na końcu ciągu znaków zawsze występuje NULL, czyli w kodzie ASCII po prostu 0. Ta liczba nie jest większa od zmiennej i, która posiada wartość większą od zera i program wychodzi z pętli.

Co do tego getchar, to wywołuj go jeden raz - tego podwójnego użycia to nawet ja nie rozumiem wink

komentarz 8 stycznia 2016 przez Patrycjerz Mędrzec (192,320 p.)

Zapomniałem dodać, że NULL na końcu występuje przy ciągach postaci:

"Ala ma kota"

Gdy stworzysz tablicę i ręcznie przypiszesz do niej znaki (nie przez "równa się tekst w nawiasie"), to nie powinieneś tej wartości uświadczyć.

komentarz 8 stycznia 2016 przez xCodezaur Bywalec (2,850 p.)
Wielkie dzięki za odpowiedź. Teraz już to rozumiem, a co do tego getchar(); to właśnie jak nie raz użyję jeden raz to program się wyłącza od razu, tak jakby tego nie widział dlatego pytałem, ale nie wszystko muszę wiedzieć na sam początek :)
komentarz 8 stycznia 2016 przez Patrycjerz Mędrzec (192,320 p.)

Tutaj wszystkiemu jest winien zapełniony bufor. Zastosuj metodę sync:

std::cin.sync();

Dzięki niej bufor zostanie oczyszczony, a funkcja getchar będzie oczekiwać na kolejny znak (gdyż bufor jest pusty).

To dwukrotne wywołanie getchar jest trochę metodą chałupniczą, ponieważ korzysta się tu z tego, że funkcja po zakończeniu wczytywania czyści w międzyczasie bufor, ale jest to błąd metodyczny i powinno się stosować tu sync.

komentarz 8 stycznia 2016 przez xCodezaur Bywalec (2,850 p.)
Dzięki, od teraz będę to stosował :)
+4 głosów
odpowiedź 8 stycznia 2016 przez Sebastian Fojcik Nałogowiec (43,020 p.)
edycja 8 stycznia 2016 przez Sebastian Fojcik

Twój zapis: wyraz[ i ] nie ma nic wspólnego z wyraz.length(). Troszkę pomyliłeś pojęcia. Twój zapis jest oczywiście błędny, a swoje działanie zawdzięcza szczęściu :-D
Spróbuję Ci wytłumaczyć dlaczego to działa i dlaczego na farcie.

Powiedzmy, że wprowadzasz tekst "abc". W takim razie Twój string "wyraz" zawiera następujące dane:

wyraz[ 0 ] = 'a';
wyraz[ 1 ] = 'b';
wyraz[ 2 ] = 'c';

I Twoja pętla wygląda tak:

for (int i=0; i<wyraz[i]; i++)

Skupię się na warunku kończącym tę pętlę. Czyli: i < wyraz[ i ]. Zadam kilka pytań, na które sam odpowiem:
Czym jest "i"? To jest int, który będzie przyjmował kolejne wartości 0, 1, 2, 3, 4....
Czym jest wyraz[ i ]? To jest konkretny znak o indeksie kolejno: 0, 1, 2, 3, 4...
Czym jest w takim razie: i < wyraz[ i ]? Jest to porównanie int'a ze znakiem char. W takim przypadku zachodzi niejawna konwersja. To znaczy, ze znak char jest traktowany jak liczba int i wtedy program sobie porównuje te wartości.

Co to dla nas oznacza? To oznacza, że litera 'a' jest zamieniona na liczbę. Jaką? Zgodnie z tablicą ASCII 'a' = 97. W takim razie:
W pierwszej iteracji pętli: porównujemy i = 0 oraz wyraz[ 0 ] = 'a' = 97. W efekcie mamy: 0 < 97. To jest prawda, więc pętla sie wykonuje.
Druga iteracja: i = 1 oraz wyraz[ 1 ] = 'b' = 98. Czyli teraz mamy sprawdzenie: 1 < 98. Prawda. Pętla się wykonuje, zwiększamy i++ i jedziemy dalej.
Trzecia iteracja: i = 2 oraz wyraz[ 2 ] = 'c' = 99. Czyli sprawdzamy czy: 2 < 99. Prawda. Lecimy dalej. Teraz uwaga.
Czwarta iteracja: i = 3 oraz wyraz[ 3 ] = ? No właśnie! CO teraz? Nie ma trzeciego elementu. Jak się zachowa nasz string? Wywali błąd i program się scrashuje? Otóż nie. Jeżeli odniesiemy się do elementu o indeksie o jeden większym niż rozmiar tablicy, to wtedy string zwraca NULL, czyli znak '\0'. Ten znak ma numer 0. Teraz konkluzja moich rozważań:
porównujemy czy i = 3 jest mniejsze od wyraz[ 3 ] = '\0' = 0. Czyli czy: 3 < 0.
To jest nieprawda, pętla się kończy.

Myślę, że po tym wszystkim rozumiesz dlaczego to działa. A teraz wyjaśnię Ci dlaczego to źle działa.

Program jest niestabilny, to znaczy, ze są przypadki, dla których może podać niepoprawny wynik albo O ZGROZO, wypluć błąd (u Ciebie akurat nie będzie błędu). Litera 'a' ma numer 97. W związku z czym, aby Twój wspaniały algorytm nie zadziałał wystarczy podać 98 liter 'a'. Coś takiego:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa... i tak do 98 literek.
Wtedy Twój program policzy tylko 97 liter i zakończy pętle. A to dlatego, że podczas 98 iteracji zajdzie taki warunek:

Iteracja 98: W 98 iteracji i = 97 (numerowaliśmy od 0), natomiast wyraz[ 97 ] = 'a' = 97. Czyli sprawdzamy czy: 
97 < 97. Fałsz, koniec pętli pomimo tego, że są jeszcze litery do wczytania!

Teraz powinieneś rozumieć, że czasami to, że coś działa, wcale nie oznacza, że to działa :-)
Pozdrawiam.

komentarz 8 stycznia 2016 przez Munvik Dyskutant (9,350 p.)
Wysoki poziom wyjaśnienia, dzięki :D !
komentarz 8 stycznia 2016 przez xCodezaur Bywalec (2,850 p.)
Wielkie dzięki za odpowiedź. Chciałbym Cię wyróżnić, ale niestety nie da się dać dwóm osobą najlepszej odpowiedzi :/

Bardzo ładnie wytłumaczyłeś to wszystko, na pewno twoja odpowiedź nie pójdzie na marne :)

Z tym wyraz.length(); chodziło mi o to, że można policzyć za pomocą niego ilość liter i wtedy wstawić do warunku pętli jego wartość, faktycznie mogło się zdawać, że się pomyliłem.

Jeszcze raz wielkie dzięki.
1
komentarz 4 lutego 2016 przez draghan VIP (106,230 p.)

Teraz powinieneś rozumieć, że czasami to, że coś działa, wcale nie oznacza, że to działa :-)

Piękny cytat, Sebastian. ^^

Podobne pytania

0 głosów
3 odpowiedzi 23,547 wizyt
pytanie zadane 22 kwietnia 2015 w C i C++ przez falauthy Stary wyjadacz (11,550 p.)
+1 głos
4 odpowiedzi 166 wizyt
0 głosów
1 odpowiedź 283 wizyt
pytanie zadane 28 stycznia 2023 w JavaScript przez Verone Nowicjusz (120 p.)

92,552 zapytań

141,399 odpowiedzi

319,534 komentarzy

61,938 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...