Powrót do początku programu - do while, return main()?

0

Uszanowanie,
prowizoryczny program do wpłacania/wypłacania/sprawdzania stanu $. Mam pytanie odnośnie powracania do początku programu. Wyczytałem, że można to robić za pomocą pętli do-while, kombinuje cały czas, nie do końca mi wychodzi ale jeszcze próbuję. Gdzieś wyskoczyła opcja "goto", ale zaraz pod nią 1501239 komentarzy, żeby o tym zapomnieć to zapomniałem. W przypadku case 4 program ma za zadanie wylogować użytkownika i powrócić do początku. Czy można to zrobić za pomocą "return main()", czy jest to praktykowane? W tym przypadku jest to najprostsze rozwiązanie jakie udało mi się znaleźć.

#include <iostream>
#include <string>
#include <windows.h>
#include <stdlib.h>
#include <conio.h>

using namespace std;
string PIN;
char wybor;
float wplata, stan=5000, wyplata;
int main()

{
    cout << "Podaj PIN: ";
    cin >> PIN;
    system ("cls");
    cout << "LOADING..." <<endl;
    Sleep (1000);

    while(PIN != "0000")
    {
        cout<<"\a";
        cout << "Bledny PIN"<<endl;
        Sleep (1000);
        system("cls");
        cout << "Podaj PIN: ";
        cin >> PIN;
        cout << "LOADING..." <<endl;
        Sleep (1000);
        system("cls");
    }

    system ("cls");

    if (PIN=="0000")
    {

        for(;;)
        {
        cout << "=============="<<endl;
        cout << "Dostepne opcje"<<endl;
        cout << "=============="<<endl;
        cout << "1. Wplata gotowki"<<endl;
        cout << "2. Wyplata gotowki"<<endl;
        cout << "3. Stan konta" <<endl;
        cout << "4. Wyloguj" <<endl;
        cout << "5. Zamknij program"<<endl;
        cout <<"_____________________"<<endl;
        wybor = getch();
        cout<<endl;

        switch (wybor)
            {
            case '1':
               cout <<"Wplata gotowki"<<endl;
               cout <<"______________"<<endl;
               cout <<"Podaj wartosc: ";
               cin >> wplata;
               system ("cls");
               cout <<"Wplacono: "<< wplata <<endl;
               cout <<"Obecny stan konta: "<<stan+wplata<<endl<<endl<<endl;
               cout <<"Press any key to continue..."<<endl;
              break;

            case '2':
                cout <<"Wyplata gotowki"<<endl;
                cout <<"______________"<<endl;
                cout <<"Podaj wartosc: ";
                cin >> wyplata;

                if (wyplata>stan)
                    cout<< "Brak wystarczajacych srodkow!";
                    else
                {
                cout <<"Wyplacono: "<< wyplata <<endl;
                cout <<"Obecny stan konta: "<<stan-wyplata<<endl<<endl<<endl;
                cout <<"Press any key to continue..."<<endl;
                }
                break;

            case '3':
                cout << "Dostepne srodki: "<< stan <<endl<<endl<<endl;
                cout <<"Press any key to continue..."<<endl;
                break;

            case '4':
                system ("cls");
                return main();
                break;

            case '5':
                exit (0);
                break;

                default:
                cout<< "\a";
                cout<<"Blad! Dostepne opcje: 1-5"<<endl;
                cout<<"Wcisnij dowolny klawisz i wybierz ponownie!"<<endl;
            }
            getch();
            system("cls");
        }
        }

    return 0;
}
3

Czy można to zrobić za pomocą "return main()", czy jest to praktykowane?

Jest wręcz niewskazane. Nie wiem czy nie jest to UB.

  1. Wyrzuć całą logikę z instrukcji switch - case do osobnych funkcji. Łatwiej dostrzeżesz rozwiązanie, gdy kod będzie przejrzysty.
  2. Zmienne globalne to zło, pozbądź się ich, bo tutaj są niepotrzebne.
  3. Piszesz w C++, korzystaj z plików nagłówkowych przepisanych dla C++ <cstdlib>.
  4. W przypadku case 4 program ma za zadanie wylogować użytkownika i powrócić do początku.

Zamknij cały kod z funkcji głównej w pętli i instrukcję switch - case w drugiej poza którą program
będzie wychodził w przypadku wylogowania usera. Jakaś dodatkowa flaga, którą ustawisz w case 4:, a która spowoduje
przerwanie pętli.

0
YooSy napisał(a):

Czy można to zrobić za pomocą "return main()", czy jest to praktykowane?

Jest wręcz niewskazane. Nie wiem czy nie jest to UB.

Jak już napisano, nie jest to UB. Ale może powodować standardowe problemy z rekurencją (w końcu skończy siępamięć), jeśli nie masz włączonego optymalizowania rekurencji ogonowej (gcc -O3 chyba optymalizuje).

Z drugiej strony jest to aplikacja interaktywna, więc szanse, że się wywali z powodu zbyt głębokiej rekurencji są bardzo małe... Chyba, że ma działać przez lata bez resetu.

5

Jakbyś nie pisał wszystkiego w main to zrobiłbyś to już dawno sam.
Dziel kod na małe funkcje.
Sam problem jest prosty jak konstrukcja cepa: do { zawartoscMain; } while (jakiś warunek);

0

Rozwiązanie return main () znalazłem na jakimś forum, chciałem się dowiedzieć czy jest to ogólnie stosowane czy lepiej unikać. Dzięki za cenne wskazówki.

3

Co do main(), standard wypowiada się następująco:

The function main shall not be used within a program. The linkage ([basic.link]) of main is implementation-defined. A program that defines main as deleted or that declares main to be inline, static, or constexpr is ill-formed. The main function shall not be declared with a linkage-specification ([dcl.link]). A program that declares a variable main at global scope or that declares the name main with C language linkage (in any namespace) is ill-formed. The name main is not otherwise reserved. [ Example: Member functions, classes, and enumerations can be called main, as can entities in other namespaces. — end example ]

http://eel.is/c++draft/basic.start.main#3

Cały 6 pkt warto przeczytać by wyrobić sobie pogląd jaki jest status tej funkcji.

Nie nie jest to "ciekawy zabieg" i nie jest to "jakieś rozwiązanie".

0
Standard C++ §6.8.3.1:

The function main shall not be used within a program.

Czyli raczej kiepski pomysł z wywoływaniem main wewnątrz programu.

0

Próbuję zamknąć to w pętli do - while. Krótki przykład:

    char wybor=getch();
    string PIN="0000";
    getch();

    do
        {
        cout <<"Podaj PIN: ";
        cin >> PIN;
        system ("cls");
        cout << "LOADING..." <<endl;
        Sleep (1000);
        system("cls");
        }
    while (wybor == '4');

Sytuacja jest taka, że po odpaleniu Podaj PIN powinno pojawiać się tylko po wciśnięciu '4', a wyskakuje po wciśnięciu dowolnego klawisza.

1
int wybor=getch(); 
//...
    while (wybor == 52);

Zamiast sleep() użyj nowoczesnego rozwiązania std::this_thread::sleep_for() (<thread>). https://en.cppreference.com/w/cpp/thread/sleep_for?
system("cls") też nie jest najlepszym wyborem. Wystarczy wysunąć konsolę o odpowiednią ilość linii.

void clearConsoleScreen(){
   for(int i = 0; i < consoleHeight; ++i){
      std::cout << '\n';
   }
}
0
 int wybor=getch();

   do
   {
   cout << "OK" <<endl;
   }
    while (wybor == 4);

Wrzuciłem wybór jako int, ale problem ten sam. Po wciśnięciu dowolnego klawisza wyskakuje "OK". Nie mogę przypisać go tylko dla 4.

Rozumiem, że sleep() jest przestarzałym, niestosowanym rozwiązaniem? A czemu system("cls") nie jest najlepszym wyborem?

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