Hỏi về giá trị của hàm getchar() trong C

Em có đoạn code như này:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int houseNumber;
    printf("Your house's number is: ");
    scanf("%d", &houseNumber);

    char fullName[20] ;
    char c;
    int i = 0;
    printf("Your name is: ");

    do {
        c = getchar();
        fullName[i] = c;
        i++;
    } while (c != '\n');

    fullName[i] = 0;
    printf("%s, Sure?", fullName);
}

Nhưng sau khi chạy thì đến đoạn scanf đầu tiên xong ấn Enter thì nó chạy xong ct luôn, e mày mò 1 lúc thì thử thêm:

c = getchar();
c = 0;

như thế này:

#include <stdio.h>
#include <stdlib.h>  
int main()
{
    int houseNumber;
    printf("Your house's number is: ");
    scanf("%d", &houseNumber);

    char fullName[20] ;
    char c;

    c = getchar();
    c = 0;

    int i = 0;
    printf("Your name is: ");

    do {
        c = getchar();
        fullName[i] = c;
        i++;
    } while (c != '\n');

    fullName[i] = 0;
    printf("%s, Sure?", fullName);
}

thì nó chạy ok, vậy em suy ra là hàm getchar() nó sẽ lấy default value là ký tự gần nhất ta nhập từ bàn phím vào đúng ko ạ, em cũng search rồi nhưng đọc tiếng anh ko hiểu lắm nên hỏi lại cho chắc ăn.

Nếu đúng thì có cách nào để ko cần viết 2 dòng đó mà vẫn được ko?
Vì lặp lại 2 lần c = getchar() em thấy ngứa mắt lắm.

Returns the next character from the standard input (stdin).
http://www.cplusplus.com/reference/cstdio/getchar/?kw=getchar

chính xác hơn là lấy từ stdin. Bạn có thể dùng fflush(stdin); để xóa đi bộ đệm bàn phím.

3 Likes

Thank anh! em thử ngon rồi.

fflush là dành cho output stream. Xài trên input stream (ở đây là stdin) có thể có kết quả ko xác định.
http://c-faq.com/stdio/stdinflush.html

while((c = getchar()) != '\n' && c != EOF);

vậy cũng 1 dòng mà bảo đảm
http://c-faq.com/stdio/stdinflush2.html

3 Likes

ok, thank bạn. :smile:

In some implementations, flushing a stream open for reading causes its input buffer to be cleared (but this is not portable expected behavior).

lý do vì sao nhỉ?

ta nghĩ là vì đại khái nó ko có lý lắm. Vì output ra file chậm nên thường phải chờ ghi 1 lượng lớn thì nó mới bắt đầu thực hiện, ví dụ chờ ghi đủ 4KB thì mới bắt đầu ghi vào đĩa cứng. Trong khi mấy log file thì cần xong dòng nào ghi dòng đó vào đĩa liền, chứ chờ đủ 4KB thì ví dụ mới 2KB thì cúp điện, log file mất ~20 dòng, trong khi đáng lẽ ko mất dòng nào nếu sau mỗi dòng thì flush output file 1 cái. Vậy nên fflush có nghĩa cho output stream.

còn với input stream thì chả lẽ mở file lên flush 1 cái hết nội dung file, vậy flush file làm gì, chỉ cần đóng file hay fseek tới end file là xong rồi… Nếu chỉ áp dụng “độc quyền” cho stdin, hay đúng hơn là “độc quyền” cho ignore 1 dòng của stdin thì nên viết code thực hiện đúng chức năng đó. Vd 1 người copy 2 đoạn văn bản rồi paste vào command line, như vậy ở giữa 2 đoạn văn bản có 1 dấu ‘\n’, đáng lẽ phải đọc được 2 đoạn thì nay chỉ đọc được 1 đoạn, đoạn thứ 2 bị flush bay mất thay vì chỉ cần ignore tới ‘\n’ ở giữa là được rồi.

3 Likes

vậy thì tùy yêu cầu nhập mà mình sử dụng các cách khác nhau thôi, tks

Bác cho hỏi đoạn code đầu tiên kia tại sao chạy xong scanf đầu tiên xong ấn Enter thì nó chạy xong ct luôn nhỉ?

Do khi bạn nhập bằng hàm scanf() thì giá trị nhập vào (bạn gõ phím gì nó đều lưu vào đây), tức lưu ký tự ‘\n’ trong stdin.

  1. Giả sử bạn nhập bằng scanf(): nhập vào số 6 gõ enter, tức là stdin = “6\n”.
  2. Hàm scanf() có nhiệm vụ lấy ra một thằng có giá trị int trong stdin. và hàm scanf() lấy đủ thứ nó cần nên trả về là ok đã xong nhiệm vụ, còn gì trong stdin thì bố mặc xác, còn ‘\n’.
  3. Tới khi bạn sử dụng hàm getchar(), hàm cũng sử dụng lại stdin và nó vô tình thấy thằng ‘\n’ trong stdin nên lôi vào sài luôn. c = getchar() bây giờ c = ‘\n’;
  4. Xong phim nó trả về ký tự nó gặp, khổ nỗi giá trị c khi kiểm tra ở while (c != '\n'); lại là ‘\n’, và thế là kết thúc cuộc tình.
  5. Còn khi bạn sửa giống chủ thớt thì c = getchar(); => c = ‘\n’, xong được gán lại c = 0; nên giờ nó không thỏa điiều kiện while => Chạy đúng yêu cầu. => stdin bây giờ được lấy ra hết nên trống. cả bước 5 sẽ giống với việc áp dụng fflush(stdin) trong VD này.
5 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?