2010-09-21 98 views
26

Tôi có điều này nhưng một khi nó đạt đến EOF nghĩa vụ nó chỉ lặp lại vòng lặp và scanf một lần nữa.Làm thế nào để bạn đọc scanf cho đến khi EOF trong C?

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

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

     return 0; 
} 
+0

Bạn đang sử dụng đầu vào nào? Bạn đang chuyển hướng tệp sang 'stdin' hoặc nhập vào bảng điều khiển? Nếu sau này, bạn đang sử dụng hệ điều hành nào và bạn gõ vào EOF bằng cách nào? –

Trả lời

0

Bạn cần kiểm tra giá trị trả về EOF, không được chống lại 1.

Lưu ý rằng trong ví dụ của bạn, bạn cũng sử dụng hai tên biến khác nhau, wordsword, chỉ tuyên bố words, và không tuyên bố chiều dài của nó, mà phải là 16 để phù hợp với 15 ký tự đọc trong cộng với một nhân vật NUL.

14

Hãy thử:

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

Bạn cần phải so sánh scanf đầu ra với EOF

Vì bạn đang xác định một chiều rộng của 15 trong chuỗi định dạng, bạn sẽ đọc tối đa là 15 char. Vì vậy, mảng từ char phải có kích thước 16 (15 +1 cho null char). Vì vậy, hãy tuyên bố như sau:

char words[16]; 
+3

Điều này KHÔNG đúng. scanf trả về số lượng trường nhập đã quét thành công, KHÔNG BAO GIỜ EOF (-1). Vì vậy, vòng lặp while của bạn là dư thừa, nó sẽ phá vỡ ở lần đầu tiên. – user411313

+2

@ user411313 không, scanf có thể trả lại EOF, vì anh ấy so sánh bằng cách sử dụng! = Nó sẽ không phá vỡ lần đầu tiên. Tuy nhiên, trong trường hợp chung, bạn cũng muốn số lượng các mục được gán để bạn có thể thực hiện một số xác thực. – nos

+1

@ user411313: Cả [man scanf] (http://www.google.com/search?q=man+scanf) và C99 §7.19.6.2/16 đều cho biết có thể trả về EOF. –

3

Quét là khá nhiều rắc rối hơn giá trị của nó. Dưới đây là hai cách tốt hơn để làm những gì bạn đang cố gắng làm. Điều đầu tiên này là bản dịch trực tiếp nhiều hơn hoặc ít hơn của mã của bạn. Nó dài hơn, nhưng bạn có thể nhìn vào nó và thấy rõ nó làm gì, không giống với 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; 
} 

Và đây là phiên bản khác. Nó khó hơn một chút để xem điều này thực hiện bằng cách kiểm tra, nhưng nó không phá vỡ nếu một dòng dài hơn 1024 ký tự, vì vậy đó là mã tôi sẽ sử dụng trong sản xuất. (Vâng, thực sự những gì tôi sẽ sử dụng trong sản xuất là tr -s '[:space:]' '\n', nhưng đây là cách bạn thực hiện một cái gì đó như thế.)

#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

Vâng, đó là * nhiều * đơn giản hơn 'cho (char buf [1024]; scanf ("% 1023 ", buf) == 1;) printf ("% s \ n ", buf);', ngoại trừ bạn đã thay đổi hành vi trong các trường hợp nhất định của khoảng trắng hàng đầu, theo sau và liền kề. –

+0

Trong cuộc sống thực, tôi sẽ viết một vòng lặp trên các ký tự riêng biệt với chính xác khoảng trắng mà tôi muốn (có thể hoặc không phải là những gì OP muốn - họ không nói), nhưng điều đó sẽ quá tẻ nhạt cho một ví dụ. Nếu bạn đang sử dụng scanf, dù sao thì bạn cũng không phải quan tâm đến hành vi của trường hợp cạnh hoặc lỗi. – zwol

+0

... bạn biết không, nó không * quá tẻ nhạt. Ví dụ viết lại. – zwol

3

Mã của bạn vòng cho đến khi nó đọc một từ duy nhất, sau đó thoát ra. Vì vậy, nếu bạn cho nó nhiều từ nó sẽ đọc đầu tiên và thoát ra, trong khi nếu bạn cho nó một đầu vào rỗng, nó sẽ lặp mãi mãi. Trong mọi trường hợp, nó sẽ chỉ in rác ngẫu nhiên từ bộ nhớ chưa được khởi tạo. Đây rõ ràng không phải là thứ bạn muốn, nhưng bạn muốn gì? Nếu bạn chỉ muốn đọc và in từ đầu tiên (nếu nó tồn tại), sử dụng nếu:

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

Nếu bạn muốn lặp miễn là bạn có thể đọc một từ, sử dụng khi:

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

Ngoài ra, như những người khác đã lưu ý, bạn cần phải cung cấp cho các mảng từ một kích thước đó là đủ lớn cho scanf của bạn:

char word[16]; 

những người khác đã đề nghị xét nghiệm cho EOF thay vì kiểm tra có bao nhiêu mục scanf phù hợp. Điều đó tốt cho trường hợp này, nơi scanf không thể không khớp trừ khi có EOF, nhưng không tốt trong các trường hợp khác (ví dụ như cố gắng đọc số nguyên), trong đó scanf có thể khớp với không có gì mà không đạt EOF (nếu đầu vào là không) t một số) và trả về 0.

chỉnh sửa

Hình như bạn đã thay đổi câu hỏi của bạn để phù hợp với mã của tôi mà làm việc tốt khi tôi chạy nó - loops đọc lời cho đến khi EOF đạt được và sau đó thoát ra. Vì vậy, cái gì khác đang xảy ra với mã của bạn, có lẽ liên quan đến cách bạn đang nuôi dưỡng nó đầu vào theo đề nghị của David

+0

Hey cảm ơn bạn đã trả lời, nhưng bạn đã thử điều này? Tôi nhận ra rằng tôi đặt "! =" Vào bài viết gốc của mình nhưng ý tôi là ==, và điều này cho tôi những gì tôi muốn, nơi tôi gõ một câu khi scanf được gọi, sau đó nó lặp lại và in ra những từ như nó được cho là quá , sau đó nó gọi scanf một lần nữa mà tôi không muốn. Nó gọi nó để lại cho tôi không có cách nào để thoát ra khỏi vòng lặp. Có lẽ trình biên dịch của tôi? nhưng vấn đề duy nhất là sau khi nó in tất cả các từ mà nó không phá vỡ. – JJRhythm

+2

@ user315903: Đó là lý do tại sao ý tưởng tốt nhất là đăng mã không hoạt động, thay vì cố gắng nhập nội dung tương tự. Nếu mã của bạn không hoạt động, vì lý do bạn không hiểu, thì bạn không hiểu điều gì sai và không thể tin tưởng bản thân để giữ nguyên bản chất của vấn đề. –

-3

Đối với người dùng C, điều này cũng sẽ làm việc

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

-1 Để sử dụng 'get'. –

+2

Để được rõ ràng, vấn đề với 'được' là nó có thể viết vượt ra ngoài kết thúc của bộ đệm được cấp phát. –

-2

Tôi đoán cách tốt nhất để làm điều này là ...

int main() 
{ 
    char str[100]; 
    scanf("[^EOF]",str); 
    printf("%s",str); 
    return 0;  
} 
Các vấn đề liên quan