scanf () để lại ký tự dòng mới trong bộ đệm


88

Tôi có chương trình sau:

int main(int argc, char *argv[])
{
  int a, b;
  char c1, c2;
  printf("Enter something: ");
  scanf("%d",&a); // line 1
  printf("Enter other something: ");
  scanf("%d", &b); // line 2

  printf("Enter a char: ");
  scanf("%c",&c1); // line 3
  printf("Enter another char: ");
  scanf("%c", &c2); // line 4

  printf("Done"); // line 5

  system("PAUSE");

  return 0;
}

Khi tôi đọc trong cuốn sách C, tác giả nói rằng scanf()đã để lại một ký tự dòng mới trong bộ đệm, do đó, chương trình không dừng lại ở dòng 4 để người dùng nhập dữ liệu, mà nó lưu trữ ký tự dòng mới trong c2 và chuyển đến dòng 5.

Có đúng không?

Tuy nhiên, điều này chỉ xảy ra với charcác kiểu dữ liệu? Vì tôi không thấy vấn đề này với intcác kiểu dữ liệu như trong dòng 1, 2, 3. Có đúng không?


Đôi khi nó được đề xuất fflush(stdin)có thể được sử dụng trước lệnh gọi tới scanf()một ký tự. Vui lòng đọc Sử dụngfflush(stdin) để thảo luận về ưu và nhược điểm và các lựa chọn thay thế cho phương pháp đó (phương pháp này hoạt động, ít nhiều, trên Windows và không hoạt động ở hầu hết các nơi khác).
Jonathan Leffler

Bạn có thể vui lòng cho chúng tôi biết bạn đang đề cập đến cuốn sách nào không.?
surya kiran

Câu trả lời:


79

Các scanf()skips chức năng hàng đầu trắng tự động trước khi cố gắng để phân tích chuyển đổi khác so với nhân vật. Các định dạng ký tự (chủ yếu %c; cũng là bộ quét %[…]- và %n) là ngoại lệ; họ không bỏ qua khoảng trắng.

Sử dụng " %c"với khoảng trống ở đầu để bỏ qua khoảng trắng tùy chọn. Không sử dụng khoảng trống ở cuối trong một scanf()chuỗi định dạng.

Lưu ý rằng điều này vẫn không sử dụng bất kỳ khoảng trắng cuối nào còn lại trong luồng đầu vào, thậm chí không ở cuối dòng, vì vậy hãy cẩn thận nếu cũng sử dụng getchar()hoặc fgets()trên cùng một luồng đầu vào. Chúng tôi chỉ nhận được scanf để bỏ qua khoảng trắng trước khi chuyển đổi, giống như đối với %dvà các chuyển đổi không phải ký tự khác.


Lưu ý rằng các "chỉ thị" không có khoảng trắng (để sử dụng thuật ngữ POSIX scanf ) ngoài các chuyển đổi, như văn bản chữ trong scanf("order = %d", &order);cũng không bỏ qua khoảng trắng. Chữ orderphải khớp với ký tự tiếp theo được đọc.

Vì vậy, bạn có thể muốn " order = %d"ở đó nếu bạn muốn bỏ qua một dòng mới từ dòng trước đó nhưng vẫn yêu cầu khớp theo nghĩa đen trên một chuỗi cố định, như câu hỏi này .


8
%c, %n, %[]Là 3 kỳ vọng nhất định mà không tiêu thụ khoảng trắng hàng đầu.
chux - Phục hồi Monica

@chux Vì vậy, Có phải trong các trường hợp khác, Scanf xóa tất cả các khoảng trắng trước đó trong bộ đệm hoặc bỏ qua chúng để họ nhập nhưng chúng vẫn ở đó không?
Suraj Jain

@SurajJain Vâng,
Chux - Khôi phục Monica

3
Xem Phần trống ở cuối trong scanf()chuỗi định dạngscanf()yêu cầu nhập hai lần trong khi tôi mong đợi nó chỉ yêu cầu một lần khi thảo luận về khoảng trống ở cuối trong chuỗi định dạng. Chúng là một ý tưởng tồi - cực kỳ tệ nếu bạn mong đợi sự tương tác của con người và không tốt cho sự tương tác của chương trình.
Jonathan Leffler

32

Sử dụng scanf(" %c", &c2);. Điều này sẽ giải quyết vấn đề của bạn.


7

Một tùy chọn khác (mà tôi nhận được từ đây ) là đọc và loại bỏ dòng mới bằng cách sử dụng tùy chọn gán-nén . Để làm điều đó, chúng tôi chỉ cần đặt một định dạng để đọc một ký tự có dấu hoa thị giữa %c:

scanf("%d%*c",&a); // line 1
scanf("%c%*c",&c1); // line 3

scanf sau đó sẽ đọc ký tự tiếp theo (nghĩa là dòng mới) nhưng không gán nó cho bất kỳ con trỏ nào.

Tuy nhiên, cuối cùng, tôi sẽ chấp nhận lựa chọn cuối cùng của Câu hỏi thường gặp :

Hoặc, tùy thuộc vào yêu cầu của bạn, bạn cũng có thể quên scanf () / getchar (), sử dụng fgets () để lấy một dòng văn bản từ người dùng và tự phân tích cú pháp.


2
Vấn đề với kỹ thuật này là nếu người dùng nhập dấu acách rồi đến dòng mới, việc chuyển đổi ký tự bị triệt tiêu sẽ đọc khoảng trắng và vẫn để lại dòng mới. Nếu người dùng nhập supercalifragilisticexpialidociouskhi bạn mong đợi a, bạn có rất nhiều ký tự bổ sung để xử lý. Bạn không bao giờ có thể biết liệu một chuyển đổi bị triệt tiêu theo sau có thành công hay không - chúng không được tính vào lợi nhuận từ scanf().
Jonathan Leffler

4

Sử dụng getchar()trước khi gọi thứ hai scanf().

scanf("%c", &c1);
getchar();  // <== remove newline
scanf("%c", &c2);

1
Điều này hoạt động với điều kiện là người dùng không nhập bất kỳ thứ gì khác - ví dụ: các khoảng trống ở cuối. Nhưng nó không tốt bằng một vòng lặp quét đến dòng mới tiếp theo: int c; while ((c = getchar()) != EOF && c != '\n') ;(được viết trên ba dòng khi không có trong nhận xét). Nó thường là đủ; nó không phải là tuyệt vời (và bạn phải nhớ rằng những kẻ ngu rất thông minh trong việc làm rơi mọi thứ).
Jonathan Leffler
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.