2010-09-21 13 views
26

Mam to, ale gdy osiągnie rzekomy EOF, ponownie powtarza pętlę i scanf.Jak czytasz scanf do EOF w C?

int main(void) 
{ 
     char words[16]; 

     while(scanf("%15s", words) == 1) 
      printf("%s\n", words); 

     return 0; 
} 
+0

Jakiego wejścia używasz? Czy przekierowujesz plik na 'stdin' lub piszesz na konsoli? Jeśli to drugie, z jakiego systemu operacyjnego korzystasz i jak wpisujesz w EOF? –

Odpowiedz

0

Trzeba sprawdzić wartość zwracana przed EOF, a nie przeciwko 1.

Należy zauważyć, że w przykładzie, użyto również dwie różne nazwy zmiennych, words i word, tylko oświadczył words i nie deklarują jego długości, która powinna wynosić 16, aby pasowały do ​​15 znaków odczytane w plus NUL charakteru.

14

Spróbuj:

while(scanf("%15s", words) != EOF) 

trzeba porównać scanf wyjście z EOF

Ponieważ jesteś określający szerokość 15 w ciągu formatu, będziesz czytać co najwyżej 15 char. Tak więc tablica znaków char powinna mieć rozmiar 16 (15 +1 dla char). Tak więc zadeklaruj jako:

char words[16]; 
+3

To NIE jest prawdą. scanf zwraca liczbę poprawnie odczytanych pól wejściowych, NIGDY EOF (-1). W związku z tym pętla while jest zbędna, zostanie przerwana za pierwszym razem. – user411313

+2

@ user411313 nie, scanf może zwrócić EOF, ponieważ porównuje użycie! = Nie zostanie przerwane za pierwszym razem. Jednak w ogólnym przypadku należy również ustawić liczbę przypisanych elementów, aby można było przeprowadzić walidację. – nos

+1

@ user411313: Zarówno [man scanf] (http://www.google.com/search?q=man+scanf), jak i C99 §7.19.6.2/16 mówią, że może zwrócić EOF. –

3

Scanf to prawie zawsze więcej kłopotów niż jest warte. Oto dwa lepsze sposoby robienia tego, co próbujesz zrobić. Ten pierwszy jest bardziej lub mniej bezpośrednim tłumaczeniem twojego kodu. Jest dłuższy, ale możesz patrzeć na niego i wyraźnie widzieć, co robi, w przeciwieństwie do scanf.

#include <stdio.h> 
#include <ctype.h> 
int main(void) 
{ 
    char buf[1024], *p, *q; 
    while (fgets(buf, 1024, stdin)) 
    { 
     p = buf; 
     while (*p) 
     { 
      while (*p && isspace(*p)) p++; 
      q = p; 
      while (*q && !isspace(*q)) q++; 
      *q = '\0'; 
      if (p != q) 
       puts(p); 
      p = q; 
     } 
    } 
    return 0; 
} 

A oto kolejna wersja. Trochę trudniej jest zobaczyć, co to robi przez inspekcję, ale nie pęka, jeśli linia jest dłuższa niż 1024 znaki, więc jest to kod, którego użyłbym w produkcji. (Dobrze, naprawdę co chciałbym użyć w produkcji jest tr -s '[:space:]' '\n', ale to, w jaki sposób zaimplementować coś takiego.)

#include <stdio.h> 
#include <ctype.h> 
int main(void) 
{ 
    int ch, lastch = '\0'; 
    while ((ch = getchar()) != EOF) 
    { 
     if (!isspace(ch)) 
      putchar(ch); 
     if (!isspace(lastch)) 
      putchar('\n'); 
     lastch = ch; 
    } 
    if (lastch != '\0' && !isspace(lastch)) 
     putchar('\n'); 
    return 0; 
} 
+0

Tak, to * znacznie * prostsze niż 'dla (char buf [1024]; scanf ("% 1023s ", buf) == 1;) printf ("% s \ n ", buf);', z wyjątkiem tego, że zmieniono zachowanie w niektórych przypadkach początkowych, końcowych i przyległych białych znaków. –

+0

W prawdziwym życiu napisałbym pętlę nad poszczególnymi postaciami z dokładnie tymi zachowaniem, których chciałem (co może, ale nie musi być tym, co OP chciał - nie powiedzieli), ale byłoby to na przykład zbyt nużące. Jeśli używasz scanf, to nie musisz przejmować się zachowaniem krawędzi ani usuwaniem błędów. – zwol

+0

... wiesz co, to * nie * jest zbyt uciążliwe. Przepisz przykład. – zwol

3

Kod pętle aż odczytuje jedno słowo, a następnie kończy działanie. Więc jeśli dasz mu wiele słów, przeczyta pierwszy i wyjdzie, a jeśli dasz mu puste wejście, zapętli się na zawsze. W każdym razie wydrukuje tylko losowe śmieci z niezainicjowanej pamięci. To najwyraźniej nie jest to, czego chcesz, ale czego chcesz? Jeśli chcesz po prostu czytać i drukować pierwsze słowo (jeśli istnieje), należy użyć, jeśli:

if (scanf("%15s", word) == 1) 
    printf("%s\n", word); 

Jeśli chcesz pętli tak długo, jak można przeczytać słowa, należy natomiast:

while (scanf("%15s", word) == 1) 
    printf("%s\n", word); 

Ponadto, jak inni to zauważyli, trzeba podać tablicę Word rozmiar, który jest wystarczająco duży dla scanf:

char word[16]; 

inni sugerowali testów dla EOF zamiast sprawdzania ile przedmiotów scanf dopasowane. To jest w porządku w tym przypadku, gdy scanf nie może się nie dopasować, chyba że istnieje EOF, ale nie jest tak dobry w innych przypadkach (na przykład próbuje odczytać liczby całkowite), gdzie scanf może pasować do niczego bez osiągnięcia EOF (jeśli wejście nie jest równe '). t liczba) i zwraca 0.

edit

Wygląda na to, że zmieniła swoje pytanie, aby dopasować mój kod, który działa dobrze, gdy go uruchomić - pętle czyta słowa, aż do osiągnięcia EOF, a następnie kończy działanie. Więc coś innego się dzieje z kodem, być może związane z wejściem jak karmisz go jako sugerowane przez Dawida

+0

Hej, dziękuję za odpowiedź, ale czy próbowałeś tego? Zdałem sobie sprawę, że umieszczam "! =" Na moim oryginalnym wpisie, ale miałem na myśli ==, a to daje mi to, co chcę, w którym wpisuję zdanie, gdy wywoływany jest scanf, to pętle i wypisuje słowa, jak to jest również przypuszczane , następnie wywołuje scanf, którego nie chcę. Nazywa to, zostawiając mnie bez możliwości wyrwania się z pętli. Może mój kompilator? ale jedynym problemem jest to, że po wydrukowaniu wszystkich słów, które nie pękają. – JJRhythm

+2

@ user315903: Dlatego najlepiej jest opublikować kod, który nie działa, zamiast pisać coś podobnego. Jeśli Twój kod nie działa, z przyczyn, których nie rozumiesz, nie rozumiesz, co jest nie tak i nie możesz zaufać sobie, by zachować istotę problemu. –

-3

Dla użytkowników C, to będzie również działać

while (gets(str) != NULL) 
+9

-1 Do używania 'dostaje'. –

+2

Dla jasności, problemem z 'dostaje' jest to, że może on pisać poza końcem przydzielonego bufora. –

-2

Chyba najlepszym sposobem na to jest ...

int main() 
{ 
    char str[100]; 
    scanf("[^EOF]",str); 
    printf("%s",str); 
    return 0;  
}