Làm cách nào để tránh nhấn Enter với getchar () để chỉ đọc một ký tự?


80

Trong mã tiếp theo:

Tôi phải nhấn Enterđể in tất cả các chữ cái tôi đã nhập vào getchar, nhưng tôi không muốn làm điều này, những gì tôi muốn làm là nhấn vào ký tự đó và ngay lập tức thấy ký tự tôi giới thiệu lặp lại mà không cần nhấn Enter. Ví dụ: nếu tôi nhấn vào ký tự 'a', tôi muốn nhìn thấy một ký tự khác 'a' bên cạnh nó, v.v.

Nhưng khi tôi nhấn 'a' thì không có gì xảy ra, tôi có thể viết các chữ cái khác và bản sao chỉ xuất hiện khi tôi nhấn Enter:

Tôi có thể làm cái này như thế nào?

Tôi đang sử dụng lệnh cc -o example example.ctrong Ubuntu để biên dịch.


5
điều này rất phụ thuộc vào cách hệ điều hành và quy trình đầu vào của bạn. nếu bạn chỉ định môi trường hoạt động của mình, bạn có thể sẽ nhận được câu trả lời tốt hơn.
goldPseudo

Câu trả lời được cung cấp tại cplusplus.com/forum/articles/19975 hoạt động trên các cửa sổ sử dụng WinAPI.

Câu trả lời:


72

Trên hệ thống linux, bạn có thể sửa đổi hành vi của thiết bị đầu cuối bằng sttylệnh. Theo mặc định, thiết bị đầu cuối sẽ đệm tất cả thông tin cho đến khi Enterđược nhấn, trước khi gửi đến chương trình C.

Một ví dụ nhanh, bẩn và không đặc biệt di động để thay đổi hành vi từ bên trong chính chương trình:

Xin lưu ý rằng điều này không thực sự tối ưu, vì nó chỉ giả định rằng đó stty cookedlà hành vi bạn muốn khi chương trình thoát, thay vì kiểm tra cài đặt đầu cuối ban đầu là gì. Ngoài ra, vì tất cả các xử lý đặc biệt bị bỏ qua ở chế độ thô, nhiều chuỗi khóa (chẳng hạn như CTRL-C hoặc CTRL-D ) sẽ không thực sự hoạt động như bạn mong đợi nếu không xử lý rõ ràng chúng trong chương trình.

Bạn có thể man sttykiểm soát nhiều hơn hành vi của thiết bị đầu cuối, tùy thuộc chính xác vào những gì bạn muốn đạt được.


Sử dụng systemlà một ý tưởng tồi.
Sapphire_Brick

Quá nhiều dữ liệu thô .... Tôi đang tìm kiếm một giải pháp có thể không đợi ENTER. Giải pháp này hãm tất cả các chức năng của thiết bị đầu cuối đầu vào.
ABC

93

Điều này phụ thuộc vào hệ điều hành của bạn, nếu bạn đang ở trong một môi trường như UNIX, cờ ICANON được bật theo mặc định, vì vậy đầu vào được lưu vào bộ đệm cho đến lần tiếp theo '\n'hoặc EOF. Bằng cách tắt chế độ chuẩn, bạn sẽ nhận được các ký tự ngay lập tức. Điều này cũng có thể thực hiện được trên các nền tảng khác, nhưng không có giải pháp đa nền tảng nào.

CHỈNH SỬA: Tôi thấy bạn đã chỉ định rằng bạn sử dụng Ubuntu. Tôi vừa đăng một cái gì đó tương tự vào ngày hôm qua, nhưng hãy lưu ý rằng điều này sẽ vô hiệu hóa nhiều hành vi mặc định của thiết bị đầu cuối của bạn.

Bạn sẽ nhận thấy rằng mỗi ký tự xuất hiện hai lần. Điều này là do đầu vào ngay lập tức được phản hồi trở lại thiết bị đầu cuối và sau đó chương trình của bạn cũng đặt nó trở lại putchar(). Nếu bạn muốn tách đầu vào khỏi đầu ra, bạn cũng phải lật cờ ECHO. Bạn có thể thực hiện việc này bằng cách chỉ cần thay đổi dòng thích hợp thành:


9
1 Mặc dù tbh, điều này có lẽ không phải là mức mã các poster ban đầu là cảm thấy thoải mái với;)
Andomar

2
Tuyệt quá! Đó là những gì tôi đang tìm kiếm!
Denilson Sá Maia

Cảm ơn sự giúp đỡ cùng với các nhận xét chi tiết, nó đã giải quyết được vấn đề của tôi.
kaminsknator

Thật không thể tin được rằng một thứ rất cơ bản lại khó đạt được và không thể di chuyển được.
Pedro77

12

getchar () là một hàm tiêu chuẩn mà trên nhiều nền tảng yêu cầu bạn nhấn ENTER để nhận đầu vào, vì nền tảng đệm đầu vào cho đến khi phím đó được nhấn. Nhiều trình biên dịch / nền tảng hỗ trợ getch () không chuẩn không quan tâm đến ENTER (bỏ qua bộ đệm nền tảng, coi ENTER giống như một khóa khác).


1
1 Đúng, getchar()bắt đầu đọc ký tự từng cái một chỉ sau khi bạn đã ép nhập
Andomar

32
getchar()không quan tâm đến ENTER, nó chỉ xử lý bất cứ thứ gì đến thông qua stdin. Bộ đệm dòng có xu hướng là hành vi được xác định bởi hệ điều hành / thiết bị đầu cuối.
goldPseudo

1
@goldPseudo: Đúng, nhưng hầu như tất cả các nền tảng đều đệm đầu vào nên đây là hành vi bạn sẽ thấy trong hầu hết các trường hợp thực tế. getch (), nếu được hỗ trợ, sẽ quản lý hoặc bỏ qua bộ đệm. Tôi biết một số triển khai DOS cũ đã bỏ qua bộ đệm hệ điều hành để tương tác trực tiếp với phần cứng. Các triển khai khác có thể tuôn ra stdin để có được hành vi tương tự.
Eric J.

10
Tuy nhiên, không phải getchar()là “yêu cầu bạn nhấn enter”, mà là môi trường.
Benji XVI

1
Rất ngắn gọn và dễ hiểu. Các câu trả lời được xếp hạng cao nhất khác chỉ xoay quanh các chi tiết công nghệ không cần thiết.
mzoz

6

I / O là một chức năng của hệ điều hành. Trong nhiều trường hợp, hệ điều hành sẽ không chuyển ký tự đã nhập vào chương trình cho đến khi nhấn ENTER. Điều này cho phép người dùng sửa đổi đầu vào (chẳng hạn như khoảng cách lùi và nhập lại) trước khi gửi đến chương trình. Đối với hầu hết các mục đích, điều này hoạt động tốt, cung cấp giao diện nhất quán cho người dùng và giúp chương trình không phải đối phó với điều này. Trong một số trường hợp, chương trình mong muốn nhận được các ký tự từ các phím khi chúng được nhấn.

Thư viện C tự xử lý các tệp và không quan tâm đến cách dữ liệu vào tệp đầu vào. Do đó, không có cách nào trong chính ngôn ngữ để lấy các phím khi chúng được nhấn; thay vào đó, đây là nền tảng cụ thể. Vì bạn chưa chỉ định hệ điều hành hoặc trình biên dịch, chúng tôi không thể tra cứu nó cho bạn.

Ngoài ra, đầu ra tiêu chuẩn thường được đệm để tăng hiệu quả. Điều này được thực hiện bởi các thư viện C, và do đó, có một giải pháp C, đó là fflush(stdout);sau mỗi ký tự được viết. Sau đó, việc các ký tự có được hiển thị ngay lập tức hay không là tùy thuộc vào hệ điều hành, nhưng tất cả các hệ điều hành mà tôi quen thuộc sẽ hiển thị đầu ra ngay lập tức, vì vậy đó thường không phải là vấn đề.


6

Tôi thích câu trả lời của Lucas, nhưng tôi muốn nói rõ hơn một chút. Có một chức năng tích hợp termios.hđược đặt tên cfmakeraw()người đàn ông mô tả là:

Về cơ bản, điều này tương tự như những gì Lucas đề xuất và hơn thế nữa, bạn có thể thấy các cờ chính xác mà nó đặt trong các trang người đàn ông: termios (3) .

Ca sử dụng


Lưu ý rằng đây cfmakeraw()là tiện ích mở rộng không di động, không phải chuẩn cho POSIXtermios.h và không nhất thiết phải có sẵn.
Andrew Henle

4

Vì bạn đang làm việc trên một dẫn xuất Unix (Ubuntu), đây là một cách để làm điều đó - không được khuyến nghị, nhưng nó sẽ hoạt động (miễn là bạn có thể nhập lệnh chính xác):

Sử dụng ngắt để dừng chương trình khi bạn cảm thấy nhàm chán với nó.

  • Dòng 'echo' lưu cài đặt đầu cuối hiện tại dưới dạng tập lệnh shell sẽ khôi phục chúng.
  • Dòng 'stty' tắt hầu hết các xử lý đặc biệt (chẳng hạn như Control-Dkhông có tác dụng) và gửi các ký tự đến chương trình ngay khi chúng có sẵn. Nó có nghĩa là bạn không thể chỉnh sửa cách nhập của mình nữa.
  • Dòng 'sh' khôi phục cài đặt đầu cuối ban đầu của bạn.

Bạn có thể tiết kiệm nếu 'stty sane' khôi phục cài đặt của bạn đủ chính xác cho mục đích của bạn. Định dạng '-g' không thể di động trên các phiên bản của 'stty' (vì vậy những gì được tạo trên Solaris 10 sẽ không hoạt động trên Linux hoặc ngược lại), nhưng khái niệm này hoạt động ở mọi nơi. Tùy chọn 'stty sane' không có sẵn trên toàn cầu, AFAIK (nhưng trên Linux).


2

Bạn có thể bao gồm thư viện 'ncurses' và sử dụng getch()thay thế getchar().


1

vâng, bạn cũng có thể làm điều này trên windows, đây là đoạn mã bên dưới, sử dụng thư viện conio.h


6
Câu hỏi đặt ra là gắn thẻ với c , không c ++
Spikatrix

@CoolGuy Vậy thì sao? Tại sao nó sẽ giúp mọi người nếu ai đó mở cùng một câu hỏi, nhưng lại thay đổi thẻ từ c thành c ++?
Andreas Haferburg

@AndreasHaferburg Bởi vì chúng tôi sẽ không có câu trả lời C ++ ở đây, đặc biệt là những câu được viết kém, nháy mắt .
Sapphire_Brick

1

Tôi đã gặp sự cố này / câu hỏi được đưa ra trong một bài tập mà tôi hiện đang làm. Nó cũng phụ thuộc vào đầu vào bạn đang lấy từ đâu. tôi đang dùng

để nhận đầu vào trong khi chương trình đang chạy, vì vậy đó cần phải là luồng lọc được liên kết với lệnh.

Trên máy ubuntu, tôi phải kiểm tra / target, nó yêu cầu nhiều hơn

hoặc là

Tôi đã phải thêm cờ --file, cũng như đường dẫn đến lệnh, như sau:

Mọi thứ bây giờ là giao hợp.


2
xin lưu ý rằng giải pháp này phụ thuộc vào hệ điều hành.
Ottavio Campana,

0

Mã này đã làm việc cho tôi. Chú ý: đây không phải là một phần của thư viện chuẩn, ngay cả khi hầu hết các trình biên dịch (tôi sử dụng GCC) đều hỗ trợ nó.

Mã này phát hiện lần nhấn phím đầu tiên.


0

" Làm thế nào để tránh bức xúc Entervới getchar()? "

Trước hết, đầu vào thiết bị đầu cuối thường là dòng hoặc được đệm hoàn toàn. Điều này có nghĩa là hệ thống hoạt động lưu trữ đầu vào thực tế từ thiết bị đầu cuối vào một bộ đệm. Thông thường, bộ đệm này được đưa vào chương trình khi fe \nđược báo hiệu / cung cấp stdin. Điều này được thực hiện bởi một báo chí Enter.

getchar()chỉ là ở cuối chuỗi. Nó không có khả năng thực sự ảnh hưởng đến quá trình đệm.


" Làm thế nào tôi có thể làm điều này? "

Bỏ quagetchar() ngay từ đầu, nếu bạn không muốn sử dụng các lệnh gọi hệ thống cụ thể để thay đổi hành vi của thiết bị đầu cuối một cách rõ ràng như đã giải thích rõ trong các câu trả lời khác.

Rất tiếc là không có chức năng thư viện tiêu chuẩn và không có cách di động nào để xóa bộ đệm khi nhập ký tự đơn. Tuy nhiên, có những giải pháp dựa trên thực thi và không thể di động.


Trong Windows / MS-DOS, có các chức năng getch()getche()hàm trong conio.htệp tiêu đề, thực hiện chính xác những gì bạn muốn - đọc một ký tự đơn lẻ mà không cần đợi dòng mới xóa bộ đệm.

Sự khác biệt chính giữa getch()getche()getch()không xuất ngay ký tự đầu vào thực tế trong bảng điều khiển, trong khi getche()đó. Phần bổ sung "e"là viết tắt của tiếng vang .

Thí dụ:


Trong Linux, một cách để có được chế biến nhân vật trực tiếp và đầu ra là sử dụng cbreak()echo()tùy chọn và getch()refresh()thói quen trong ncurses-thư viện.

Lưu ý rằng bạn cần khởi tạo cái gọi là màn hình tiêu chuẩn với initscr()và đóng cùng một endwin()quy trình.

Thí dụ:


Lưu ý: Bạn cần gọi trình biên dịch với -lncursestùy chọn để trình liên kết có thể tìm kiếm và tìm thấy thư viện ncurses.


-1

Theo mặc định, thư viện C đệm đầu ra cho đến khi nó thấy kết quả trả về. Để in kết quả ngay lập tức, hãy sử dụng fflush:


2
Tuy nhiên, sản lượng là một phần của vấn đề. Người hỏi muốn có các phím đọc chương trình khi chúng được nhấn và in ngay lập tức trên màn hình. Đó là cả vấn đề đầu vào và đầu ra.
David Thornley

tức là fflush chỉ tuôn ra đầu ra, nhưng getchar sẽ vẫn không trở lại sau khi nhấn phím (các phím sẽ được đệm).
NickSoft 19/12/12
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.