rambosek Temat założony przez niniejszego użytkownika |
Rozdział 15 Zad. domowe - Kalkulator | sprawdzenie kodu » 2017-01-29 14:58:13 Witam wszystkich serdecznie. Niedawno zacząłem się uczyć programowania, i chciałbym aby ktoś z doświadczonych forumowiczów ocenił mój kod i wyjaśnij mi dokładniej niektóre funkcje w moim kodzie. Powiedzmy że jest to pierwsza "poważniejsza" praca domowa, nad którą trzeba było już dłuższą chwilę spędzić. Przede wszystkim nie jestem pewny, czy dobrze zrozumiałem treść zadania domowego, brzmi tak: - Napisz prosty kalkulator, który będzie potrafił dodawać, odejmować, mnożyć i dzielić. Program ten ma działać następująco: 1. Wypisuje obecny wynik 2. Wprowadź liczbę 3. Wybierz działanie (jeżeli liczba różna od 0) 4. Wykonaj obliczenia (jeżeli liczba różna od 0) 5. Wróć do kroku 1. 6. Jeżeli wprowadzoną liczbą jest 0, zakończ program. - Zabezpiecz wcześniej napisany kalkulator przed podawaniem niepoprawnych liczb i operacji. Wykorzystaj wiedzę zdobytą z pierwszego zadania pracy domowej niniejszego rozdziału. Zabezpiecz również w analogiczny sposób przed możliwością wyboru nieprawidłowego działania. Przede wszystkim zastanawiają mnie punkty 2, 3 i 4. W 2 punkcie "Wprowadź liczbę" sugeruje że mam wprowadzić 1 liczbę, napisałem kalkulator tak aby od razu wprowadzać 2 liczby. Ponadto nie rozumiem w kolejnych punktach tych nawiasów (jeżeli liczba różna od 0). Przecież można wykonywać wszystkie działania z 0, poza dzieleniem przez 0. W każdym razie czy ktoś mógłby ocenić mój kod, ewentualnie nanieść jakieś poprawki? Chciałbym jeszcze zapytać o zabezpieczenie przed podaniem niepoprawnych liczb i operacji. Użyłem do tego funkcji sprawdzającej strumień wejścia cin.good(), a jej wynik zapisałem w zmiennej bool. Bez zmiennej cała pętla przy wprowadzaniu liter mi się zapętlała w kółko nie mam pojęcia dlaczego, tak samo jak nie ma funkcji cin.clear() oraz cin.sync(). Ponadto nie rozumiem czemu program zwraca mi 0 i kończy działanie, jak przy wyborze operacji (dodawanie, odejmowanie itp.) wpisze literę zamiast cyfry, komunikat wyświetla poprawnie że nie ma takiej opcji w menu, ale kończy działanie programu. Czy ktoś mógłby dokładnie wytłumaczyć mi działanie funkcji cin.clear() oraz cin.sync()? Jak się domyślam, program działa odczytując kolejne wiersze więc nie rozumiem, czemu to działa w przypadku, kiedy obie te funkcje są przed wprowadzaniem danych. Wklejam kod i pozdrawiam :) #include <iostream>
using namespace std;
int main() { float a, b; int dzialanie; float wynik = 0; bool spr; do { cin.clear(); cin.sync(); cout << "Wynik = " << wynik << endl; cout << endl << "Wprowadz 2 liczby rozdzielone spacjami: "; cin >> a >> b; spr = cin.good(); if( spr == 1 ) { cout << endl << "[1] Dodawanie \n[2] Odejmowanie \n[3] Mnozenie \n[4] Dzielenie \n[5] Zakoncz" << endl << endl; cout << "Wybierz dzialanie: "; cin.clear(); cin.sync(); cin >> dzialanie; switch( dzialanie ) { case 1: wynik = a + b; cout << a << " + " << b << endl; break; case 2: wynik = a - b; cout << a << " - " << b << endl; break; case 3: wynik = a * b; cout << a << " * " << b << endl; break; case 4: if( b != 0 ) { wynik = a / b; cout << a << " / " << b << endl; } else cout << endl << "Nie dzielimy przez 0 LAMUSIE!" << endl; break; case 5: cout << endl << "Dzieki za skorzystanie z kalkulatora!" << endl; return 0; default: cout << endl << "Nie ma takiej opcji w menu!" << endl; break; } } else cout << "Wprowadz poprawne liczby" << endl; } while( dzialanie != 0 ); return 0; }
|
|
latajacaryba |
» 2017-01-29 15:30:09 Przede wszystkim zastanawiają mnie punkty 2, 3 i 4. W 2 punkcie "Wprowadź liczbę" sugeruje że mam wprowadzić 1 liczbę, napisałem kalkulator tak aby od razu wprowadzać 2 liczby. Ponadto nie rozumiem w kolejnych punktach tych nawiasów (jeżeli liczba różna od 0). Przecież można wykonywać wszystkie działania z 0, poza dzieleniem przez 0. |
Myślę, że chodzi tu o switch 'a, jeśli użytkownik poda liczbę 0, to program ma się zakończyć. Jeśli jest różna od zera, to oznacza to: switch( liczba ) { case 1: break case 2: break; case 0: cout << "dziekuje za skorzystanie z programu!"; exit( 0 ); }
Oczywiście w //kod dodawania pobierasz dane od uzytkownika (co ma byc dodane). Przynajmniej tak ja to rozumiem. Co do Twojego kodu: - wolę, kiedy kalkulator podaje mi wynik PO wykonaniu obliczeń :D cout << "Wynik = " << wynik << endl;
Jak to naprawić? Ano, zaimplementuj ten fragment kodu dopiero po obliczeniach (po zakończeniu klamer switch'a) default: cout << endl << "Nie ma takiej opcji w menu!" << endl; break; } cout << "Wynik = " << wynik << endl; } else cout << "Wprowadz poprawne liczby" << endl;
- program ma opcję wyjścia za pomocą klawisza 5, dlatego usuń to: do { } while( dzialanie != 0 ); i wstaw w miejsce tej pętli while( 1 ) { } while(1) oznacza: wykonuj w nieskończoność. Poza tym zmień opcję wyjścia z programu z 5 na 0 (jak w poleceniu). |
|
rambosek Temat założony przez niniejszego użytkownika |
» 2017-01-29 20:42:08 Dziękuje bardzo za sugestie :) jednakże wciąż nurtuje mnie to, jak działają funkcje cin.good() oraz cin.sync(); czy na pradę jest sens stosować te funkcje przed każdym wczytywaniem danych? Tzn. widze na przykładzie że jest ale dalej nie wiem jak to dokładnie działa ;P wklejam poprawiony kod, czy teraz jest okej? dodałem IFa sprawdzającego poprawność wprowadzonych danych przy wyborze działania, tylko mam pytanie: Jak zrobić gdy w przypadku wprowadzenia litery przy wyborze działania, wymuszało ponowne wybranie opcji działania, a nie wraca aż do wprowadzenia liczb do obliczenia ponownie. Pozdrawiam #include <iostream>
using namespace std;
int main() { float a, b; int dzialanie; float wynik = 0; do { cout << "Wprowadz 2 liczby rozdzielone spacjami: "; cin.clear(); cin.sync(); cin >> a >> b; if( cin.good() ) { cout << endl << "[1] Dodawanie \n[2] Odejmowanie \n[3] Mnozenie \n[4] Dzielenie \n[0] Zakoncz" << endl << endl; cout << "Wybierz dzialanie: "; cin.clear(); cin.sync(); cin >> dzialanie; if( cin.good() ) { switch( dzialanie ) { case 1: wynik = a + b; cout << a << " + " << b << endl; break; case 2: wynik = a - b; cout << a << " - " << b << endl; break; case 3: wynik = a * b; cout << a << " * " << b << endl; break; case 4: if( b != 0 ) { wynik = a / b; cout << a << " / " << b << endl; } else cout << endl << "Nie dzielimy przez 0 LAMUSIE!" << endl; break; case 0: cout << endl << "Dzieki za skorzystanie z kalkulatora!" << endl; return 0; default: cout << endl << "Nie ma takiej opcji w menu!" << endl; break; } cout << "Wynik = " << wynik << endl; } else cout << "Nie ma takiej opcji w menu!" << endl; } else cout << "Wprowadz poprawne liczby" << endl; } while( 1 ); return 0; }
|
|
karambaHZP |
» 2017-01-29 21:09:02 Właśnie to zadanie ma ci uświadomić, po co są te metody. Więcej można doczytać tutaj. Z metodą std::cin.sync() byłbym ostrożny w stosowaniu do czyszczenia bufora strumienia, bo jest to jej efekt uboczny, a nie główna właściwość. |
|
latajacaryba |
» 2017-01-29 22:18:32 jednakże wciąż nurtuje mnie to, jak działają funkcje cin.good() oraz cin.sync(); czy na pradę jest sens stosować te funkcje przed każdym wczytywaniem danych? |
Akurat tego kursu nie czytałem (uczę się z książek), a obsługa strumieni jest trochę później. Jednak coś tam wiem ;) Wiesz zapewne, co się stanie, kiedy poprosisz użytkownika o coś takiego: cout << "Podaj swoje imie" << endl; cin >> imie; cout << "Podaj imie matki\n"; cin >> imie2; cout << "twoje imie to " << imie << " a imie Twojej Mamy to " << imie2;
W takim przypadku, gdy użytkownik przez np. nieuwagę poda przy pierwszym cin>>imie np. Jarosław Kaczyński, to: w buforze będą 2 c-stringi (2 ciągi znaków) to pierwszy (Jarosław) zostanie przypisany do zmiennej imie. Tylko pierwsze. Natomiast drugi nadal będzie siedział w buforze. teraz wyświetli się prośba o podanie imienia Matki, ale nie będziemy mieli czasu na wpisanie, gdyż zostanie wykorzystany string z buforu (Kaczyński). Efektem będzie: "twoje imie to "Jarosław" a imie Twojej Mamy to Kaczyński" Właśnie po to czyści się bufor funkcją cin.sync() Co do kodu: - za dużo if'ów. Przykład: if( cin.good() ) {...} else cout << "Nie ma takiej opcji w menu!" << endl;
if( cin.good() == false ) cout << "Nie ma takiej opcji w menu!";
Nie ma sensu z takiego powodu brać całego kodu w klamry. Im więcej klamer i zagnieżdżeń tym trudniej potem się połapać Jednak to chyba Cię nie zadowala, bo pisałeś Jak zrobić gdy w przypadku wprowadzenia litery przy wyborze działania, wymuszało ponowne wybranie opcji działania, a nie wraca aż do wprowadzenia liczb do obliczenia ponownie. |
Zrób to więc tak: cout << endl << "[1] Dodawanie \n[2] Odejmowanie \n[3] Mnozenie \n[4] Dzielenie \n[0] Zakoncz" << endl << endl; cout << "Wybierz dzialanie: ";
do { cin.clear(); cin.sync(); cin >> dzialanie; if( cin.good() == false ) cout << "zle podana liczba! sprobuj ponownie\n"; } while( cin.good() == false );
switch( dzialanie )
To samo zrób z if'em, zamien go na pętle do{}while. Poniżej wkleje jak powinien wyglądać kod, ale spróbuj najpierw sam go naprawić (mam na myśli: zmień tego if'a na tą pętle do...while.) KOD int main() { float a, b; int dzialanie; float wynik = 0; do { cout << "Wprowadz 2 liczby rozdzielone spacjami: "; do { cin.clear(); cin.sync(); cin >> a >> b; if( cin.good() == false ) cout << "zle podana liczba! sprobuj ponownie\n"; } while( cin.good() == false ); cout << endl << "[1] Dodawanie \n[2] Odejmowanie \n[3] Mnozenie \n[4] Dzielenie \n[0] Zakoncz" << endl << endl; cout << "Wybierz dzialanie: "; do { cin.sync(); cin >> dzialanie; if( cin.good() == false ) cout << "zle podana liczba! sprobuj ponownie\n"; } while( cin.good() == false ); switch( dzialanie ) { case 1: wynik = a + b; cout << a << " + " << b << endl; break; case 2: wynik = a - b; cout << a << " - " << b << endl; break; case 3: wynik = a * b; cout << a << " * " << b << endl; break; case 4: if( b != 0 ) { wynik = a / b; cout << a << " / " << b << endl; } else cout << endl << "Nie dzielimy przez 0 LAMUSIE!" << endl; break; case 0: cout << endl << "Dzieki za skorzystanie z kalkulatora!" << endl; return 0; default: cout << endl << "Nie ma takiej opcji w menu!" << endl; break; } cout << "Wynik = " << wynik << endl; } while( 1 ); return 0; }
|
|
rambosek Temat założony przez niniejszego użytkownika |
» 2017-01-30 00:03:35 Baaardzo dziekuje za pomoc :) @latajacaryba naprowadziles mnie na lepsze rozwiazanie, rzeczywiscie lepiej jest zrobic wiecej petli, program jest wydajniejszy dzieki temu. Moze IFów w twoim przykładzie nie jest mniej, tyle że nie ma klamer i kod jest czytelniejszy. I jeszcze taka uwaga, jak testowałem twój kod, przy wyborze działania jak wpisałem literkę, to zapętlał się komunikat o tym żeby spróbować ponownie. Tam w pętli masz samo cin.sync() bez clear. Jak dodałem clear to już ten problem nie występuje i kalkulator działa bardzo dobrze. Dziękuje jeszcze raz ;) |
|
karambaHZP |
» 2017-01-30 00:51:37 Nie ma sensu z takiego powodu brać całego kodu w klamry. |
Też tak kiedyś myślałem. Pisz klamry. Kiedyś możesz potrzebować dopisać drugą instrukcję do wykonania w ifie, a zapomnisz dostawić klamry i kłopot gotowy. Im więcej klamer i zagnieżdżeń tym trudniej potem się połapać |
Im więcej klamer - nie. Im więcej zagnieżdżeń - tak. Już przy drugim zagnieżdżeniu powinno się rozważyć wydzielenie kodu z najbardziej zagnieżdżonego bloku do osobnej funkcji. Tytaj możesz zerknąć jak używa się sprawdzania poprawności wprowadzanych danych oraz czyści strumień. https://4programmers.net/C/FAQ/Zabezpieczenie_przed_wpisywaniem_liter Nie powinno się porównywać liczb zmiennoprzecinkowych operatorami == oraz != . |
|
latajacaryba |
» 2017-01-30 10:47:24 Rambosek faktycznie, sprawdzalem co sie stanie jak nie dodam clear i zapomnialem potem dolaczyc tej funkcji do kodu:p sorry |
|
« 1 » 2 |