30/09/2018, 21:36
Gặp lỗi trong bài tập nhập thông tin sinh viên?
Hi mọi người. Em có làm 1 bài tập như sau: Nhập vào thông tin của nhiều sinh viên ( < 50 ) gồm họ và tên, số tuổi, điểm toán và điểm anh.
Đây là bài làm của em:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <math.h>
#include <Windows.h>
#include <limits.h>
typedef struct diemthi DIEMTHI;
struct diemthi
{
char hoten[50];
int tuoi;
float diemtoan;
float diemanh;
};
void NhapDiem(DIEMTHI &x)
{
printf("
Nhap ho va ten: ");
gets(x.hoten);
printf("Nhap so tuoi: ");
scanf("%d",&x.tuoi);
printf("Nhap diem toan: ");
scanf("%f",&x.diemtoan);
printf("Nhap diem tieng anh: ");
scanf("%f",&x.diemanh);
}
void XuatDiem(DIEMTHI x)
{
printf("
Ho va ten: ");
puts(x.hoten);
printf("So tuoi: %d
",x.tuoi);
printf("So diem toan: %.1f
",x.diemtoan);
printf("So diem tieng anh: %.1f
",x.diemanh);
}
void NhapMang(DIEMTHI a[], int n)
{
for (int i = 0; i < n; i++)
{
printf("
Nhap thong tin sinh vien %d: ",i+1);
NhapDiem(a[i]);
}
}
void XuatMang(DIEMTHI a[], int n)
{
for (int i = 0; i < n; i++)
{
printf("
Thong tin sinh vien %d:
", i+1);
XuatDiem(a[i]);
}
}
int main()
{
int a[50];
int n;
do
{
printf("
Nhap so luong sinh vien: ");
scanf("%d",&n);
if (n < 0 || n > 50)
printf("
So luong sinh vien khong hop le
");
} while (n < 0 || n > 50);
NhapMang(a, n);
XuatMang(a, n);
getch();
return 0;
}
Nhưng khi chạy thì nó bị lỗi như thế này:
Mong các bạn giỏi giúp em nhé! Xin cảm ơn nhiều !
Bài liên quan
mảng a trong hàm
main
của bạn là kiểuint
mà, còna
trong hàmNhapMang
là kiểuDIEMTHI
Trời đất, sao sai cái lỗi “trên trời dưới đất” thế này
Cảm ơn bạn @freedom nhiều nhé
Cơ nhưng còn 1 vấn đề nữa là sao khi mình run lên, nó không cho nhập họ và tên mà nhập thẳng tuổi rồi điểm luôn nhỉ? Như picture dưới đây nè:
Vì sau khi bạn nhập
n
trong hàm main, trongsdtin
vẫn còn ký tự'\n'
nên khi vào hàmNhapDiem
ký tự'\n'
sẽ được hàmgets
nhận vàox.hoten
--> trôi ký tự.–> phải làm sạchstdin
, thêm trướcgets(...)
đoạn này:Bạn có thể nói rõ tác dụng của đoạn code bạn xíu được không ? Giải quyết được vấn đề rồi đấy nhưng chưa hiểu code bạn lắm
Vòng lặp đầu tiên của hàm
NhapMang
là như mình nói lúc nãy. Sau khi kết thúc vòng lặp đầu tiên, trongstdin
sẽ còn 3 ký tự'\n'
ở các lần nhậpx.tuoi
,x.diemtoan
,x.diemanh
nên nếu không có đoạn code trên trongNhapDiem
thì ở các vòng lặp tiếp theo cũng sẽ bị trôi không nhập đượcx.hoten
. Còn về đoạn code đó, nó có ý nghĩa là lấy các ký tự ra khỏistdin
đến khi nào trongstdin
không còn'\n'
và khác EOF, dùng để làm sạchstdin
thôi, tại ANSI-C không có hàm nào làm sạchstdin
cả.Cho hỏi ngu xíu, Không biết có liên quan đến C++ hay không mà mình chưa nghe tới stdin bao giờ
stdin là khái niệm trong C mà bạn, stdin là thiết bị nhập chuẩn (standard input) trong C được định nghĩa trong
<stdio.h>
có file descriptor là 0, được gắn với ngoại vi là bàn phím. C++ thì có dòng nhập chuẩn std::cin, chức năng cũng tương tự như stdin nhưng được định nghĩa trong namespace std, có type là std::istream.Bác cho em hỏi là kí tự ‘\n’ bị thừa ra là do đâu vậy , em có thấy đoạn code nó nhập kí tự này đâu mà hàm gets lại nhận ạ ( bác chụp rõ cái dòng code gây ra lỗi này hộ em với được không ạ )
Khi bạn nhập dữ liệu vào từ bàn phím thì nó được đưa vào
stdin
, sau đó các hàm nhưscanf
,gets
sẽ lấy dữ liệu từstdin
vào chương trình chứ không đọc trực tiếp từ bàn phím. Bạn tưởng tượng như là khi bạn đọc ghi file vậy,stdin
cũng là một file, nhưng là file đặc biệt của hệ thống do hệ điều hành cấp cho ngoại vi là bàn phím. Giả sử bạn nhập vào biếnn
cho chương trình, bạn phải bấm 3—>Enter, thì cả 3 và kí tự Enter('\n'
) đều được đẩy lênstdin
, sau đó hàmscanf
sẽ nhận 3 vàon
còn ký tự'\n'
vẫn còn trênstdin
, sau đó hàmgets
sẽ tiếp tục đọc ký tự này và lưu vàox.hoten
.Nếu thế thì mấy vòng lặp tiếp theo trở đi (
i >= 1
) mới bị lỗi không nhập đượcx.hoten
chứ nhỉ?Còn đằng này là vòng lặp đầu tiên (
i = 0
) thì cũng bị lỗi không nhập đượcx.hoten
?Nếu còn 3 ký tự
'\n'
thì :cả thằng
gets
và 2 thằngscanf
kia vẫn không chạy được chứ nhỉ ?Tức là ý mình là sau khi chạy vòng lặp for đầu tiên (
i = 0
) thì còn dư 3 ký tự'\n'
củax.tuoi
,x.diemtoan
vàx.diemanh
đúng không. Vậy sang vòng lặp for thứ 2 (x = 1
) thì do dư 3 ký tự'\n'
chứ không phải 1 ký tự'\n'
nên cả thằnggets
và 2 thằngscanf
phải bị lỗi luôn chứ, đằng này thì khi chạy chỉ có mỗi thằnggets
bị lỗi ?P/S: Do còn còn “ngu” và khó hiểu quá nên có thể mình “làm phiền” bạn 1 tí, hi vọng bạn giải thích rõ giùm mình nhé
Tại vì ở vòng lặp đầu, sau khi bạn nhập
n
trong hàm main thì trong buffer vẫn còn'\n'
Bạn đã bỏ đoạn code làm sạch buffer trước
gets
rồi nên cho dù có bao nhiêu ký tự'\n'
liên tiếp còn lại trong stdin cũng bị lấy ra ngoài, nêngets
vẫn nhập bình thường. Cònscanf
bạn nhập với định dạng%d
và%f
nên không nhận ký tự'\n'
vào biến. Bạn debug thì thấy rõ mà.Thì ra là thế
Không, ý mình là lúc trước khi chưa bỏ đoạn code ấy, thì sau vòng lặp đầu tiên sẽ dư 3 ký tự
'\n'
, dẫn đến sang vòng lặp thứ 2 thì thằnggets
sẽ hứng 3 ký tự'\n'
đúng không ? Còn 2 thằngscanf
kia do có định dạng%d
và%f
rồi nên nó sẽ không hứng 2 ký tự'\n'
còn lại đúng không ?Không bạn, gets sẽ kết thúc khi gặp phải
'\n'
chuỗix.hoten
sau khi thực hiện gets là một chuỗi rỗng, tức là chuỗi chỉ chứa ký tự kết thúc chuỗi'\0'
còn hàmscanf
thì như bạn nóiMình hiểu rồi, thanks bạn nhiều nhé
Mà bạn ơi. Mình quên mất cái trường hợp này !
Theo mình biết thì cái đoạn code của bạn được gọi là Xóa bộ nhớ đệm đúng không ?
Nếu thế thì để
fflust(stdin)
vẫn được chứ nhỉfflush thực chất vốn ko cho các luồng vào (stdin chẳng hạn).
Nó cho các luồng ra (stdout, file out).
Như output buffer đang chứa các data mà chưa kịp ghi. Dùng fflush sẽ giúp “đẩy” nó ra.
Như ví dụ này
Khoan hãy nhập vội để nó tiếp tục mà mở file bla.txt thì bạn sẽ thấy nó chả có gì ở trong đó.
Nhưng thêm cái fflush(f) ngay trc hàm getchar và mở file thì thấy ngay.
Vậy nên freedom đã cho bạn 1 vòng while nhỏ để clear buffer là vậy đó.
cho em hỏi thêm là khi thêm đoạn code của bác vào thì khi run phải enter 2 lần mới run được tiếp là sao ạ