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

2018-12-17 22:47
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;
}
edytowany 2x, ostatnio: furious programming, 2018-12-18 15:58

Pozostało 580 znaków

2018-12-18 00:19
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.


Nie pisz na priv. Zadaj dobre pytanie na forum.
Nie jest to UB, tak jak każdą inną funkcję, main można wywołać. Swoją drogą ciekawy zabieg. - enedil 2018-12-18 10:06
Nie byłem pewny, a nie wpadł mi żaden sensowny doc w sieci. - YooSy 2018-12-18 11:25

Pozostało 580 znaków

2018-12-18 14:26
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.

Pokaż pozostałe 4 komentarze
http://eel.is/c++draft/expr.call#13 stąd... analogiczny zapis jest do wcześniejszych standardów bo to "żywy draft". - Mokrowski 2018-12-19 16:24
@Mokrowski: A, mówiłeś o main -- to OK -- zrozumiałem, ze masz na myśli rekurencję w ogóle... :) Sorki. - koszalek-opalek 2018-12-19 16:56
Przeczytaj dokładnie wpis. Rekurencja dla wywołań funkcji jest dozwolona/dopuszczalna (ang. permitted) ale nie jest wymagana a dla main zabroniona. - Mokrowski 2018-12-19 17:16
Przeczytałem. Rozumiem to tak, że standard wymaga, by kompilator dopuszczał rekurencję. A dla main zabrania. - koszalek-opalek 2018-12-19 17:17
Nie. Żle rozumiesz. I sprawdź to w dowolnym serwisie tłumaczeń. - Mokrowski 2018-12-19 17:21

Pozostało 580 znaków

2018-12-18 15:49
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);


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.

Pozostało 580 znaków

2018-12-19 12:59
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.

Pozostało 580 znaków

2018-12-19 13:20
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".


Każdy problem w informatyce można rozwiązać, dodając kolejny poziom pośredniości,z wyjątkiem problemu zbyt dużej liczby warstw pośredniości — David J. Wheeler
edytowany 1x, ostatnio: Mokrowski, 2018-12-19 13:22

Pozostało 580 znaków

2018-12-19 13:23
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.

Opóźniony jestem :P - tajny_agent 2018-12-19 13:24

Pozostało 580 znaków

2018-12-19 21:41
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.

Pozostało 580 znaków

2018-12-20 01:07
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';
   }
}

Nie pisz na priv. Zadaj dobre pytanie na forum.
edytowany 1x, ostatnio: YooSy, 2018-12-20 01:08

Pozostało 580 znaków

2018-12-20 12:58
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?

Pozostało 580 znaków

2018-12-20 13:37
0

Ogólnie system() jest funkcją nieprzenośną (windowsową).

int myGetch() {
    int ch = getch();
    if (!ch) {
        return getch();
    }
    return ch;
}

int main() {
    std::cout << myGetch() << std::endl;
}

getch() zwraca dwa kody, aby łatwiej odróżniać znaki podstawowe od specjalnych.

std::cout << getch() << " : " << getch() << '\n';

Edit:
Nie zwróciłem na to uwagi:

do
{
   cout << "OK" <<endl; // to wykona się zawsze przed pierwszym sprawdzeniem warunku pętli.
}
    while (wybor == 4);

Tak jak w komentarzu. Wykonywanie programu w C++ jest od góry do dołu. Użyj do tego celu pętli while(){} lub for(;;).


Nie pisz na priv. Zadaj dobre pytanie na forum.
edytowany 2x, ostatnio: YooSy, 2018-12-20 13:55
https://en.cppreference.com/w/cpp/utility/program/system problem leży raczej w tym, że zwykle argumenty dla system są nieprzenośne. - MarekR22 2018-12-20 14:10

Pozostało 580 znaków

Liczba odpowiedzi na stronę

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