2012-03-05 43 views
18

Tôi có khối mã này (chức năng bỏ qua như logic là một phần của một bài tập về nhà):C: của Nhiều scanf, khi tôi nhập vào một giá trị cho một scanf nó bỏ qua scanf thứ hai

#include <stdio.h> 

int main() 
{ 
    char c = 'q'; 
    int size; 

    printf("\nShape (l/s/t):"); 
    scanf("%c",&c); 

    printf("Length:"); 
    scanf("%d",&size); 

    while(c!='q') 
    { 
     switch(c) 
     { 
      case 'l': line(size); break; 
      case 's': square(size); break; 
      case 't': triangle(size); break; 
     } 


     printf("\nShape (l/s/t):"); 
     scanf("%c",&c); 

     printf("\nLength:"); 
     scanf("%d",&size); 
    } 

    return 0; 
} 

Các Đầu tiên, Scanf làm việc rất tốt, không có vấn đề gì khi chúng ta đi vào vòng lặp while, tôi gặp vấn đề ở đâu, khi bạn được yêu cầu nhập một char hình dạng mới, thay vào đó nhảy xuống số printf của Length và đợi nhập từ đó cho một char, sau đó là một số thập phân trên vòng lặp tiếp theo của vòng lặp.

Lặp lại vòng lặp:

Scanf: Hình dạng. Tác phẩm Tuyệt vời
Scanf: Độ dài. Không có vấn đề

Vòng 1.

Scanf: Hình dạng. Bỏ qua số này
Scanf: length. Vấn đề, scanf này ánh xạ tới hình dạng char.

Vòng 2
Quét: Hình dạng. Bỏ qua số này
Scanf: length. Vấn đề, scanf này ánh xạ tới kích thước int bây giờ.

Tại sao lại thực hiện việc này?

Trả lời

34

scanf("%c") đọc ký tự dòng mới từ phím ENTER.

Khi bạn gõ giả 15, bạn gõ một 1, một 5 và sau đó nhấn ENTER then chốt. Vì vậy, bây giờ có ba ký tự trong bộ đệm đầu vào. scanf("%d") đọc số 15, diễn giải chúng dưới dạng số 15, nhưng ký tự dòng mới vẫn nằm trong bộ đệm đầu vào. scanf("%c") sẽ ngay lập tức đọc ký tự dòng mới này và sau đó chương trình sẽ chuyển sang số scanf("%d") tiếp theo và đợi bạn nhập số.

Lời khuyên thông thường là đọc toàn bộ dòng đầu vào với fgets và diễn giải nội dung của từng dòng trong một bước riêng biệt. Một giải pháp đơn giản cho vấn đề trước mắt của bạn là thêm getchar() sau mỗi scanf("%d").

+0

Đó là tuyệt vời !! Cảm ơn^_^ – noMAD

+0

Bạn vừa mới cứu mạng tôi. –

+2

'scanf ("% d "); kết hợp getchar(); 'không thành công nếu người dùng vô tình nhập vào một dấu cách (hoặc các thùng rác khác) sau số đó. – ilkkachu

1

Khi bạn nhập hình dạng và ENTER, hình dạng được tiêu thụ bởi scanf đầu tiên, nhưng ENTER không phải là! Các scanf thứ hai hy vọng một số như vậy, ENTER được bỏ qua bởi vì được coi là một không gian màu trắng, và scanf chờ đợi cho một đầu vào hợp lệ (một số) mà, một lần nữa, được chấm dứt bởi ENTER. Vâng, số lượng được tiêu thụ, nhưng ENTER không phải là, do đó, các scanf đầu tiên bên trong trong khi sử dụng nó và dấu nhắc hình dạng của bạn bị bỏ qua ... quá trình này lặp đi lặp lại. Bạn phải thêm% c khác trong scanfs để xử lý phím ENTER. Tôi hi vọng cái này giúp được!

1

Ký tự '\n' vẫn còn trên luồng đầu vào sau khi cuộc gọi đầu tiên đến scanf hoàn tất, vì vậy lệnh gọi thứ hai là scanf() đọc số này. Sử dụng getchar().

5

Sử dụng chức năng

void fflushstdin(void) 
{ 
    int c; 
    while((c = fgetc(stdin)) != EOF && c != '\n'); 
} 

để xóa khỏi bộ đệm đầu vào của bạn.

+0

Đây là một chức năng tốt. Để dễ đọc, tôi sẽ đặt câu lệnh null (dấu chấm phẩy đơn) trên một dòng riêng biệt. –

+1

Tôi cũng thích điều này, nhưng tôi nghĩ nó sẽ là tốt nhất * không * để sử dụng từ "tuôn ra", vì điều này có một định nghĩa được thiết lập trong tiêu chuẩn mâu thuẫn với việc sử dụng ở đây. Có lẽ 'seek_to_next_line' sẽ là một tên mô tả hơn? – Sebivor

18

Vấn đề cơ bản là scanf() để lại dòng mới sau số trong bộ đệm, và sau đó đọc nó với %c trên lần vượt tiếp theo. Trên thực tế, đây là một minh chứng tốt về lý do tại sao tôi không sử dụng scanf(); Tôi sử dụng trình đọc dòng (ví dụ: fgets()) và sscanf(). Nó dễ kiểm soát hơn.

Bạn có thể giải cứu nó bằng cách sử dụng " %c" thay vì "%c" cho chuỗi định dạng. Các ô trống gây ra scanf() để bỏ qua khoảng trắng (bao gồm cả dòng mới) trước khi đọc ký tự.

Nhưng sẽ dễ dàng hơn trong thời gian dài để từ bỏ scanf()fscanf() và sử dụng fgets() hoặc tương đương với sscanf(). Ngoài ra, báo cáo lỗi sẽ dễ dàng hơn nhiều khi bạn có toàn bộ chuỗi để làm việc, chứ không phải các driblets bị bỏ lại sau scanf() sau khi nó không thành công.

Bạn cũng nên luôn luôn kiểm tra xem bạn có nhận được giá trị được chuyển đổi từ scanf() hay không. Dữ liệu nhập không thành công — thường xuyên và khủng khiếp. Đừng để nó phá hỏng chương trình của bạn bởi vì bạn đã không kiểm tra.

4

Thử thêm khoảng trắng trong tệp quét.

scanf(" %d", &var); 
// ^
// there 

Điều này sẽ gây ra tất cả khoảng trắng trước khi khớp với số nguyên.

+1

Theo [phần 7.21.6.2p8] (http://port70.net/~nsz/c/c11/n1570.html#7.21.6.2p8), 'scanf' sẽ * bình thường * loại bỏ tất cả khoảng trống trước khi khớp với một số nguyên Tuy nhiên, hiển thị khoảng trống trong chuỗi định dạng này vô nghĩa: * "Nhập ký tự khoảng trắng (như được chỉ định bởi hàm isspace) bị bỏ qua, trừ khi đặc tả bao gồm [, c, hoặc n specifier." * – Sebivor

+0

Điều này sẽ không khắc phục sự cố. '% d' đã bỏ qua các ký tự trắng khoảng trắng. –

1

Bạn cũng có thể sử dụng scanf("%c%*c", &c); để đọc hai nhân vật và bỏ qua những người cuối cùng (trong trường hợp này '\ n')