2010-10-19 65 views
5

Tôi đang cố viết một chương trình đơn giản yêu cầu người dùng chọn từ một menu trong vòng lặp. Tôi sử dụng getchar() để lấy dữ liệu đầu vào, tuy nhiên tôi nhận thấy rằng khi tôi nhập char và nhấn 'Enter', chương trình sẽ tạo hai vòng lặp (như nếu tôi nhấn hai lần) một char làm đầu vào và một ký tự khác cho 'Enter 'làm đầu vào.Sử dụng hàm getchar() trên c nhận 'Nhập' sau khi nhập

Làm cách nào để khắc phục sự cố này?

Thanx.

Trả lời

0

Làm thế nào về

#include <stdio.h> 

/*! getline() reads one line from standard input and copies it to line array 
* (but no more than max chars). 
* It does not place the terminating \n in line array. 
* Returns line length, or 0 for empty line, or EOF for end-of-file. 
*/ 
int getline(char line[], int max) 
{ 
    int nch = 0; 
    int c; 
    max = max - 1;   /* leave room for '\0' */ 

    while ((c = getchar()) != EOF) { 
    if (c == '\n') 
     break; 

    if (nch < max) { 
     line[nch] = c; 
     nch = nch + 1; 
    } 
    } 

    if (c == EOF && nch == 0) 
    return EOF; 

    line[nch] = '\0'; 
    return nch; 
} 

Source

+0

Tôi không được sử dụng chuỗi hoặc mảng char (công việc của khóa học) – SnapDragon

3

Bạn cần phải đọc về kinh điển vs đầu vào không kinh điển. Các địa chỉ sau Stack Overflow câu hỏi này:

canonical-vs-non-canonical-terminal-input

+0

+1 - Bạn có thể đặt thiết bị đầu cuối thành chế độ thô (không chuẩn) bằng cách sử dụng [tcsetattr()] (http: // www. opengroup.org/onlinepubs/000095399/functions/tcsetattr.html) để thao tác cấu trúc ** termios **. – jschmier

2

Thêm một getchar() sau getchar(): P

+0

Tôi đoán Nó sẽ làm việc, nhưng gây mê yên tĩnh của nó. – SnapDragon

+0

Điều đó sẽ tạo ra các vấn đề trong một số trường hợp mà người dùng sẽ thấy mình phải bấm trở lại hai lần. – Kaitain

2

Cách đơn giản nhất là để lọc ra vào phím như giá trị trả về từ getchar

char c = (char)getchar(); 
if (c != '\n') { 
    ... 
} 
+0

Tôi đoán bạn có nghĩa là getchar()? nếu như vậy getchar() trả về int. – Nyan

+0

@Nyan, 'getchar' thực sự trả về' int' nhưng nó hợp pháp để gán cho 'char' thông qua chuyển đổi. Tham khảo http://www.cplusplus.com/reference/clibrary/cstdio/getchar/ – JaredPar

+1

@Jared: có, nhưng char được giới hạn ở (tipically) 256 giá trị, và bạn cần (tipically) 257 giá trị để xác định ** ALL * * ký tự ** VÀ ** EOF. Đó là lý do tại sao 'getchar()' trả về một int – pmg

2

getchar() trả về ký tự đầu tiên trong bộ đệm đầu vào và loại bỏ nó khỏi bộ đệm đầu vào. Nhưng các ký tự khác vẫn nằm trong bộ đệm đầu vào (\n trong ví dụ của bạn). Bạn cần xóa bộ đệm đầu vào trước khi gọi lại getchar() lần nữa:

void clearInputBuffer() // works only if the input buffer is not empty 
{ 
    do 
    { 
     c = getchar(); 
    } while (c != '\n' && c != EOF); 
} 
1

Bạn đã trả lời câu hỏi của chính mình; bạn phải đối phó với nhân vật mới bằng cách nào đó.

Có một số tùy chọn. Nếu tùy chọn trình đơn của bạn được số, bạn có thể sử dụng scanf() để đọc trong một giá trị số nguyên và chuyển đổi dựa trên rằng:

printf("Pick an option: "); 
fflush(stdout); 
scanf("%d", &option); 
switch(option) 
{ 
    case 0 : do_something(); break; 
    case 1 : do_something_else(); break; 
    ... 
    default: bad_option(); break; 
} 

Ưu điểm của tùy chọn này là sự xác định %d chuyển đổi bỏ qua đối với bất kỳ khoảng trắng hàng đầu, bao gồm các ký tự dòng mới, do đó bạn không phải lo lắng về việc chưa đọc bất kỳ dòng chưa đọc nào (trên thực tế, hầu hết các trình chuyển đổi bỏ qua khoảng trắng đầu tiên; %c không làm cho nó hoạt động rất giống như getchar()).

Điểm bất lợi của tùy chọn này là nếu ai đó đánh dấu ngón tay vào một ký tự không phải chữ số trong đầu vào, nó sẽ không được đọc với thông số chuyển đổi %d và sẽ bị kẹt trong luồng đầu vào cho đến khi gọi đến getchar() hoặc scanf() với số %s hoặc %c quy tắc chuyển đổi.

Tùy chọn tốt hơn là đọc tất cả đầu vào dưới dạng ký tự chuỗi sử dụng fgets(), sau đó phân tích cú pháp và xác thực khi cần thiết.

/** 
* Prints a prompt to stdout and reads an input response, writing 
* the input value to option. 
* 
* @param prompt [in] - prompt written to stdout 
* @param option [out] - option entered by user 
* 
* @return - 1 on success, 0 on failure. If return value is 0, then option 
* is not changed. 
*/ 
int getOption(const char *prompt, char *option) 
{ 
    char input[3]; // option char + newline + 0 terminator 
    int result = 0; 

    printf("%s: ", prompt); 
    fflush(stdout); 

    if (fgets(input, sizeof input, stdin)) 
    { 
    /** 
    * Search for a newline character in the input buffer; if it's not 
    * present, then the user entered more characters than the input buffer 
    * can store. Reject the input, and continue to read from stdin until 
    * we see a newline character; that way we don't leave junk in the 
    * input stream to mess up a future read. 
    */ 
    char *newline = strchr(input, '\n'); 
    if (!newline) 
    { 
     printf("Input string is too long and will be rejected\n"); 
     /** 
     * Continue reading from stdin until we find the newline 
     * character 
     */ 
     while (!newline && fgets(input, sizeof input, stdin)) 
     newline = strchr(input, '\n'); 
    } 
    else 
    { 
     *option = input[0]; 
     result = 1; 
    } 
    } 
    else 
    printf("Received error or EOF on read\n"); 

    return result; 
} 

Có, đó là rất nhiều công việc để đọc trong một tùy chọn menu ngu ngốc và đó là phiên bản đơn giản. Chào mừng bạn đến với thế giới tuyệt vời của quá trình xử lý đầu vào tương tác trong C.

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