Lỗi đọc file EOF

Mọi người cho em hỏi: khi em đọc mảng sinh viên, em để vòng lặp while(!filein.eof()) thì bị lỗi không thể thực hiện được ạ. Em mới học c++ nên mong mọi người chỉ giáo. Em cảm ơn.
Đề bài:

Bài làm:

/*
hoang duy - 0949771945 - 16/11/1994 - 4.5 5.5 6.5
Tran Minh Cuong - 0917552182 - 18/12/1998 - 10 10 10
Minh Hoang - 0912155022 - 12/12/2004 - 9 9 9.5
Minh Vi - 0943219155 - 28/12/1996 - 6.5 10 9.7

*/
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;

struct sinhvien
{
	string name, phone;
	int day, month, year;
	float toan, ly, hoa;
};
typedef struct sinhvien sv;	

void doc1sinhvien(ifstream& filein, sv& x)
{
	getline(filein, x.name, '-'); // đọc tới dầu gạch '-' => bị thừa 1 khoảng trắng => sau khi đọc getline con trỏ sẽ lùi về 1 vị trí => ở sau dấu '-'
	x.name.erase(x.name.begin() + (x.name.length() - 1)); // xóa ký tự cuối cùng
	filein.seekg(1, 1);
	filein >> x.phone;
	filein.seekg(3, 1);
	filein >> x.day;
	filein.seekg(1, 1);
	filein >> x.month;
	filein.seekg(1, 1);
	filein >> x.year;
	filein.seekg(3, 1);
	filein >> x.toan >> x.ly >> x.hoa;
	string temp; // đọc ký tự cuối xuống dòng
	getline(filein, temp);
}

void ghi1sinhvien(ofstream& fileout, sv x)
{
	fileout << "\nten: " << x.name;
	fileout << "\nsdt: " << x.phone;
	fileout << "\nSinh nhat: " << x.day << "/" << x.month << "/" << x.year;
	fileout << "\ntoan: " << x.toan;
	fileout << "\nly: " << x.ly;
	fileout << "\nhoa: " << x.hoa;
	fileout << "\n------------------------------------------";
}

void docmangsinhvien(ifstream& filein, vector<sv>& arr)
{
	for (int i = 0; i < 4; i++)
	{
		sv x;
		doc1sinhvien(filein, x);
		arr.push_back(x);
	}
	filein.close();
}
void ghimangsinhvien(ofstream& fileout, vector<sv> arr)
{
	for (int i = 0; i < arr.size(); i++)
	{
		ghi1sinhvien(fileout, arr[i]);
	}
	fileout.close();
}
float tinhdiemtrungbinh(sv x)
{
	return (x.toan + x.ly + x.hoa) / 3;
}

void hoanvi(sv& x, sv& y)
{
	sv temp;
	temp = x;
	x = y;
	y = temp;
}

void giamdantheodiemtrungbinh(vector<sv> &arr)
{
	for (int i = 0; i < arr.size() - 1; i++)
	{
		for (int j = i + 1; j < arr.size(); j++)
		{
			if (tinhdiemtrungbinh(arr[i]) < tinhdiemtrungbinh(arr[j]))
			{
				hoanvi(arr[i], arr[j]);
			}
		}
	}
}
int main()
{
	ifstream filein("input.txt");
	vector<sv> arr;
	docmangsinhvien(filein, arr);
	ofstream fileout("output.txt");
	giamdantheodiemtrungbinh(arr);
	ghimangsinhvien(fileout, arr);

	
	system("pause");
	return 0;
}

Cấu trúc của input.txt là thế nào?

Mỗi dòng lưu 1 sinh viên? Đọc dùng seekg() là không ổn.
Đọc luôn 1 dòng, sau đó dùng strtok() để tách các giá trị, kết hợp với stoi()stof() để chuyển về dạng số.

Cũng nên chú ý: nếu dòng cuối (hoặc dòng bất kì) chỉ có kí tự xuống dòng (dòng trống) thì vẫn lỗi.

4 Likes

em xài filein.ignore() để bỏ qua 1 ký tự ấy, đừng xài seekg :V

muốn xóa ký tự cuối cùng trong string có thể xài pop_back() :V

và cuối cùng là đừng xài filein.eof() :V Em xài while (filein) là được

4 Likes

để tránh lỗi dòng trống cuối cùng thì em đành đọc từng dòng vào rồi chuyển dòng đó thành 1 string stream vậy:

void docmangsinhvien(ifstream& filein, vector<sv>& arr) {
    for (string line; getline(filein, line);) { // đọc từng dòng tới hết
        istringstream iss(line); // chuyển dòng đó thành input string stream (giống ifstream hoặc cin)
        sv x;
        doc1sinhvien(iss, x); // truyền iss thay vì truyền filein
        arr.push_back(x);
    }
}

void doc1sinhvien(istream& linein, sv& x) { // linein là istream
    // input có dạng
    // hoang duy - 0949771945 - 16/11/1994 - 4.5 5.5 6.5
    getline(linein, x.name, '-');
    x.name.pop_back(); // xóa ký tự cuối cùng
    linein >> x.phone;
    linein.ignore(3); // bỏ qua " - "
    linein >> x.day;
    linein.ignore(); // bỏ qua '/'
    linein >> x.month;
    linein.ignore();
    linein >> x.year;
    linein.ignore(3);
    linein >> x.toan >> x.ly >> x.hoa;
}
3 Likes

có lẽ viết kiểu >> như C++ có lý hơn: :V

istream& operator>>(istream& is, SinhVien& sv) {
    // hoang duy - 0949771945 - 16/11/1994 - 4.5 5.5 6.5
    if (!getline(is, sv.name, '-')) return is; // ko đọc được nữa
    sv.name.pop_back(); // xóa ký tự cuối cùng
    is >> sv.phone;
    is.ignore(3); // bỏ qua " - "
    is >> sv.day;
    is.ignore(); // bỏ qua '/'
    is >> sv.month;
    is.ignore();
    is >> sv.year;
    is.ignore(3);
    is >> sv.toan >> sv.ly >> sv.hoa;
    return is;
}

int main() {
    ifstream filein("input.txt");
    vector<SinhVien> arr;
    for (SinhVien sv; filein >> sv;) arr.push_back(sv);
    ...

cẩn thận thì

istream& operator>>(istream& is, SinhVien& sv) {
    // hoang duy - 0949771945 - 16/11/1994 - 4.5 5.5 6.5
    if (!getline(is, sv.name, '-')) return is; // ko đọc được nữa
    sv.name.pop_back(); // xóa ký tự cuối cùng
    if (!(is >> sv.phone)) return is;
    if (!is.ignore(3)) return is; // bỏ qua " - "
    if (!(is >> sv.day)) return is;
    if (!is.ignore()) return is; // bỏ qua '/'
    if (!(is >> sv.month)) return is;
    if (!is.ignore()) return is;
    if (!(is >> sv.year)) return is;
    if (!is.ignore(3)) return is;
    return is >> sv.toan >> sv.ly >> sv.hoa;
}

viết cẩn thận + gộp lại:

istream& operator>>(istream& is, SinhVien& sv) {
    // hoang duy - 0949771945 - 16/11/1994 - 4.5 5.5 6.5
    if (!getline(is, sv.name, '-')) return is; // ko đọc được nữa
    sv.name.pop_back(); // xóa ký tự cuối cùng
    return ((((is >> sv.phone).ignore(3) >> sv.day).ignore() >> sv.month).ignore() >> sv.year).ignore(3) >> sv.toan >> sv.ly >> sv.hoa;
}

:rofl:

để tránh hại mắt thì có thể tách ngày sinh ra làm struct riêng, quá tải toán tử >> cho nó:

struct NgaySinh {
    int ngay, thang, nam;
};

istream& operator>>(istream& is, NgaySinh& ns) {
    char _;
    return is >> ns.ngay >> _ >> ns.thang >> _ >> ns.nam;
}

struct SinhVien {
    string name, phone;
    NgaySinh ngaysinh;
    float toan, ly, hoa;
};

istream& operator>>(istream& is, SinhVien& sv) {
    // hoang duy - 0949771945 - 16/11/1994 - 4.5 5.5 6.5
    if (!getline(is, sv.name, '-')) return is; // ko đọc được nữa
    sv.name.pop_back();                        // xóa ký tự cuối cùng
    return ((is >> sv.phone).ignore(3) >> sv.ngaysinh).ignore(3) >> sv.toan >>
           sv.ly >> sv.hoa;
}

ta có thể tạo 1 struct riêng để khỏi xài cái hàm ignore nữa mà viết >> ignore:

struct ignore {
    streamsize n;
    char c;
    ignore(streamsize n = 1, char c = '\n') : n(n), c(c) {}
};
istream& operator>>(istream& is, ignore i) {
    return is.ignore(i.n, i.c);
}

struct NgaySinh {
    int ngay, thang, nam;
};
istream& operator>>(istream& is, NgaySinh& ns) {
    return is >> ns.ngay >> ignore() >> ns.thang >> ignore() >> ns.nam;
}
ostream& operator<<(ostream& os, const NgaySinh& ns) {
    return os << ns.ngay << '/' << ns.thang << '/' << ns.nam;
}

struct SinhVien {
    string name, phone;
    NgaySinh ngaysinh;
    float toan, ly, hoa;
};
istream& operator>>(istream& is, SinhVien& sv) {
    // hoang duy - 0949771945 - 16/11/1994 - 4.5 5.5 6.5
    if (!getline(is, sv.name, '-')) return is; // ko đọc được nữa
    sv.name.pop_back();                        // xóa ký tự cuối cùng
    return is >> sv.phone >> ignore(3) >> sv.ngaysinh >> ignore(3) >> sv.toan >>
           sv.ly >> sv.hoa;
}
4 Likes

em cảm ơn anh nhiều ạ . có mấy cái em chưa load được hết nhưng cũng hiểu 1 phần . cảm ơn a nhiều

vâng ạ , em cảm ơn a nhiều :wink:

83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?