2013-06-13 43 views
5

Mã sau đây cung cấp o/p kỳ lạ ngay sau khi tôi biên dịch nó.Tại sao chúng ta cần đặt khoảng trống trước% c?

main() { 
    char name[3]; 
    float price[3]; 
    int pages[3], i; 

    printf ("\nEnter names, prices and no. of pages of 3 books\n") ; 

    for (i = 0 ; i <= 2 ; i++) 
     scanf ("%c %f %d", &name[i], &price[i], &pages[i]); 

    printf ("\nAnd this is what you entered\n") ; 

    for (i = 0 ; i <= 2 ; i++) 
     printf ("%c %f %d\n", name[i], price[i], pages[i]); 
} 

Nhưng nếu chúng tôi đưa khoảng trắng trong báo cáo scanf trước% c, nó sẽ cung cấp đúng o/p.

Có ai vui lòng giải thích cho tôi lý do tại sao không?

Cập nhật: -

Nếu tôi cung cấp đầu vào như this-

F 
123.45 
56 
J 
134 
67 
K 
145 
98 

sau đó câu hỏi của tôi là tại sao chúng ta không được đưa ra không gian trước% f và không gian trước% d? Tại sao chúng ta cần cung cấp khoảng trống trước% c?

+1

Bạn đang đề cập đến '"% c "' nào? –

+0

Và đầu ra thích hợp là gì? Đầu ra của chương trình là gì? –

+0

@JeffMercado, đã cập nhật câu hỏi của tôi. Tôi đang nói về tuyên bố scanf. –

Trả lời

11

Thêm khoảng trắng vào chuỗi định dạng cho phép scanf để sử dụng ký tự dòng mới từ đầu vào xảy ra mỗi khi bạn nhấn trả lại. Nếu không có không gian, name[i] sẽ nhận được mã số '\n'thực char bị bỏ qua để được hiểu sai bởi %f.

Vì vậy, nói đầu vào của bạn là

a 1.0 2 
b 3.0 4 
c 5.0 6 

Chương trình nhìn thấy nó như thế này:

a 1.0 2\nb 3.0 4\nc 5.0 6\n\377 

Đó là, các dòng-chia là những nhân vật thực tế trong file (và \ 377 ở đây cho biết "kết thúc tệp").

Đầu tiên scanf sẽ xuất hiện để hoạt động tốt, tiêu thụ char, phao và số nguyên. Nhưng nó để lại các đầu vào như thế này:

\nb 3.0 4\nc 5.0 6\n\377 

Vì vậy, thứ hai scanf sẽ đọc '\n' tính theo% c của nó, trừ khi bạn thoát khỏi nó lần đầu tiên.

Thêm khoảng trắng vào chuỗi định dạng hướng dẫn quét để loại bỏ bất kỳ ký tự khoảng trống nào (bất kỳ khoảng trắng ' ', tab '\t' hoặc newline '\n').

Một chỉ là một trong các nội dung sau:

  • Một chuỗi các ký tự trắng-space (không gian, tab, xuống dòng, vv .; thấy isspace (3)). Chỉ thị này khớp với bất kỳ khoảng trắng nào, kể cả không có gì trong đầu vào.

  • ...

từ http://linux.die.net/man/3/scanf


loại này của vấn đề phát sinh bất cứ khi nào bạn sử dụng scanf với %c trong một vòng lặp.Bởi vì, giả sử dạng tự do đầu vào, dòng mới có thể xảy ra ở mọi nơi. Vì vậy, thông thường, hãy cố gắng tránh toàn bộ vấn đề bằng cách sử dụng phương pháp hai tầng. Bạn đọc dòng đầu vào vào bộ đệm (sử dụng fgets); chop-off các ký tự dòng mới ngớ ngẩn; sau đó sử dụng sscanf thay vì scanf để đọc từ bộ đệm (chuỗi) thay vì thẳng từ tệp.

+0

Cảm ơn bạn đã đề xuất. Tôi vẫn không thể hiểu khái niệm này. Xin lỗi vì sự thiếu hiểu biết của tôi, tôi mới đến C. –

+0

Đã thêm một số giải thích thêm. –

+2

Chỉ cần thêm vào luser droog. Ký tự dòng mới sẽ được lưu trữ trong bộ đệm và scanf đầu tiên nhìn thấy bộ đệm và nếu bộ đệm không trống thì nó sẽ lấy đầu vào từ bộ đệm. Nếu không nó lấy từ stdin. Vì vậy, inorder để tuôn ra bộ đệm chúng tôi đặt không gian trước mặt của% c trong scanf. –

3

đầu vào sai sử dụng% c

Hãy xem xét các đoạn mã sau đây:

int main(){ 
int x; 
char y; 
scanf("%d", &x); 
scanf("%c", &y); 
printf("%d %c", x, y); 
} 

Hành vi:
Khi bạn chạy chương trình trên, scanf đầu tiên được gọi sẽ đợi bạn nhập số thập phân. Giả sử bạn nhập 12 (Đó là ASCII ‘1’ và ASCII ‘2’). Sau đó, bạn nhấn phím "enter" để báo hiệu kết thúc của đầu vào. Tiếp theo chương trình sẽ thực hiện quét lần thứ hai , ngoại trừ bạn sẽ nhận thấy rằng chương trình không chờ bạn nhập ký tự và thay vào đó đi tới đầu ra 12 theo sau bởi ‘\ n’.



Giải thích:
Tại sao điều đó xảy ra? Hãy xem xét hành vi của từng bước một của chương trình . Ban đầu không có gì trong bộ đệm. Khi scanf() đầu tiên được gọi, nó không có gì là để đọc, và vì vậy nó chờ đợi. Nó tiếp tục chờ cho đến khi bạn gõ 1,2, sau đó "nhập". Bây giờ, những gì trong bộ đệm là ký tự 1, ký tự 2 và ký tự ‘\ n’. Hãy nhớ rằng ‘\ n’ biểu thị kết thúc của đầu vào, khi tất cả các trường đã được nhập, nhưng nó cũng được lưu trữ trong bộ đệm dưới dạng ký tự ASCII. Tại thời điểm này scanf sẽ đọc đầu vào thập phân lớn nhất từ ​​ bộ đệm và chuyển đổi thành số nguyên. Trong ví dụ này, nó tìm thấy chuỗi "12" và chuyển đổi nó thành giá trị thập phân mười hai và đặt nó trong x. Sau đó, scanf trả về kiểm soát trở lại chức năng chính và trả về giá trị 1, để có thể chuyển đổi một mục nhập thành công. Trong ví dụ của chúng ta, chúng ta không bắt được giá trị trả về của scanf trong một biến. Đối với mã mạnh mẽ, điều quan trọng là kiểm tra giá trị trả về của scanf() để đảm bảo rằng người dùng đã nhập dữ liệu chính xác.



gì bây giờ còn lại trong bộ đệm là ‘\ n’. Tiếp theo, scanf thứ hai là được gọi và nó mong đợi một nhân vật. Vì bộ đệm đã có ký tự ‘\ n’ trong đó, scanf thấy rằng, lấy nó từ bộ đệm, và đặt nó vào y. Đó là lý do tại sao khi bạn thực hiện printf sau đó, 12 và “enter” được in ra màn hình.



Giải pháp:
đạo đức của câu chuyện là, nhập là một nhân vật giống như bất kỳ khác, và được nhập vào bộ đệm, và tiêu thụ từ bộ đệm bởi% c chỉ như bất kỳ ký tự ASCII nào khác. Để sửa lỗi này, hãy thử sử dụng mã này thay vì:


int main(){ 
int x; 
char y; 
scanf("%d", &x); 
scanf("\n%c", &y); /* note the \n !! */ 
printf("%d %c", x, y); 
} 


**

như thế nào này có khắc phục vấn đề này?


** Vì vậy, bạn lại gõ ‘1’,’2’ ,’ \ n’. Lần quét đầu tiên đọc "1" và "2", chuyển đổi thành số thập phân mười hai và để lại ‘\ n’ trong bộ đệm. Lần quét tiếp theo hiện mong đợi ‘\ n’ ở đầu đầu vào tiếp theo. Nó tìm thấy ‘\ n’ trong bộ đệm, đọc nó và loại bỏ nó. Bây giờ bộ đệm trống và scanf đang chờ người dùng nhập ký tự. Nói người dùng nhập ‘c’, theo sau là phím enter. ‘C’ bây giờ là được gán cho y, NOT "enter". Do đó printf sẽ xuất ra "12 c" đến màn hình . LƯU Ý: lại một lần nữa ‘\ n’ đang ngồi trong hàng đợi ngay bây giờ. Vì vậy, nếu bạn cần thực hiện một lần quét khác cho một ký tự, bạn sẽ phải "tiêu thụ" rằng '\ n' trước khi lấy một ký tự khác từ người dùng.

Đây không phải là một vấn đề đối với bất kỳ specifier định dạng khác, như tất cả họ đều bỏ qua không gian trắng trước đầu vào.

+0

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 một ** [, c, hoặc n ** specifier – chux

+1

Hầu hết câu trả lời của bạn được định dạng dưới dạng trích dẫn. Nếu bạn đang trích dẫn một số nguồn, tôi khuyên bạn nên ghi nhận nó; nếu không, chỉ cần viết văn bản thuần túy. –

Các vấn đề liên quan