ShDe Opublikowano 8 Grudnia 2008 Zgłoś Opublikowano 8 Grudnia 2008 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. Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
carck3r Opublikowano 8 Grudnia 2008 Zgłoś Opublikowano 8 Grudnia 2008 (edytowane) #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 8 Grudnia 2008 przez carck3r Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
shooter Opublikowano 9 Grudnia 2008 Zgłoś Opublikowano 9 Grudnia 2008 rekurencja :) Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
PelzaK Opublikowano 9 Grudnia 2008 Zgłoś Opublikowano 9 Grudnia 2008 (edytowane) 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 9 Grudnia 2008 przez PelzaK Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
shooter Opublikowano 10 Grudnia 2008 Zgłoś Opublikowano 10 Grudnia 2008 (edytowane) 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 10 Grudnia 2008 przez shooter Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
PelzaK Opublikowano 10 Grudnia 2008 Zgłoś Opublikowano 10 Grudnia 2008 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. Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
rezo_ Opublikowano 10 Grudnia 2008 Zgłoś Opublikowano 10 Grudnia 2008 (edytowane) 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 10 Grudnia 2008 przez krawetko Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
grzybiarz Opublikowano 10 Grudnia 2008 Zgłoś Opublikowano 10 Grudnia 2008 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ę :] Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
rezo_ Opublikowano 10 Grudnia 2008 Zgłoś Opublikowano 10 Grudnia 2008 (edytowane) 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 10 Grudnia 2008 przez krawetko Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
shooter Opublikowano 10 Grudnia 2008 Zgłoś Opublikowano 10 Grudnia 2008 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 :) Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
grzybiarz Opublikowano 10 Grudnia 2008 Zgłoś Opublikowano 10 Grudnia 2008 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. Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
rezo_ Opublikowano 10 Grudnia 2008 Zgłoś Opublikowano 10 Grudnia 2008 (edytowane) 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 10 Grudnia 2008 przez krawetko Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
jediknight Opublikowano 10 Grudnia 2008 Zgłoś Opublikowano 10 Grudnia 2008 Nie będzie żadnego przepełnienia stosu, bo ta rekurencja jest ogonowa i nie używa stosu ;) Imo najbardziej elegancki program podał shooter. Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
rezo_ Opublikowano 10 Grudnia 2008 Zgłoś Opublikowano 10 Grudnia 2008 (edytowane) 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 10 Grudnia 2008 przez krawetko Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
shooter Opublikowano 10 Grudnia 2008 Zgłoś Opublikowano 10 Grudnia 2008 Nie będzie żadnego przepełnienia stosu, bo ta rekurencja jest ogonowa i nie używa stosu ;) Imo najbardziej elegancki program podał shooter. to pomysl krewetko - ja go tylko zacytowalem :) Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
PelzaK Opublikowano 11 Grudnia 2008 Zgłoś Opublikowano 11 Grudnia 2008 ino używanie rekurencji gdzie nie jest potrzebna jest średnim pomysłem. Chociażby z powodu takowego, że ciężko się to debuguje ;) Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
rezo_ Opublikowano 11 Grudnia 2008 Zgłoś Opublikowano 11 Grudnia 2008 (edytowane) 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 11 Grudnia 2008 przez krawetko Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
PelzaK Opublikowano 12 Grudnia 2008 Zgłoś Opublikowano 12 Grudnia 2008 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... Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
rezo_ Opublikowano 12 Grudnia 2008 Zgłoś Opublikowano 12 Grudnia 2008 (edytowane) 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 12 Grudnia 2008 przez krawetko Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
Polar Opublikowano 12 Grudnia 2008 Zgłoś Opublikowano 12 Grudnia 2008 Rekurencja zwiększa takze czytelność rozwiązania Zależy dla kogo. oraz łatwość jego modyfikacji w stosunku do równoważnego rozwiązania iteracyjnego Zależy od problemu. Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
PelzaK Opublikowano 12 Grudnia 2008 Zgłoś Opublikowano 12 Grudnia 2008 (edytowane) 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 12 Grudnia 2008 przez PelzaK Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
rezo_ Opublikowano 12 Grudnia 2008 Zgłoś Opublikowano 12 Grudnia 2008 (edytowane) 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 13 Grudnia 2008 przez krawetko Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
PelzaK Opublikowano 13 Grudnia 2008 Zgłoś Opublikowano 13 Grudnia 2008 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"? Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
shooter Opublikowano 14 Grudnia 2008 Zgłoś Opublikowano 14 Grudnia 2008 PelzaK masz racje - trzeba pisac najprosciej jak sie da. Rozwiazanie rekurencyjne nie jest optymalnym w tym przypadku, ale nie ma juz co sie rozwodzic o tym. Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
rezo_ Opublikowano 14 Grudnia 2008 Zgłoś Opublikowano 14 Grudnia 2008 (edytowane) 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 14 Grudnia 2008 przez krawetko Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
PelzaK Opublikowano 20 Grudnia 2008 Zgłoś Opublikowano 20 Grudnia 2008 kto by tam posty czytał ;) tu chodzi o pisanie :twisted: Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...