[C] Czym zastapić fflush(stdin)?

Awatar użytkownika
Pneumokok
Użytkownik
Użytkownik
Posty: 48
Rejestracja: 2 sty 2011, o 14:29
Płeć: Mężczyzna
Lokalizacja: Małopolska
Podziękował: 11 razy
Pomógł: 1 raz

[C] Czym zastapić fflush(stdin)?

Post autor: Pneumokok » 29 cze 2011, o 11:55

Witajcie!

Mam pewien problem, choć właściwie go nie ma ale podobno jest.... Otóż:
Po wczytaniu z klawiatury danych za pomocą funkcji scanf/gets czyszczę bufor wejścia poprzez fflush(stdin) [przynajmniej do niedawna tak myslałem]. Na przykład:

Kod: Zaznacz cały

    printf("Podaj wys: "); scanf("%d", &wys); fflush(stdin);
    printf("Podaj szer; "); scanf("%d", &szer); fflush(stdin);
Nigdy nie napotkałem żadnych problemów z działaniem tej funkcji (bez niej programy dziwaczyły), jednak gdzieś wyczytałem że użycie fflusha dla stdin nie jest zdefiniowane przez standard i efekty tego działania mogą być nie do przewidzenia... Czym więc można zastąpić funkcję fflush(stdin)?

Pozdrawiam i dziekuję za pomoc,
Pneumokok.
Ostatnio zmieniony 29 cze 2011, o 19:52 przez Afish, łącznie zmieniany 1 raz.
Powód: Poprawa wiadomości.

soku11
Użytkownik
Użytkownik
Posty: 6607
Rejestracja: 16 sty 2007, o 19:42
Płeć: Mężczyzna
Podziękował: 119 razy
Pomógł: 1822 razy

[C] Czym zastapić fflush(stdin)?

Post autor: soku11 » 29 cze 2011, o 16:55

1. scanf/gets pobierają dane ze strumienia, a nie z klawiatury.
2. Co rozumiesz pod pojęciem czyścić strumień wejściowy?
3. Na strumieniu wejściowym się nie wykonuje funkcji fflush. fflush służy do "wypchnięcia" danych. Gdy zapisujesz coś do pliku, na początku dane są buforowane do strumienia plikowego. Jak ci się aplikacja za chwilę wywali, to nic się pewnie w takim pliku nie pojawi. Aby dane na pewno się zapisały wywołuje się fflush na tym strumieniu.
4. To fflush(stdin) to zapewne jakiś ogólnie UB, którego efektem ubocznym jest to do czego tego używasz.
5. Podejrzewam, że używasz tego, bo strumieniu po wczytaniu znaku pozostaje znak '\n'. W związku z tym zamiast fflush(stdin) wystarczy pobrać ten znak za pomocą getchar().

Awatar użytkownika
Pneumokok
Użytkownik
Użytkownik
Posty: 48
Rejestracja: 2 sty 2011, o 14:29
Płeć: Mężczyzna
Lokalizacja: Małopolska
Podziękował: 11 razy
Pomógł: 1 raz

[C] Czym zastapić fflush(stdin)?

Post autor: Pneumokok » 29 cze 2011, o 17:33

Mamy więc taki kod:

Kod: Zaznacz cały

#include <stdio.h>
int silnia(int);

int main()
{
    int liczba, wynik;
    printf("Podaj liczbe: "); scanf("%d", &liczba); fflush(stdin);
    wynik = silnia(liczba);
    printf("Silnia %d to %d
", liczba, wynik);
    getchar();
    return 0;
}

int silnia(int n)
{
    int wynik;
    if (n)
       wynik = n * silnia(n-1);
    else
       wynik=1;
    return wynik;
}
Który liczy silnię z liczby. W tym momencie działa on poprawnie, natomiast gdy np oznaczę flush(stdin) znakami komentarza //, program nie działa prawidłowo (tak jakby bardzo szybko się wykonał, okienko po wpisaniu liczby znika). Podobnie gdy zapiszę liczba=getchar();
Gdy napiszę:

Kod: Zaznacz cały

liczba=getchar(); 
fflush(stdin); 
Wynikiem zawsze jest 0, więc ów zapis także nie jest poprawny, problem nadal pozostał więc aktualny.
Używam Dev C++ 4.9.9.2

Pisząc o klawiaturze użyłem skrótu myślowego, o ile znaki pobieram przez getchara (wtedy też stosuję fflush(stdin) bo bez tego działa jak w podanym przykładzie) o tyle liczby scanfem.

soku11
Użytkownik
Użytkownik
Posty: 6607
Rejestracja: 16 sty 2007, o 19:42
Płeć: Mężczyzna
Podziękował: 119 razy
Pomógł: 1822 razy

[C] Czym zastapić fflush(stdin)?

Post autor: soku11 » 29 cze 2011, o 18:10

Chodziło mi o takie coś po prostu:

Kod: Zaznacz cały

	scanf("%d", &liczba);
	getchar();
	wynik = silnia(liczba);

Awatar użytkownika
Pneumokok
Użytkownik
Użytkownik
Posty: 48
Rejestracja: 2 sty 2011, o 14:29
Płeć: Mężczyzna
Lokalizacja: Małopolska
Podziękował: 11 razy
Pomógł: 1 raz

[C] Czym zastapić fflush(stdin)?

Post autor: Pneumokok » 29 cze 2011, o 18:15

Faktycznie, po tej modyfikacji:

Kod: Zaznacz cały

    printf("Podaj liczbe: "); scanf("%d", &liczba); getchar();
Nie jest już potrzebny fflush.

Dziękuję za pomoc

Awatar użytkownika
argv
Użytkownik
Użytkownik
Posty: 569
Rejestracja: 27 maja 2009, o 01:27
Płeć: Mężczyzna
Podziękował: 51 razy
Pomógł: 66 razy

[C] Czym zastapić fflush(stdin)?

Post autor: argv » 29 cze 2011, o 18:15

Nie kombinuj - to co chcesz zrobić to

Kod: Zaznacz cały

system("PAUSE"); 
przed returnem.

Awatar użytkownika
Pneumokok
Użytkownik
Użytkownik
Posty: 48
Rejestracja: 2 sty 2011, o 14:29
Płeć: Mężczyzna
Lokalizacja: Małopolska
Podziękował: 11 razy
Pomógł: 1 raz

[C] Czym zastapić fflush(stdin)?

Post autor: Pneumokok » 29 cze 2011, o 18:17

argv pisze:Nie kombinuj - to co chcesz zrobić to

Kod: Zaznacz cały

system("PAUSE"); 
przed returnem.
Nie bardzo rozumiem... To rozwiązanie problemy z fflushem?

Awatar użytkownika
argv
Użytkownik
Użytkownik
Posty: 569
Rejestracja: 27 maja 2009, o 01:27
Płeć: Mężczyzna
Podziękował: 51 razy
Pomógł: 66 razy

[C] Czym zastapić fflush(stdin)?

Post autor: argv » 29 cze 2011, o 18:20

Tak naprawdę to nie jest problem, tylko sztucznie taki wytworzyłeś. Jeśli chcesz zatrzymać program w devie na koniec by zobaczyć jego wyniki (co jak rozumiem chcesz zrobić), dajesz na końcu system("PAUSE") bez kombinowania z getcharami, fflushami itp.

Awatar użytkownika
Pneumokok
Użytkownik
Użytkownik
Posty: 48
Rejestracja: 2 sty 2011, o 14:29
Płeć: Mężczyzna
Lokalizacja: Małopolska
Podziękował: 11 razy
Pomógł: 1 raz

[C] Czym zastapić fflush(stdin)?

Post autor: Pneumokok » 29 cze 2011, o 18:22

Aa
Ale getchar() na samym końcu, przed returnem, daje podobny efekt - tyle, że system("pasue") coś tam wyświetla - ale nie w tym był akurat problem

Afish
Moderator
Moderator
Posty: 2823
Rejestracja: 15 cze 2008, o 15:45
Płeć: Mężczyzna
Lokalizacja: Seattle, WA
Podziękował: 3 razy
Pomógł: 354 razy

[C] Czym zastapić fflush(stdin)?

Post autor: Afish » 29 cze 2011, o 19:52

Pneumokok pisze:Jednak gdzieś wyczytałem że użycie fflusha dla stdin nie jest zdefiniowane przez standard i efekty tego działania mogą być nie do przewidzenia
Ogólnie odpalenie tej funkcji dla strumienia przeznaczonego do odczytu nie jest sprecyzowane i zależy od konkretnej implementacji. Zazwyczaj powoduje to wyczyszczenie strumienia.
Nie kombinuj - to co chcesz zrobić to

Kod: Zaznacz cały

system("PAUSE"); 
przed returnem.
Nieprzenośne, potrzebuje zewnętrznej aplikacji, czyli lepiej zrobić to inaczej.

Pneumokok, cały "problem" to pozostający znak w buforze. Scanf nie pobiera z bufora znaku nowej linii, więc pojedyncza instrukcja getchar() na końcu programu natrafi właśnie na niego, dlatego nie spowoduje "zatrzymania programu", tak jak byś chciał.

Awatar użytkownika
argv
Użytkownik
Użytkownik
Posty: 569
Rejestracja: 27 maja 2009, o 01:27
Płeć: Mężczyzna
Podziękował: 51 razy
Pomógł: 66 razy

[C] Czym zastapić fflush(stdin)?

Post autor: argv » 29 cze 2011, o 19:58

Nieprzenośne, potrzebuje zewnętrznej aplikacji, czyli lepiej zrobić to inaczej.
Napisałem przecież wyraźnie ...
Jeśli chcesz zatrzymać program w devie na koniec by zobaczyć jego wyniki ...
Oczywiście że nieprzenośne, bo nie jest częścią finalnego programu a jedynie sposobem obejrzenia wyników (o co jak rozumiem chodzi autorowi bo program mu się "za szybko wykonuje" )

ODPOWIEDZ