Pętla źle działa ze stringami

0

Mam program który wczytuje dwie liczby i je porównuje. Chciałem go zrobić idiotoodpornym (żeby wywalało błędy, jeśli ktoś nie działa w zgodzie z instrukcjami), ale już nie wiem jak skonstruować ostatnią pętlę. Użytkownik ma wpisać"koniec" jeśli chce zakończyć albo "replay" jeśli chce powtórzyć. Chciałem zrobić tak, żeby po wpisaniu cokolwiek innego (nie raply i nie koniec) wyskakiwał błąd, ale poległem.

int main()
{
    float a, b;
    string replay;
    int koniec;

    cout << "Podaj liczbe a: ";
    do
    {
        Czysc();
        cin >> a;
        if ( cin.fail())
            cout << "Blad. Sprobuj ponownie: ";
    }
    while (cin.fail());

    cout << "Podaj liczbe b: ";
    do
    {
        Czysc();
        cin >> b;
        if (cin.fail())
            cout << "Blad. Sprobuj ponownie: ";
    }
    while (cin.fail());


    if ( a == b)
    cout << "Czy liczba a jest rowna liczbie b? " << "Tak" << endl;
    else cout << "Czy liczba a jest rowna liczbie b? " << "Nie" << endl;

    if ( a > b)
    cout << "Czy liczba a jest wieksza od liczby b? " << "Tak" << endl;
    else cout << "Czy liczba a wieksza od liczby b? " << "Nie" << endl;

    if ( a < b)
    cout << "Czy liczba a jest mniejsza od liczby b? " << "Tak" << endl;
    else cout << "Czy liczba a jest mniejsza od liczby b? " << "Nie" << endl;

    if ( a!= b)
    cout << "Czy liczba a jest rozna od b? " << "Tak"<< endl;
    else cout << "Czy liczba a jest rozna od b?  " << "Nie" << endl;
    cout <<"Jesli chcesz sprobowac jeszcze raz, napisz: \"replay\" lub \"koniec\", jezeli chcesz zakonczyc: ";
    do
    {
        Czysc();
        cin >> replay;

    if (replay=="koniec")
        {
            koniec=1;
        }
    if (replay=="replay")
        {
            koniec=2;
        }
    else
        {
            cout <<"Blad. Sprobuj jeszcze raz: ";
            Czysc();
            cin >> replay;
        }
    }
    while(koniec!=1,2);

    switch (koniec)
    {
    case 1:
        return 0;
        break;
    case 2:
        do
        {
            main();
            break;
        }
        while (cin.fail());

    }

}
0
if (replay=="koniec")
        {
            koniec=1;
        }
    if (replay=="replay")
        {
            koniec=2;
        }
    else
        {
            cout <<"Blad. Sprobuj jeszcze raz: ";
            Czysc();
            cin >> replay;
        }

przy drugim ifie chyba miało stać else

while(koniec!=1,2);

chyba bardziej ci chodziło o:

while(koniec != 1 && koniec != 2);
 main();
            break;

Nie można wywoływać funkcji main w programie. Zrób to za pomocą pętli.

Podziel program na funkcje, aby można było to łatwiej ogarnąć. Np. stwórz funkcję odpowiedzialną za wczytywanie pewnej danej do skutku.

1

Dlaczego nazwałeś zmienną wczytującą ciąg od użytkownika replay?
Toż to nic nie mówi. Nazwij ją input lub option lub cokolwiek innego...

0

Gdy wpiszę błędną wartość, a później wpiszę "koniec" to nic się nie dzieje. Zostaje puste pole. Gdy wpiszę błędną wartość, a później "replay" to pętla się nie kończy. Zrobiłem sobie to dla testu i powinno zwracać odpowiednią wartość icontinue, a tymczasem nic. Ja już nie wiem.

int Continue()
{
    string inputAtt;
    int icontinue;

    do
    {
        Clear();
        cin>>inputAtt;
        if (inputAtt!="koniec" && "replay")
            cout<<"Blad. Sprobuj ponownie: ";
    }
    while(inputAtt=="koniec" || "replay");
    if (inputAtt=="koniec")
    {
        icontinue=1;
    }
    if (inputAtt=="replay")
    {
        icontinue=2;
    }
    cout<<icontinue;
}
 
1

Już drugi raz to piszę: nie ma takich skrótowych wyrażeń jak:

inputAtt!="koniec" && "replay"

czy

inputAtt=="koniec" || "replay"

Każdy warunek musisz potraktować oddzielnie a dopiero potem połączyć je operatorem logicznym np:

inputAtt!="koniec" && inputAtt!="replay"

tzn. są to poprawne zapisy, ale robią coś, czego nie chciałeś zrobić.

0

A napisz ten kod tak, abyś nie musiał w trzech miejscach pisać koniec oraz replay.

0

Na razie mam to tak i nawet po wpisaniu za pierwszym razem "koniec" lub "replay" nie zwraca wartości icontinue. Czyli jest gdzieś, coś skopane, ale nie wiem gdzie i nie wiem co.

int Continue()
{
    string inputAtt;
    int icontinue;

    do
    {
        Clear();
        cin>>inputAtt;
        if (inputAtt!="koniec" && inputAtt!="replay")
            cout<<"Blad. Sprobuj ponownie: ";
    }
    while(inputAtt=="koniec" || inputAtt=="replay");

    if (inputAtt=="koniec")
    {
        icontinue=1;
    }
    if (inputAtt=="replay")
    {
        icontinue=2;
    }
    cout<<icontinue;
} 
1

Niepotrzebnie sobie życie utrudniasz.

int getUserOption() {
	string input;
	std::cin >> input;
	
	switch (input) {
		case "koniec":
			return 1;
			
		case "replay":
			return 2;
			
		default:
			std::cout << "Blad. Sprobuj ponownie. ";
			return getUserOption();
	}
}

Plus nazywaj funkcje sensownie. Co Ci niby mówi nazwa Continue?

Edit: @Satirev słusznie mi przypomniał, że w C++ nie ma string-switch. W takim wypadku masz obejście za pomocą http://stackoverflow.com/questions/16388510/evaluate-a-string-with-a-switch-in-c lub

int getUserOption() {
	string input;
	std::cin >> input;
	
	if (input == "koniec") {
		return 1;
	}
	
	if (input == "replay") {
		return 2;
	}
	
	std::cout << "Blad. Sprobuj ponownie. ";
	return getUserOption();
}
1

Skoro i tak działasz na liczbach to powinieneś wczytywać tylko liczby i ignorować wszystko co nie jest liczbą.
Zabezpieczenie przed wpisywaniem liter

0

Zrobiłem z pomocą kolegi. Tak wygląda kod

#include <iostream>
#include <string>

using namespace std;
int Compare();
int Continue();

int Clear()
{
    cin.clear();
    cin.sync();
}

int Compare()
{
    float a, b;


    cout << "Podaj liczbe a: ";
    do
    {
        Clear();
        cin >> a;
        if ( cin.fail())
            cout << "Blad. Sprobuj ponownie: ";
    }
    while (cin.fail());

    cout << "Podaj liczbe b: ";
    do
    {
        Clear();
        cin >> b;
        if (cin.fail())
            cout << "Blad. Sprobuj ponownie: ";
    }
    while (cin.fail());

    if ( a == b)
    cout << "Czy liczba a jest rowna liczbie b? " << "Tak" << endl;
    else cout << "Czy liczba a jest rowna liczbie b? " << "Nie" << endl;

    if ( a > b)
    cout << "Czy liczba a jest wieksza od liczby b? " << "Tak" << endl;
    else cout << "Czy liczba a wieksza od liczby b? " << "Nie" << endl;

    if ( a < b)
    cout << "Czy liczba a jest mniejsza od liczby b? " << "Tak" << endl;
    else cout << "Czy liczba a jest mniejsza od liczby b? " << "Nie" << endl;

    if ( a!= b)
    cout << "Czy liczba a jest rozna od b? " << "Tak"<< endl;
    else cout << "Czy liczba a jest rozna od b?  " << "Nie" << endl;
    cout<<"Jesli chcesz zakonczyc napisz \"koniec\" lub \"replay\" jesli chcesz powtorzyc. ";
    Continue();
}

int Continue()
{
    string inputAtt;
    int icontinue;

    Clear();
    cin>>inputAtt;

    if (inputAtt=="koniec")
    {

    }
    else if (inputAtt=="replay")
    {
	Compare();
    }
    else
    {
    	cout<<"Blad. Sprobuj jeszcze raz: ";
    	Continue();
    }
}


int main()
{

    Compare();
}
 
1

Słabo mi, wody...
1.

    cout << "Podaj liczbe a: ";
    do
    {
        Clear();
        cin >> a;
        if ( cin.fail())
            cout << "Blad. Sprobuj ponownie: ";
    }
    while (cin.fail());
 
    cout << "Podaj liczbe b: ";
    do
    {
        Clear();
        cin >> b;
        if (cin.fail())
            cout << "Blad. Sprobuj ponownie: ";
    }
    while (cin.fail());

Czy te dwa kawałki kodu nie wyglądają podobnie? Nie, wyglądają identycznie. Za każdego copy-paste powinieneś dostawać pejczem po plecach. Czemu nie zrobiłeś z tego osobnej funkcji?
2. Tak sie nie pętli programu. Rekurencja to jest tragiczny pomysł bo C++ to nie jest język funkcyjny. Jak ktoś zapętli sie na tym rekurencyjnym wywołaniu funkcji kilka razy to program sie wysypie bo skończy się stos.

0

Jak ktoś zapętli sie na tym rekurencyjnym wywołaniu funkcji kilka razy to program sie wysypie bo skończy się stos.

Kilkaset*, jak najbardziej, lecz to raczej mało prawdopodobny przypadek.

0

@Shalom
Poprawione. Zrobiłem z tego osobną funkcję.

@topic
Ale właśnie o takie działanie mi chodziło. Program ma się powtarzać, gdy użytkownik wpisze "replay", i ma mu wywalać błąd i wykonywać pętlę z funkcją Continue(), jeśli wpisze cokolwiek innego od "replay" bądź "koniec".
Jako, że jestem newbie to nie kwestionuję waszego zdania. Moglibyście mi wytłumaczyć dlaczego tak nie powinno być i dać jakieś wskazówki jak to poprawić? Z góry dzięki

0

Ok, problem polega na tym co się dzieje jak wywołujesz funkcje w programie. Na poziomie asemblera wywołanie funkcji powoduje:

  • odłożenie na stos adresu powrotu z funkcji (żeby program wiedział w które miejsce kodu skoczyć jak funkcja sie skończy)
  • skok do funkcji
    A zakończenie ciała funkcji / return powoduje:
  • zdjęcie ze stosu adresu powrotu
  • skok w miejsce z którego wywołaliśmy funkcje
    Dość proste i logiczne. Problem pojawia się kiedy zaczynasz wołać funkcje rekurencyjnie, tzn wywołujesz funkcje będąc jeszcze wewnątrz poprzedniego wywołania! To znaczy że wcale nie dochodzisz do momentu zdjecia ze stosu adresu powrotu i skoku powrotnego. Zamiast tego zaraz przed tym powoduje odłożenie nowego adresu powrotu i skok na początek funkcji. To oznacza że za drugim twoim "zapętleniem" na stosie masz już 2 adresy powrotu (jeden na koniec twojej funkcji a drugi do main() tam gdzie wywołałeś funkcje pierwszy raz). Za każdym kolejnym na stosie pojawi sie kolejny adres powrotu wskazujacy na koniec funkcji. Tyle że stos nie jest nieograniczony. Wręcz przeciwnie, zwykle jest dość mały. Więc może się okazać że n-te zapętlenie wysypie program bo skończy się pamięć na stosie.

Zamiast tego należy używać zwykłych pętli. Taka pętla wcale nie wymaga odkładania niczego na stos.

0

Nie wiem, czy dobrze zrozumiałem. Chodzi o coś takiego?

#include <iostream>
#include <string>

using namespace std;
int Clear();
int Compare();
int Continue();
int Variables();
float a,b;
string inputAtt;
int icontinue;


int Clear()
{
    cin.clear();
    cin.sync();
}

int Compare()
{

    Variables();
    if ( a == b)
    cout << "Czy liczba a jest rowna liczbie b? " << "Tak" << endl;
    else cout << "Czy liczba a jest rowna liczbie b? " << "Nie" << endl;

    if ( a > b)
    cout << "Czy liczba a jest wieksza od liczby b? " << "Tak" << endl;
    else cout << "Czy liczba a wieksza od liczby b? " << "Nie" << endl;

    if ( a < b)
    cout << "Czy liczba a jest mniejsza od liczby b? " << "Tak" << endl;
    else cout << "Czy liczba a jest mniejsza od liczby b? " << "Nie" << endl;

    if ( a!= b)
    cout << "Czy liczba a jest rozna od b? " << "Tak"<< endl;
    else cout << "Czy liczba a jest rozna od b?  " << "Nie" << endl;
    cout<<"Jesli chcesz zakonczyc napisz \"koniec\" lub \"replay\" jesli chcesz powtorzyc. ";
}

int Continue()
{
    Clear();
    cin>>inputAtt;
    if (inputAtt=="koniec")
    {
        return 0;
    }
    else if (inputAtt=="replay")
    {
        Compare();
        Continue();
    }
}

int Variables()
{
    cout << "Podaj liczbe a: ";
    do
    {
        Clear();
        cin >> a;
        if ( cin.fail())
            cout << "Blad. Sprobuj ponownie: ";
    }
    while (cin.fail());

    cout << "Podaj liczbe b: ";
    do
    {
        Clear();
        cin >> b;
        if (cin.fail())
            cout << "Blad. Sprobuj ponownie: ";
    }
    while (cin.fail());
}


int main()
{
    Compare();
    Continue();
    if (inputAtt != "koniec" && inputAtt!="replay")
        do
    {
        cout<<"Blad. Sprobuj ponownie. Wpisz \"replay\" lub \"koniec\": ";
        Continue();
    }
    while(inputAtt != "koniec" && inputAtt!="replay");
}
 

1 użytkowników online, w tym zalogowanych: 0, gości: 1