getchar() i EOF

0
 #include <iostream>
#include <stdio.h>
//#include <stdbool.h>
#include <math.h>

/*
Napisz własne funkcje wypisujące i wczytujące dziesiętne liczby całkowite ze standardowego
wejścia (czytając/wypisując po znaku getchar()/putchar()). Liczba może zaczynać się od pewnej
liczby spacji po których następuje znak + lub -  po którym występuje ciąg cyfr dziesiętnych, aż
do napotkania spacji.
*/


int GetDec(int *ref)
{
	//zapisuje liczbe odwrotnie
    int ciag[20];
	//pamieta dlugosc ciagu
    int i = 0;
	//sprawdza czy liczba nie jest ujemna
    bool ujemna = false;	
	//czy byl plus minus lub cyrfra
    bool bylznak = false;
    int x;// do czytywania znaku

    while( (x = getchar()) != -1 )//dopoki wyjscie sie nie zakonczylo
    {
		//ok dostajemy spacje
		if( x == ' '  ){
			//jak cos wczesniej bylo to koniec -> wychodzimy z while
			if(bylznak) break;
			else {/*ignorujemy*/}
		}
		//ok mamy plus lub minus
		else if( x == '+' || x== '-'){
			//jesli jest pierwszy plus lub minus
			if(!bylznak){
				bylznak = true;				
				if(x == '-')ujemna = true;
			}
			//error -> dawaj od nowa
			else return GetDec(ref);
		}
		else if( x >= '0' && x <= '9'){
			//jesli dodatnia bez znaku
			if(!bylznak) bylznak = true;
			//dodajemy cyfre i zwieszamy dlugosc ciagu
			ciag[i] = x;
            i++;
		}
		else{
			if(x == '\n'  ){
				//if(bylznak) break;
				//else return 1;
			}
			//w naszej liczbie jest jakis syf
			if(bylznak) return GetDec(ref);
			else {/*ignoruj*/}
		}
    }
	//----------------------------------------------
    if( i > 0 ) i--; //dekrementujemy wskaznik
	
    //teraz odwracamy
    int liczba = 0;
    int pot = 0;
	//od konca cyfry mnozymy przez rosnace potegi dziesiatek tj 1,10,100 itd.
    while(i >= 0){
        double dz = 10;
		int d =  (ciag[i] - 48) * (int)pow(dz, pot);
		liczba += d;
		pot++;
		i--;
    }
    if(ujemna) liczba = -liczba;
    //ustawiamy liczbe	
    *ref = liczba; 	
	if(x == -1 ){ printf("Jest EOF"); return 1;}	
    return 0;
}

void PutDec(int w)
{//tu jest wszystko git majonez	
    int x;
    if(w < 0) { putchar('-'); x = -w; }
    else x = w;
	//jeszcze tylko szegolny przypadek od algorytmu
	if( x == 0) { putchar('0'); return; }
	//teraz zamiana z modulo i dzieleniem calkowitym potem obrocenie ciagu w dobra kolejnosc
    int ciag[20];
    int i = 0;
    while(x > 0){
        int l = x % 10;
        x /= 10;
        ciag[i] = l;;
        i++;
    }	
    while(i--){
        putchar(ciag[i]+48); // +48 == +'0'
    }
}

int main(void)
{

    int l  = 55;
    while( 1 )
    { 
		if ( GetDec( &l ) != 1){
			PutDec(l); 		
			putchar('\n');
		}
		else break;		

		if(l == 0) break;
	}  
	system("pause");
}

No więc mam taki kod i interesuje mnie czemu dla takiego przypadku:
np. "10 -5 123 [ctrl+z][enter]" wypisuje mi liczby po kolei 10 -5 123 ale nie wykrywa [ctrl+z] czyli EOF (moge dalej cos upychac do strumienia), chodzi o funkcje GetDec(). A jak już wpisze samo "[ctrl+z][enter]" to EOF zostaje wykryty. Nie mam pojęcia co może być nie tak, bo zakladajac ze na wejsciu jest EOF to:

 
int GetDec(int *ref)
{
//zapisuje liczbe odwrotnie
    int ciag[20];
	//pamieta dlugosc ciagu
    int i = 0;
	//sprawdza czy liczba nie jest ujemna
    bool ujemna = false;	
	//czy byl plus minus lub cyrfra
    bool bylznak = false;
    int x;// do czytywania znaku

   <del> while( (x = getchar()) != -1 )//dopoki wyjscie sie nie zakonczylo
    {
		//ok dostajemy spacje
		if( x == ' '  ){
			//jak cos wczesniej bylo to koniec -> wychodzimy z while
			if(bylznak) break;
			else {/*ignorujemy*/}
		}
		//ok mamy plus lub minus
		else if( x == '+' || x== '-'){
			//jesli jest pierwszy plus lub minus
			if(!bylznak){
				bylznak = true;				
				if(x == '-')ujemna = true;
			}
			//error -> dawaj od nowa
			else return GetDec(ref);
		}
		else if( x >= '0' && x <= '9'){
			//jesli dodatnia bez znaku
			if(!bylznak) bylznak = true;
			//dodajemy cyfre i zwieszamy dlugosc ciagu
			ciag[i] = x;
            i++;
		}
		else{
			if(x == '\n'  ){
				//if(bylznak) break;
				//else return 1;
			}
			//w naszej liczbie jest jakis syf
			if(bylznak) return GetDec(ref);
			else {/*ignoruj*/}
		}
    }</del>
	//----------------------------------------------
    if( i > 0 ) i--; //dekrementujemy wskaznik
	
    //teraz odwracamy
    int liczba = 0;
    int pot = 0;
	//od konca cyfry mnozymy przez rosnace potegi dziesiatek tj 1,10,100 itd.
    while(i >= 0){
        double dz = 10;
		int d =  (ciag[i] - 48) * (int)pow(dz, pot);
		liczba += d;
		pot++;
		i--;
    }
    if(ujemna) liczba = -liczba;
    //ustawiamy liczbe	
    *ref = liczba; 	
	if(x == -1 ){ printf("Jest EOF"); return 1;}	
    return 0;
}

Czyli gdy dostanie EOF na wejsciu nie powinno w ogole wejsc do petli reszta jest nie istotna i w koncu dochodzi do if(x == -1 ){ printf("Jest EOF"); return 1;} i powinno wywalic w mainie 1 i wyjsc z while(1). Ale tak sie nie dzieje w tym pierwszym przypadku co podalem. W tym drugim już jednak tak.

1

Okropnie to napisane jest. Nadaje się w zasadzie do przepisania. Może podam Ci szkielet to będzie ci łatwiej.

int GetDec(int *ref)
{
    // IgnoreWhiteSpace ma usunąć (wyłacznie) znaki białe ze strumienia
    IgnoreWhiteSpace();

    // ReadSign ma wczytać znak liczby (+/-), czyli
    // * pobieramy znak
    // * jeśli jest minusem to zwracamy -1
    // * jeśli jest plusem to zwracamy +1
    // * jeśli ani plusem ani minusem to zwracamy znak do strumienia i zwracamy +1
    int sign = ReadSign();

    int number;
    // ReadDigits ma wczytać (wyłacznie) cyfry ze strumienia i zamienić je na liczbę
    // zwrócić 1 jeśli udało się wczytać choć jedną cyfrę
    if (!ReadDigits(&number)) return 0;
    
    *ref = sign * number;
    return 1;
}

I teraz jak będziesz pobierać kolejne znaki i okaże się, że dany znak nie pasuje do wzorca (np. nie jest cyfrą) to zwróć go do strumienia (funkcja ungetc) aby kolejne funkcje mogły ten znak odczytać. Dla przykładu pokaże może IgnoreWhiteSpace:

int IgnoreWhiteSpace()
{
    int c;
    do {
        c = fgetc(stdin); // pobieramy znak
    } while (c != EOF && isspace(c)); // przerywamy gdy znak nie jest biały

    /* i tu uwaga, znak który wczytaliśmy nie jest znakiem białym */
    /* więc zwracamy go do strumienia by nie został pominięty przez kolejne funkcje */
    ungetc(c, stdin);
}

No i teraz możemy korzystać z funkcji w następujący sposób:

for (;;) {
    if (GetDec(&l)) {
        printf("Podana liczba to %d\n", l);
    } else if (feof(stdin)) {
        puts("Napotkano EOF, wychodzę");
        break;
    } else if (ferror(stdin)) {
        puts("Błąd strumienia, wychodzę");
        break;
    } else {
        puts("Nieprawidłowy format liczby!\n");
    }
}
1

Dzięki za sugestie. Wiem, że kod nie jest najlepszy, ale działa, i w sumie na tej samej zasadzie co ty podałeś. Jednak to nie jest odpowiedz na moje pytanie. Zakładając że nie mogę/nie chce, zwracać do strumienia, czemu w takim przypadku "-123 23 24 [ctrl+z][enter]" nie wykrywa, a w takim "[ctrl+z][enter]" wykrywa. Jak już napisałem w tym kodzie( w GetDec() ) dokładnie, nie ma żadnych returnów poza

while( (x = getchar()) != EOF) 

gdzie EOF nie wejdzie. Wiec może wytne tego while i zapytam czemu ten fragment nie dziala jak trzeba, albo zrobie nowy przyklad:

#include <stdio.h>

int Test(){
	int x = 0;
	while( ( x = getchar() ) != EOF){}
	if( x == EOF) return 1;
	return 0;
}

int main(void)
{    
    while( Test() != 1 )
    { 
		//tadabadum
	}
	printf("Hurra wyszedl z petli! weeee!\n");
	getchar();
} 

Jak widać w tym przykladzie jest ten sam problem: Jak zapodam ciag na wejscie "dsfadsafjks fds;kjdsf lkdsafjs[ctr+z][enter]" to nic sie nie dzieje dalej jest w while, a jak zapodam "[ctz+z][enter]" to wychodzi z petli -> jest napis "Hurra wyszedl z petli! weeee!". Może teraz ktoś mi odpowie?

1

Jeszcze jedno [ctrl+z] zakładam, że to EOF, wklepuje to w konsoli(na wejscie) w w systemie windows XP jeśli komuś ma to pomóc, a z tego co wiem to enter po prostu przekazuje to co wklepalem w konsoli do mojego programu na wejscie + siebie tez przekazuje. Wiec czemu raz wykrywa, a raz nie?

0

http://stackoverflow.com/a/1782134/224059

W szczególności: „Depending on the operating system, this character [Ctrl+Z] will only work if it's the first character on a line, i.e. the first character after an Enter.”

1

Dobra, dzięki. Fajnie gdybym to wiedział "przed" :)

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