Xài chung scanf với gets không bị làm sao được hả. Coi cái này :
Em có một bài tập demo về cấu trúc. Tạo một cấu trúc về hồ sơ nhân viên, nhập và xuất ra màn hình các thông tin đó.
Đây là bài làm của em:
Chương trình vẫn chạy được nhưng sau khi nhập tuổi của nhân viên xong thì chương trình bỏ qua luôn bước nhập chức vụ. Em không biết lỗi gì mong các anh giúp vớiCode:#include <stdio.h> #include <stdlib.h> struct HoSo { char *hoten; int tuoi; char *chucvu; }; int main() { struct HoSo nv; nv.hoten = (char*)malloc(sizeof(char*)); nv.chucvu = (char*)malloc(sizeof(char*)); printf("Ho ten:"); gets(nv.hoten); printf("Tuoi:"); scanf("%d",&nv.tuoi); printf("Chuc vu:"); gets(nv.chucvu); system("cls"); printf("%s\n",nv.hoten); printf("%d\n",nv.tuoi); printf("%s\n",nv.chucvu); return 0; }
Xài chung scanf với gets không bị làm sao được hả. Coi cái này :
Trùi ui em mới lẹt đẹt C mà bác chơi đến C++ làm sao em hỉu :((
fflush(stdin); thêm cái này sau thằng gets thử xem. Ờ quên trong box C ! Sorry bạn nha T_T.
Oh ! Em sửa được rồi !Nhưng tại sao lại phải thêm fflush(stdin) như vậy nhỉ. Bác giải thích cặn kẽ được không
hề hề, đã nhỉOh ! Em sửa được rồi !. Bác huynguyen có giải thích trong cái link mình đưa đó, cái này thì C hay C++ chắc cũng giống nhau. Đang dở sách ra học C đây hic hic. Do mình cũng không rành C cho lắm. Nhưng mình nghĩ cơ bản là thế, bạn đọc lại kĩ cái link là ok
!
hi hi sướng chứ sao không !Hi hi cái thú của lập trình !
Tríc bài của anh huynguyen để trả lời câu hỏi trên ( trong C++ ) . Ở đây đơn giản lắm , trong sách PVA thì nó giải thích như thế này : khi bạn nhập 1 ký tự từ bàn phím thì ký tự ấy sẽ được chuyển vào 1 trong 2 nơi : bộ đệm bàn phím hoặc tệp stdin . Làm sao biết khi ta nhập 1 ký tự bất kỳ thì nó sẽ gửi vào đâu . Câ trả lời là nếu ta nhập ký tự trong lúc máy dừng chờ trước các hàm scanf , gets , getchar thì máy sẽ gửi ký tự vào tệp stdin . Nếu ko phải 3 hàm ấy thì là vào bộ đệm bàn phím . Tệp stdin có tính chất như sau :Câu hỏi của bạn rơi vào đúng cái điểm dở của cin.get hoặc cin.getline đó là nó lấy phím enter trong bộ đệm.
Để tôi giải thích từng dòng lệnh nhé:
Đặt cin.getline(title,50); là (1)
Đặt cin>> year; là (2)
Giả sử bạn gõ Gone wind(enter) thì sau câu lệnh (1) biến title có giá trị là Gone wind(enter). Tôi ghi chữ (enter) tức là phím enter nhé.
Sau khi bạn gõ 1900(enter) thì sau lệnh (2) biến year có giá trị là 1900 đồng thời trong buffer hay các bạn gọi là bộ đệm sẽ còn lại phím enter.
Sau khi chạy lại câu lệnh yêu cầu nhập title thì đến câu lệnh (1). cin.getline nó thấy trong buffer có phím enter và nó lấy ra luôn. Kết quả là gặp lỗi như bạn thấy.
Để sửa lỗi này thì bạn chỉ cần thêm fflush(stdin); trước câu lệnh cin.getline là xong.
_Nếu trên stdin có dư dữ liệu ( tức là bạn bấm nhiều phím bất kỳ ) thì các hàm trên sẽ nhận được 1 phần dữ liệu mà chúng yêu cầu . Các ký tự còn lại vẫn nằm trên stdin .
_khi stdin chưa đủ dữ liệu thì máy sẽ chờ cho đến khi người dùng nhập đủ dữ liệu vào .
Ở đây cái sai mà bạn gặp phải là do tính chất 1 gây ra . Có thể ví dụ đơn giản như sau :
khi bạn nhập như sau : 55 và bấm ENTER cho hàm scanf thì ký tự 55 sẽ được gán cho biến n . Nhưng ký tự ENTER vẫn còn lưu lại trên stdin và hàm gets sẽ nhận nó vì thế sẽ làm trôi hàm gets đi . Dù bạn rất muốn nhập cái gì đó cho chuỗi s nhưng cũng bó tay .Code:scanf("%d",&n); gets(s);
Thế thì cách giải quyết chính là làm sạch tệp stdin . Và người ta dùng hàm fflush(FILE *filepoint) để làm sạch nó với tham số là tên con trỏ tệp stdin : fflush(stdin);
Ở đây có 1 vấn đề khá hay : nếu bạn đảo lại thứ tự trong code trên thì sẽ ko gặp phải vấn đề trên . Tức là bạn sẽ nhập đủ cho cả 2 hàm . Vì sao vậy ? Đó là do tính chất của hàm gets . Đúng là hàm gets nhận ký tự từ bộ đệm bàn phím và sẽ chờ người dùng nhấn phím ENTER để kết thúc việc nhập cho hàm . Như vậy thì theo đúng thì ký tự ENTER sẽ còn lại trên stdin và hàm scanf ngay phía dưới sẽ bị trôi đi . Nhưng ko , hàm gets sẽ xoá nó đi khỏi stdin đấy . Vì thế hàm scanf sẽ ko bị trôi đi đâu .