File DIEMTHI.BIN ch ứa thông tin điểm thi với các trường dữ liệu: - Mã học phần mahp - Mã số sinh viên mssv - ểm học phần diemĐiYêu cầu về dữ liệu: - Không có 2 bản ghi nào trong SV.BIN
Trang 2Trang 2
Trang 3Trang 3
Mục l c ụ
1 Trình bày bài toán 4
2 Thiết kế chương trình theo phương pháp tinh chỉnh từng bước 5
3 Mã nguồn: 22
4 Kết quả ra của chương trình 58
Kết quả file output: 58
Kết quả màn hình: 65 5 Kết luận, đánh giá những kết quả đạt được, những ưu điểm và những thiếu sót 74
Trang 4Trang 4
1 Trình bày bài toán
Bài toán: Quản lý thông tin sinh viên và điểm học phần
Mô tả bài toán:
Trường Đại học XYZ muốn quản lý thông tin của sinh viên và điể học phần trong các file nhị phân m Hệ ống cần hỗ ợ các thao tác bổ sung, xóa, và sửa chữa dữ ệu trong 3 file th tr li SV.BIN HP.BIN, , và
DIEMTHI.BIN và đồng thời đảm bảo các yêu cầu sau: 1 File SV.BIN ứa thông tin về sinh viên với các trường dữ ch liệu: - Mã số sinh viên (mssv)
- Họ đệm và Tên sinh viên - ới tínhGi
- Ngày sinh
2 File HP.BIN ứa thông tin về các học phần với các trường dữ ch liệu: - Mã học phần (mahp)
- Tên môn học - Số tín chỉ
3 File DIEMTHI.BIN ch ứa thông tin điểm thi với các trường dữ liệu: - Mã học phần (mahp)
- Mã số sinh viên (mssv) - ểm học phần (diem)Đi
Yêu cầu về dữ liệu:
- Không có 2 bản ghi nào trong SV.BIN giống nhau trên Mã số sinh viên - Không có 2 bản ghi nào trong HP.BIN giống nhau trên Mã học phần
- Không có 2 bản ghi nào trong DIEMTHI.BIN đồng thời giống nhau trên Mã học phần và Mã số
sinh viên
Các chức năng cần hỗ trợ:
- Bổ sung thông tin sinh viên vào file SV.BIN - Bổ sung thông tin học phần vào file HP.BIN - Bổ sung thông tin điểm thi vào file DIEMTHI.BIN - Xóa thông tin sinh viên khỏi file SV.BIN - Xóa thông tin học phần khỏi file HP.BIN - Xóa thông tin điểm thi khỏi file DIEMTHI.BIN - Sửa thông tin sinh viên trong file SV.BIN - Sửa thông tin học phần trong file HP.BIN
Trang 5- Khi bổ sung thông tin điểm thi vào DIEMTHI.BIN, mọi Mã sinh viên trong file DIEMTHI phải là
một Mã sinh viên trong file SV.BIN
- Ngày sinh được nhập vào theo đúng định dạng ngày tháng
- Điểm học phần là một số ực gồm 1 chữ số sau dấu phẩy, thuộc khoảng [0 10] và lẻ đến 0.5 (thang thđiểm 10)
- Ghi vào tệp văn bản để thể hiện quá trình thực hiện chương trình và các kết quả ra
2 Thiết kế chương trình theo phương pháp tinh chỉnh từng bước
Bước 0:
Trang 6Trang 6
Trang 7(dd/mm/yyyy) - struct HocPhan :
mahp: Mã học phần, kiểu char array (c-string) có độ dài tối đa là 10 ký tự ten_mon_hoc: Tên môn học, kiểu char array (c-string) có độ dài tối đa là 50 ký tự so_tc: Số tín chỉ của học phần, kiểu int
if (strlen(ngay_sinh) != 10), yêu cầu nhập lại, return false
ểm tra tính hợp lệ của ngày tháng năm nếu sai yêu cầu nhập lại, Ki : return false else return true
- Kiểm tra xem điểm thi nằm từ 0 đến 10 và lẻ đến 0.5 hay không: bool kiemTraDiem(float diem)
+ Đầu vào: diem là số ực (float)th
+ Đầu ra: true nếu đúng và false nếu ngược lại bool kiemTraDiem(float diem) {
if(diem >= 0.0 && diem <= 10.0 && static_cast<int>(diem * 10) % 5 == 0) { return true;
} return false;
Trang 8Trang 8
Bước 3: Nhập thông tin sinh viên, học phần, điểm thi Nhập thông tin sinh viên
SinhVien NhapSV() Đầu vào:
Đầu ra: biến sv lưu thông tin sinh viên
• Khai báo và định nghĩa hàm “NhapSV()” để nhập thông tin của một sinh viên • Tạo biến “SinhVien sv” để lưu thông tin sinh viên
• Yêu cầu người dùng nhập các yêu cầu: mssv, hodem, ten_sv, gioi_tinh
• Sử dụng một vòng lặp “do-while” để yêu cầu nhập ngày sinh (sv.ngay_sinh) trong đúng định dạng dd/mm/yyyy và kiểm tra tính hợp lệ của ngày sinh bằng hàm KiemTraNgaySinh() bool hopLe = false ;
do {
cout << "Nhap ngay sinh (theo dang dd/mm/yyyy): "; cin.getline(sv.ngay_sinh, 11);
hopLe = KiemTraNgaySinh(sv.ngay_sinh); } while (!hopLe) ;
• Sau khi nhập sinh viên hợp lệ, trả về thông tin Sinh viên (SinhVien sv) vừa nhập
ập thông tin học phầnNh
HocPhan nhap_hp() Đầu vào:
Đầu ra: biến hp lưu thông tin học phần
• Khai báo và định nghĩa hàm “nhap_hp()” để nhập thông tin của một học phần • Tạo một biến “HocPhan hp” để lưu thông tin học phần
• Nhập: mahp, ten_mon_hoc, so_tc
• Trả về thông tin học phần (HocPhan hp) vừa nhập
Nhập thông tin điểm thi
DiemThi nhap_diem_thi() Đầu vào:
Đầu ra: biến dt lưu thông tin điểm thi
• Khai báo và định nghĩa hàm “nhap_diem_thi” để nhập thông tin về điểm thi • Tạo 1 biến “DiemThi dt” để lưu thông tin điểm thi
• Nhập: mahp, mssv, diem
Trang 9• Sau khi nhập điểm hợp lệ, trả về thông tin điểm thi (DiemThi dt) vừa nhập
Bước 4: ghi và đọc file SV.BIN, HOCPHAN.BIN, DIEMTHI.BIN Hàm ghi file (SV.BIN, HP.BIN, DIEMTHI.BIN)
Đầu vào: const SinhVien& sv, const HocPhan & hp, const DiemThi& dt Đầu ra:
• Mở file để ghi dữ ệu bằng cách sử dụng ofstream với chế độ ios::binary | ios::app.li• Sử dụng hàm write để ghi dữ ệu của đối tượng sinh viên sv vào file dưới dạng nhị phân, vớli i
kích thước là sizeof(….) if (binFile.is_open()) {
binFile.write(reinterpret_cast<const char*>(& ),sizeof( )); binFile.close();
cout << "Ghi sinh vien vao file BIN thanh cong" << endl; } else {
cout << "Khong the mo file SV.BIN" << endl; }
• Đóng file sau khi ghi xong thông tin
Hàm đọc file: (SV.BIN, HP.BIN, DIEMTHI.BIN)
• Mở file để đọc dữ ệu bằng cách sử dụng ifstream với chế độ ios::binary.li
• Sử dụng vòng lặp while kết hợp vớ hàm read để đọc dữ ệu từ file vào biến sv với kích i lithước là sizeof(SinhVien)
while (binFile.read(reinterpret_cast<char*>(& ), sizeof( ))) • Hiển thị thông tin vừa đọc được của sinh viên lên màn hình • Lặp lại quá trình cho đến khi đọc hết dữ ệu trong file.li• Đóng file sau khi đọc xong thông tin
Bước 5: Hàm kiểm tra trùng lặ mssv, mahpp Kiểm tra trùng lặp trong file SV.BIN
bool checkDuplicateMSSV Đầu vào: con trỏ ỏ mssvtr
Đầu ra: false không trùng mssv, true nếu ngược lại
Trang 10Trang 10
• Mở tập tin SV.BIN để đọc thông tin về sinh viên
• Đọc dữ ệu từ tập tin li SV.BIN bằng vòng lặp while:
+ Đọc một bản ghi từ tập tin SV.BIN vào biến sv kiểu SinhVien
+ So sánh mã số sinh viên (sv.mssv) với mã số sinh viên (mssv) được truyền vào Nếu trùng
khớp, đóng tập tin và trả về true
• Đóng tập tin SV.BIN
• Nếu không tìm thấy mã số sinh viên trùng khớp, trả về false
+ Hàm kiểm tra trùng lặp Mã học phần trong file HP.BIN
bool checkDuplicateMaHP Đầu vào: con trỏ ỏ mahptr
Đầu ra: false nếu không trùng mahp, true nếu ngược lại
• Mở tập tin HP.BIN để đọc thông tin về học phần
• Đọc dữ ệu từ tập tin li HP.BIN bằng vòng lặp while:
+ Đọc một bản ghi từ tập tin HP.BIN vào biến hp kiểu HocPhan
+ So sánh mã học phần (hp.mahp) với mã học phần (mahp) được truyền vào Nếu trùng khớp,
đóng tập tin và trả về true
• Đóng tập tin HP.BIN
• Nếu không tìm thấy mã học phần trùng khớp, trả về false
Hàm kiểm tra trùng lặp Mã học phần và Mã số sinh viên trong file DIEMTHI.BIN
bool checkDuplicateDiem Đầu vào: con trỏ ỏ mahp, mssvtr
Đầu ra: false nếu không trùng, true nếu ngược lại
• Mở tập tin DIEMTHI.BIN để đọc thông tin về điểm thi của sinh viên.
• Đọc dữ liệu từ tập tin DIEMTHI.BIN bằng vòng lặp while:
+ Đọc một bản ghi từ tập tin DIEMTHI.BIN vào biến dt kiểu DiemThi
+ So sánh mã học phần (dt.mahp) với mã học phần (mahp) và mã số sinh viên (dt.mssv) với mã số sinh viên (mssv) được truyền vào Nếu cả hai điều kiện đều trùng khớp, đóng tập tin và trả về true
• Đóng tập tin DIEMTHI.BIN
• Nếu không tìm thấy thông tin điểm trùng khớp, trả về false
Bước 5: Bổ sung dữ liệu
Trang 11Trang 11
Bổ sung file SV.BIN
void bosungSV() Đầu vào:
Đầu ra: Thông tin sinh viên
• Kiểm tra xem mssv đã tồn tại trong file SV.BIN hay chưa bằng cách gọi hàm checkDuplicateMSSV(sv.mssv)
Đầu ra: Thông tin sinh viên
• Kiểm tra xem mahp đã tồn tại trong file HP.BIN hay chưa bằng cách gọi hàm checkDuplicateMAHP hp mahp( )
Đầu ra: Thông tin điểm
• Kiểm tra xem mssv và mahp đã tồn tại trong file DIEM.BIN hay chưa bằng cách gọi hàm checkDuplicateMSSV(sv.mssv) vàcheckDuplicateMAHP hp mahp)(
• Nếu mssv và mahp đã tồn tại, kết thúc hàm
• Nếu mã số sinh viên không tồn tại, ghi thông tin của sinh viên vào file SV.BIN bằng cách gọi hàm ghiDiemThi (dt)
Bước 6: Xóa dữ liệu Xóa dữ ệu trong file SV.BINli
void xoaSinhVien Đầu vào: mssv
Đầu ra: dữ ệu đã được xóali
• Mở file nhị phân SV.BIN: ifstream inFile("SV.BIN", ios::binary);
Trang 12Trang 12
• Mở file temp.BIN để tạo một file tạm để sao chép thông tin sinh viên không bị xóa: ofstream tempFile("temp.BIN", ios::binary);
• Lặp qua từng bản ghi trong file SV.BIN bằng cách sử dụng vòng lặp while
▪ Trong mỗi lần lặp, đọc một bản ghi từ file SV.BIN và kiểm tra mã số sinh viên của bản ghi đó
▪ Nếu mã số sinh viên không trùng khớp với mã số sinh viên cần xóa, sao chép bản ghi đó vào file tạm temp.BIN bằng cách sử dụng tempFile.write()
while (inFile.read(reinterpret_cast<char*>(&sv), sizeof(SinhVien))) { if (strcmp(sv.mssv, mssv) != 0) {
tempFile.write(reinterpret_cast<constchar*>(&sv),sizeof(SinhVien)); }
Đầu ra: dữ ệu đã được xóali
• Mở file nhị phân HP.BIN: ifstream inFile("HP.BIN", ios::binary);
• Mở file temp.BIN để tạo một file tạm để sao chép thông tin sinh viên không bị xóa: ofstream tempFile("temp.BIN", ios::binary);
• Lặp qua từng bản ghi trong file HP.BIN bằng cách sử dụng vòng lặp while
▪ Trong mỗi lần lặp, đọc một bản ghi từ file HP.BIN và kiểm tra mã học phầ của bản ghi đó.n ▪ Nếu mã học phần không trùng khớp vớ mã học phần cần xóa, sao chép bản ghi đó vào file i
tạm temp.BIN bằng cách sử dụng tempFile.write() while (inFile.read(reinterpret_cast<char*>(&hp), sizeof(HocPhan))) { if (strcmp(sv.mahp, hp) != 0) {
tempFile.write(reinterpret_cast<constchar*>(&hp),sizeof(HocPhan)); }
}
• Sau khi lặp qua toàn bộ file HP.BIN, đóng cả hai file inFile và tempFile • Đổi tên file temp.BIN thành HP.BIN bằng cách sử dụng:
rename("temp.BIN", "HP.BIN")}
Trang 13Trang 13
Xóa điểm thi
void xoaDiemThi Đầu vào: mahp, mssv Đầu ra: dữ ệu đã được xóali
• Mở file nhị phân DIEMTHI.BIN:
ifstream inFile("DIEMTHI.BIN", ios::binary);
• Mở file temp.BIN để tạo một file tạm để sao chép thông tin sinh viên không bị xóa: ofstream tempFile("temp.BIN", ios::binary);
• Lặp qua từng bản ghi trong file DIEMTHI.BIN bằng cách sử dụng vòng lặp while
▪ Trong mỗi lần lặp, đọc mộ bản ghi từ file DIEMTHI.BIN và kiểm tra mã học phần của bản t ghi đó
▪ Nếu mã học phần không trùng khớp vớ mã học phần cần xóa, sao chép bản ghi đó vào file i tạm temp.BIN bằng cách sử dụng tempFile.write()
while (inFile.read(reinterpret_cast<char*>(& ), sizeof(DiemThi))) {dt if (strcmp(dt.mahp, mahp) != 0 || strcmp(dt.mssv, mssv) != 0) {
tempFile.write(reinterpret_cast<constchar*>(&hp),sizeof(HocPhan)); }
Đầu ra: Dữ ệu đã đượli c sửa
• Mở file SV.BIN trong chế độ đọc và ghi nhị phân: fstream (ios::binary|ios::in | ios::out)
• Lặp qua từng bản ghi trong file SV.BIN bằng cách sử dụng vòng lặp while while (file.read(reinterpret_cast<char*>(&sv), sizeof(SinhVien))) {
if (strcmp(sv.mssv ,mssv) == 0) { SinhVien sv ;
file.seekp(-static_cast<int>(sizeof(SinhVien)), ios::cur);
file.write(reinterpret_cast<const char*>(&sv), sizeof(SinhVien));
Trang 14Trang 14 file.close();
return; }
• Nếu không tìm thấy bản ghi nào có mã số sinh viên trùng khớp, đóng file SV.BIN
Sửa dữ ệu file HP.BINli
void suaHocPhan Đầu vào: mahp
Đầu ra: Dữ ệu đã được sửali
• Mở file HP.BIN trong chế độ đọc và ghi nhị phân: fstream (ios::binary|ios::in | ios::out)
• Lặp qua từng bản ghi trong file HP.BIN bằng cách sử dụng vòng lặp while while (file.read(reinterpret_cast<char*>(& ), sizeof(HocPhan))) {hp
if (strcmp(hp.mahp,mahp) == 0) { HocPhan hp ;
file.seekp(-static_cast<int>(sizeof(HocPhan)), ios::cur);
file.write(reinterpret_cast<const char*>(& ), sizeof(SinhVien));hp file.close();
return; }
• Nếu không tìm thấy bản ghi nào có mã học phần trùng khớp, đóng file HP.BIN
Sửa dữ ệu file DIEMTHI.BINli
void suaDiemThi Đầu vào: mahp , mssv Đầu ra: Dữ ệu đã được sửali
• Mở file DIEMTHI.BIN trong chế độ đọc và ghi nhị phân: fstream (ios::binary|ios::in | ios::out)
• Lặp qua từng bản ghi trong file DIEMTHI.BIN bằng cách sử dụng vòng lặp while while (file.read(reinterpret_cast<char*>(&dt), sizeof(DiemThi)){
if (strcmp(dt.mahp, mahp) == 0 && strcmp(dt.mssv, mssv) == 0) { DiemThi dt;
file.seekp(-static_cast<int>(sizeof(DiemThi)), ios::cur);
Trang 15Trang 55 case 2: { int bxs; do {
hienThiMenuBoSungXoaSua(bxs); bxs = _getch() - '0';
xuLyMenuBoSungXoaSua(bxs); if (bxs != 0) {
cout << "Nhan phim bat ky de tiep tuc." << endl; _getch();
system("cls"); }
} while (bxs != 0); break; } case 3: {
ghiLuaChonVaoFile("3 Tinh diem trung binh tich luy cua sinh vien ") ; char mssv[10];
cout << "Nhap ma sinh vien: "; cin >> mssv;
float gpa = tinhGPA(mssv); ghiGPA(mssv, gpa); break;
} case 4: {
ghiLuaChonVaoFile("4 Hien thi sinh vien theo hoc phan") ; char mahp[10];
cout << "Nhap ma hoc phan: "; cin >> mahp;
hien_thi_sv_theo_hp(mahp); break;
} case 5: {
ghiLuaChonVaoFile("5 Hien thi danh sach sinh vien chua dat hoc phan ") ;
Trang 16} case 6:{
ghiLuaChonVaoFile("6 Hien thi danh sach hoc phan sinh vien chua dat ") ;
cout << " Danh sach hoc phan chua dat " << endl; hien_thi_hoc_phan_chua_dat();
break; } case 7:{
ghiLuaChonVaoFile("7 Hien thi GPA sinh vien ") ; char mssv[10] ;
cout << "Nhap ma so sinh vien: "; cin >> mssv;
hienThiGPA(mssv); break;
} case 0: {
cout << "Thoat chuong trinh" << endl; break;
} default:{
cout << "Lua chon khong hop le, vui long nhap lai!" << endl; break;
} }
if (luaChon != 0) {
cout << endl << "Nhan phim bat ky de quay lai menu." << endl; _getch();
system("cls");
Trang 17Trang 57 menu(luaChon); }
}
int main(int argc, char* argv[]) { int luaChon = 1;
int phim; while (true) { menu(luaChon); phim = _getch();
if (phim == 0 || phim == 224) { phim = _getch(); switch (phim) { case 72: // Mui ten len luaChon ;
if (luaChon < 0) luaChon = 8; break;
case 80: // Mui ten xuong luaChon++;
if (luaChon > 10) luaChon = 0;
break; }
} else if (phim == 13) { if (luaChon == 1) {
xuLyMenuNhapDuLieu(luaChon); } else if (luaChon == 2) {
xuLyMenuBoSungXoaSua(luaChon); } else {
xuLyLuaChon(luaChon); }
if (luaChon == 0) {
cout << "Thoat chuong trinh." << endl; break;