Skocz do zawartości
ShDe

[c++] Maly Problem Z Petla I If-em

Rekomendowane odpowiedzi

Zaczelem pisac ostatnio proste programy w C++, mam maly problem i licze na szybka pomoc ;)

Mianowicie:

if(a+b>0){instrukcja1...instrukcja2...instrukcjaN...}else cout<<"wprowadziles nie poprawne dane, wprowadz je ponownie"<<endl;
Chcialbym zeby w przypadku gdy if nie zostanie spelniony, program ponownie poprosil o wprowadzenie danych. Nie pisze struktury calego programu bo mysle ze niema to sensu, wszystko wyjasnilem na przykladzie.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

#include <iostream>#include <conio.h>using namespace std;int a;int b;int foo(){	cin >> a;	cin >> b;	if(a+b<0){		cout << "masakra";	getchar();	return 0;}	else {	cout<<"wprowadziles niepoprawne dane, wprowadz je ponownie"<<endl;	foo();}}int main(){	foo();}
Edytowane przez carck3r

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

a w przypadku gdy walniesz się w ifach. które nie zawsze są tak proste jak a<1 to masz gotowy stack overflow ;]

 

Jak chcesz robić takie rzeczy to robisz np pętlę while() i sprawdzasz w niej warunek. A warunek końca umieszczasz w tym swoim ifie

 

czyli

bool powtarzajPetle = truewhile( powtarzajPetle ){//  instrukcje  if( (a+b>0) )  {	  //insturkcje	 powtarzajPetle = false;  }  else	  cout<<"wprowadziles nie poprawne dane, wprowadz je ponownie"<<endl; // niepoprawne się pisze razem;]}
Edytowane przez PelzaK

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

a w przypadku gdy walniesz się w ifach. które nie zawsze są tak proste jak a<1 to masz gotowy stack overflow ;]

No nie przesadzajmy - zeby miec stack overflow to naprawde setki rekurencji musza byc wywolane. Ostatnio stack overflow to mialem przy implementacji algorytmu pozaru prerii kiedy to funkcja wywolywala 4 krotnie sama siebie :) i overflow byl przy wiekszych figurach.

 

BTW PelzaK w której pamieci jest odkladany stos? w RAMie bankowo nie, w cache tez nie. To gdzie?

Edytowane przez shooter

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

No mówię, jeśli walniesz się w ifach to setki wywołań nastąpią w ułamku sekundy, wierz mi, pisałem kiedyś warcaby z drzewem gry. Komputery są szybkie ;]

 

Pytanie o stos jakieś podchwytliwe? :wink: Każdy proces ma przydzielony kawał pamięci wirtualnej. Część tej pamięci znajduje się w ramie, reszta ląduje w swapie po pewnym czasie. W tej pamięci jest miejsce na stos i na stertę.. W cache'u natomiast są umieszczane fragmenty kodu aktualnie przerabianego, czy stos też tam ląduje? Nie wiem. Zależy pewnie od architektury procesora.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

No Pelzak ale jego programowi to przepelnienie stosu na pewno nie grozi, musialby naprawde zawziecie setki razy wpisywac za kazdym wywolaniem te zmienne a i b z konsoli wiec raczej szybciej by sie kapnal ze cos jest w if'ie nie tak niz by doprowadzil do przepelnienia stosu :P Poza tym przepelnienie stosu nie jest takie zle, szybciej sie w takim wypadku kapniesz ze zwalone jest cos w rekurencji niz w przypadku gdyby twoj program nie wiedziec czemu stal w miejscu i nic nie robil (tkwil by w nieskonczonej petli while).

A co do przedstawionego problemu to ewentualnie ta rekurencja lub do while:

do {	cout << "Wprowadz a i b tak, aby ich suma byla wieksza od zera:\n";	cin >> a;	cin >> b;} while (a+b <= 0);
Edytowane przez krawetko

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

No Pelzak ale jego programowi to przepelnienie stosu na pewno nie grozi, musialby naprawde zawziecie setki (..)

Przy pierwszym czytaniu z wejscia wystarczy podać jakiś napis zamiast liczby: efekt - stos przepełnia się w niecałą minutę :]

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Przy pierwszym czytaniu z wejscia wystarczy podać jakiś napis zamiast liczby: efekt - stos przepełnia się w niecałą minutę :]

Tak ale to juz kwestia obslugi zlosliwych danych ktora dodatkowo mozna zaimplementowac. Wystarczy po kazdym wczytaniu zmiennej czyscic bufor cin'a i Twoj napis nie sprawi zadnego klopotu. gcc version 2.95 19990728 (release) - zaskakuje za pierwszym razem po podaniu napisu.. Edytowane przez krawetko

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

krawetko bardzo ładnie rozwalil ten problemik

do {	cout << "Wprowadz a i b tak, aby ich suma byla wieksza od zera:\n";	cin >> a;	cin >> b;} while (a+b <= 0);
PelzaK - zadnej podchwytliwosci - z ciekawosci pytalem.

Czy stos jest w RAMie? Wątpię - jak rozpoczynałem pożar patrzyłem na zużycie pamięci RAM - ledwo 1MB wchłonęło a tu przepełnienie :)

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

gcc version 2.95 19990728 (release) - zaskakuje za pierwszym razem po podaniu napisu..

Iście przedwojenne gcc, więc niekoniecznie miarodajne. Ogólnie powinno być tak: operatorowi >> nie udaje się wczytać liczby, więc ustawia failbit. Każde kolejne odwołanie do tego strumienia powinno się nie udać - dopóki nie wyczyścimy owego failbit. Jeżeli gcc 2.95 robi inaczej, to widać pora przesiąść się na 3.4 albo 4.0

Czy stos jest w RAMie? Wątpię - jak rozpoczynałem pożar patrzyłem na zużycie pamięci RAM - ledwo 1MB wchłonęło a tu przepełnienie :)

Stos jest w RAMie. Jego góra (element z wierzchu stosu) znajduje się pod adresem ss:esp. Na stos zwykle pamięć przeznaczana jest przy starcie programu, temu też nie widać by program zajmował jakąś dodatkową pamięć. Z tego wynika, iż im więcej zmiennych lokalnych w rekurencyjnej funkcji, tym szybciej się przepełni.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Czy stos jest w RAMie? Wątpię - jak rozpoczynałem pożar patrzyłem na zużycie pamięci RAM - ledwo 1MB wchłonęło a tu przepełnienie :)

Tak jak pisal Grzybiarz Stos jest w RAM'ie, tak jak i Sterta (lecz w roznych miejscach). To ile miejsca na stos zostanie przeznaczone dla kazdego watku zalezy od kompilatora i Systemu. W systemie Windows domyslny rozmiar stosu dla pojedynczego watku to wlasnie 1MB-co zgadza sie z Twoimi obserwacjami. Edytowane przez krawetko

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Nie będzie żadnego przepełnienia stosu, bo ta rekurencja jest ogonowa i nie używa stosu ;)

Zajdzie przepelnienie stosu. Zaden kompilator C/C++ domyslnie nie optymalizuje rekurencji ogonowej. To o czym piszesz oczywiscie mozna osiagnac, lecz po przez kompilacje kodu z odpowiednimi parametrami, pozwalajacymi kompilatorowi na optymalizacje, na co nie zawsze mozna sobie pozwolic.

 

Iście przedwojenne gcc, więc niekoniecznie miarodajne. Ogólnie powinno być tak: operatorowi >> nie udaje się wczytać liczby, więc ustawia failbit. Każde kolejne odwołanie do tego strumienia powinno się nie udać - dopóki nie wyczyścimy owego failbit. Jeżeli gcc 2.95 robi inaczej, to widać pora przesiąść się na 3.4 albo 4.0

Oczywiscie jest tak jak napisales, cin ustawia failbit, ale zauwaz ze wtedy zmienna pozostaje niezainicjalizowana. W konsekwencji zawiera w sobie jakies smieci i to czy spelni if'a i nie dojdzie do przepelnienia stosu zalezy juz od tego jakie smieci w niej beda. Edytowane przez krawetko

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

ino używanie rekurencji gdzie nie jest potrzebna jest średnim pomysłem. Chociażby z powodu takowego, że ciężko się to debuguje ;)

To juz zalezy od tego jak dobrze masz ja opanowaną ;) Edytowane przez krawetko

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Nie, to zawsze jest nadużycie. Rekurencja służy z reguły do rozwiązywania zadań rekurencyjnych, takich jak przeglądanie drzew chociażby. A sprawdzanie poprawności danych za pomocą rekurencji to jest już istotne nadużycie. Co jeśli program się rozwinie, będziesz musiał rozwijać funkcję rekurencyjną i dbać o to, żeby działała prawidłowo - strata czasu i zasobów...

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Jesli tylko potrafisz sformulowac prawidlowy warunek koncowy to stosowanie rekurencji nie jest w zadnym stopniu naduzyciem - choc czesto rozwiazanie iteracyjne jest "bardziej eleganckie" - tak jak np w przytoczonym w tym watku problemie. Zaleta rekurencji jest zwiezlosc zapisu. Rekurencja zwiększa takze czytelność rozwiązania oraz łatwość jego modyfikacji w stosunku do równoważnego rozwiązania iteracyjnego - lecz jesli tak jak piszesz dbanie o jej poprawne dzialanie nastarcza Ci problemow to faktycznie pownienes sobie ja darowac ;)

Edytowane przez krawetko

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

lecz jesli tak jak piszesz dbanie o jej poprawne dzialanie nastarcza Ci problemow to faktycznie pownienes sobie ja darowac icon_wink2.gif

Wiesz, jeśli piszesz programy które mają po tysiąc linii kodu to się nie dziwię, że jest to dla Ciebie oczywiste i przejrzyste... Ale ja pracuje z programem, który ma ponad 2 tysiące plików z kodem... wielokrotne dziedziczenie po 10 klasach, różne inne cuda na kiju, to rekurencja nie jest już taka banalna. A już na pewno nie powiesz mi, że łatwiej w takim środowisku debugować funkcje rekurencyjne niźli zwykłe, że tak powiem, płaskie.

 

ps. W prawdziwych programach warunek końcowy często jest modyfikowany, tak samo jak ciało funkcji, do tego przez różne osoby.. A sam warunek nie jest jeden, tylko może być ich kilka, kilkanaście.. prędzej czy później bug Cię dopadnie. Pomijam już sprawy wydajności bo są może mniej istotne, ale jednak... wywoływanie 50 razy tej samej funkcji jest po prostu bezcelowe jeśli można wykonać 50 razy pętle.

 

Zresztą, wedle Twej teorii to w każdej funkcji zamiast pętli powinieneś wykorzystywać rekurencję... przecież to zwiększa czytelność rozwiązania... ;)

Edytowane przez PelzaK

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Nie mydl oczu tymi plikami i dziedziczeniem, bo to czy pracujesz z tysiącami plikow z dziedziczeniem po 350 klasach nie ma tu zadnego znaczenia. Rekurencje stosujesz w konkretnej funkcji, a funkcje maja byc (w miare mozliwosci) krotkie i zwiezle (no chyba ze Twoje maja po 1000 lini kodu, ale to by tylko o Tobie zle swiadczylo - lecz o takie rzeczy Cie nie podejrzewam). Poza tym gdybys doczytal moj wczesniejszy post nie pisałbyś ze kazda petle chcialbym zastepowac rekurencja, gdyz wyraznie napisalem ze czesto rozwiazania iteracyjne sa duzo "bardziej eleganckie" i jak najbardziej nalezy je stosowac.

Nie staram sie postawić rekurencji nad rozwiązaniami iteracyjnymi ani na odwrót, zawsze nalezy wybrac rozwiazanie optymalne do problemu. Probuje Ci tylko uzmyslowic ze stosowanie rekurencji nie ogranicza sie jedynie do drzew, grafów czy problemu konika szachowego, lecz z powodzeniem mozna ja stosowac na codzien, co jednakze wymaga dobrego jej zrozumienia.

Pozdrawiam

Edytowane przez krawetko

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

no tak, tylko potem spróbuj to sobie debugować (w tym celu właśnie wspomniałem o wielokrotnym dziedziczeniu, bo bo ma swoje odzwierciedlenie w debugowaniu), i teraz masz taką swoją funkcję rekurencyjną, która wywołuje 5 innych funkcji, z których któraś też dziwnym trafem jest rekurencyjna (bo pół roku temu tak właśnie ją zaimplementowałeś Ty lub Twój kolega z teamu). Wywołujesz taką funkcję 20 razy i skaczesz debugerem 20 razy w taką funkcję, jedną drugą, piątą za każdym razem przechodząc przez wywołanie (już pomijam, ze można brejki postawić, bo czasami chcesz sprawdzić coś krok po kroku dokładnie). Takie debugowanie jest o wiele bardziej upierdliwe niż debugowanie zwykłej pętli.

 

Znam wielu programistów, bardzo dobrych programistów, i szczerze, to nie widziałem, żeby któryś z nich na dzień dobry stosował funkcje rekurencyjne gdzie nie ma problemu wymagającego rekurencyjnego podejścia. Może to o czym mówisz to jakaś nowa moda, nie wiem. Jeśli Ci tak dobrze to programuj w ten sposób, ja nie zamierzam bo to wprowadza chaos w ciągłość kodu.

 

W przypadku rekurencji pokazanej na górze w tym wątku... Uważasz, że jest to "rozwiazanie optymalne do problemu"?

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

W przypadku rekurencji pokazanej na górze w tym wątku... Uważasz, że jest to "rozwiazanie optymalne do problemu"?

Naprawde nie czytasz tych postow? Przeciez pisalem ze w tym przypadku iteracja jest lepszym rozwiazaniem i zreszta sam zaproponowalem rozwiazanie za pomoca do while ;) Edytowane przez krawetko

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Dołącz do dyskusji

Możesz dodać zawartość już teraz a zarejestrować się później. Jeśli posiadasz już konto, zaloguj się aby dodać zawartość za jego pomocą.

Gość
Dodaj odpowiedź do tematu...

×   Wklejono zawartość z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Odnośnik został automatycznie osadzony.   Przywróć wyświetlanie jako odnośnik

×   Przywrócono poprzednią zawartość.   Wyczyść edytor

×   Nie możesz bezpośrednio wkleić grafiki. Dodaj lub załącz grafiki z adresu URL.

Ładowanie


×
×
  • Dodaj nową pozycję...