Câu hỏi về đọc Struct trong file C++

Em chào các anh chị
Em làm bài tập về đọc file trong C++ mà có câu không làm ra em mong được các anh chị giúp đỡ .
Đây là code của em . Phần em gạch đen là phần em làm sai mà không viết sửa kết quả sao cho đúng ạ. Em có thử dùng getline(infile,s[i].name,’\n’) nhưng vẫn không đọc được cả Nguyen van A .Em cảm ơn anh chị ạ.

Tất cả dữ liệu đều nằm trên từng dòng, nên dùng getline cho từng dữ liệu.
mssv là kiểu chuỗi phải không?

Lưu ý: trên Windows thì mỗi dòng phân biệt bằng \r\n chứ không phải \n.

2 Likes

Dạ đây là phần khai báo struct của em
Anh ơi anh em có sửa lại là: getline(infile,s[i].name,"\r\n"); Nhưng không hiểu sao vẫn không được ạ

post code lên chứ sao lại chụp màn hình thế kia :V

```cpp
bỏ code vô đây
```

lỗi ở chỗ đọc infile >> mssv thì nó ko đọc ký tự newline của 01, nên tiếp theo có getline đi nữa thì nó cũng chỉ đọc vào chuỗi rỗng, phải ignore ký tự newline thừa này đi.

  • input là “2\n01\nNguyen Van A\n2003\n1\n02\nLe Van B\n2003\n10”
  • infile >> n consume hay tạm nói là “ăn” mất ký tự “2”, input còn “\n01\nNguyen Van A\n2003\n1\n02\nLe Van B\n2003\n10”,
  • vào vòng for, infile >> mssv sẽ ăn tiếp các ký tự “\n01”, input còn “\nNguyen Van A\n2003\n1\n02\nLe Van B\n2003\n10”
  • đọc tiếp getline(...) nó chỉ ăn ký tự “\n” chứ ko phải ăn “Nguyen Van A\n”, tức là đọc vào chuỗi rỗng (vì getline bỏ qua ký tự xuống dòng cuối cùng trong chuỗi ký tự ăn từ input), input còn lại là “Nguyen Van A\n2003\n1\n02\nLe Van B\n2003\n10”

thêm dòng infile.ignore(10, '\n'); sau infile >> mssv để bỏ qua là được.

Số 10 ở đây là số chọn đại, 100 1000 cũng được :V ignore tối đa 10 ký tự hoặc tới khi gặp ‘\n’ thì bỏ qua \n rồi dừng. Ví dụ input sau “01” có 10 ký tự khoảng trắng

          \nNguyen Van A

thì infile.ignore(10, '\n') chỉ ignore 10 khoảng trắng này, input vẫn còn “\nNguyen Van A” vậy là ko bỏ qua được ký tự xuống dòng này :V nhưng trong input kia chắc \n liền sau 01 ko có khoảng trắng nào, ignore() bình thường thôi cũng đủ, nhưng cứ ghi đại ignore(10, '\n') cũng được :V Muốn chắc ăn ignore được ký tự \n bất kể sau 01 có bao nhiêu khoảng trắng đi nữa thì viết ignore(std::numeric_limits<std::streamsize>::max(), '\n') mà có lẽ dài quá nên để số 10 hay 100 gì tạm được rồi :V

nhớ là C++ đọc bằng >> nó đọc tới khi nào gặp khoảng trắng (ví dụ như ' ', '\t', '\r', '\n', …) thì nó dừng, ko consume khoảng trắng này. Khi xài liền trước getline thì nó lấn cấn ký tự \n >> sẽ ko consume làm getline đọc dòng trống không.

3 Likes

https://www.ideone.com/kRCX6I

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

struct SINHVIEN
{	
	string mssv;
	string name;
	int namsinh;
	string quequan;
};

int doc_file();
void Doc_ThongTinSinhVien(ifstream &infile , SINHVIEN s[] , int &n);
void Xuat_ThongTinSinhVien(SINHVIEN s[],int n);


int main()
{
	doc_file();

}

int doc_file()
{
	ifstream infile;
	infile.open("C:\\Users\\Admin\\Desktop\\infile.txt",ios::in);

	if(infile.fail())
	{
		cout<<"Mo file that bai"<<endl;
		return 0;
	}

	SINHVIEN s[100];
	int n;
	Doc_ThongTinSinhVien(infile,s,n);
	Xuat_ThongTinSinhVien(s,n);
	infile.close();
}

void Doc_ThongTinSinhVien(ifstream &infile , SINHVIEN s[] , int &n)
{
	infile>>n;
	for( int i=0;i<n;i++ )
	{
		infile>>s[i].mssv;
		infile>>s[i].name;
		infile>>s[i].namsinh;
		infile>>s[i].quequan;
	}
}

void Xuat_ThongTinSinhVien(SINHVIEN s[],int n)
{
	cout<<n;
	for( int i=0;i<n;i++ )
	{
		cout<<"\nMa So Sinh Vien La: "<<s[i].mssv;
		cout<<"\nTen Sinh Vien la: "<<s[i].name;
		cout<<"\nNam Sinh la: "<<s[i].namsinh;
		cout<<"\nQue Quan la: "<<s[i].quequan;
		cout<<endl;
	}
	cout<<endl;
}

Dạ đây là code của em
Dạ em hiểu rồi . Em cảm ơn anh.
Anh ơi anh có thể cho em xin tài liệu nói về phần này được không anh : infile.ignore(10, '\n')

https://en.cppreference.com/w/cpp/io/basic_istream/ignore có ở đây nè em :V Thắc mắc gì về C++ cứ gg “cppref <tên hàm>” ví dụ “cppref ignore” là ra :V

anh có giải thích thêm ở dưới đó :V

ký tự ‘\n’ có thể thay bằng ký tự nào cũng được. Xài ‘\n’ vì ở đây các phần tử ngăn cách bằng ký tự xuống dòng. Ví dụ csv nó ngăn cách các phần tử bằng dấu phẩy thì thế ignore(..., '\n') bằng ignore(..., ',').

còn tìm hiểu/đọc tài liệu thì phải chịu khó đọc tiếng Anh thôi em :V bởi vậy ai nói học cntt cần giỏi toán là chưa đúng lắm, cần giỏi đọc tiếng Anh nhiều hơn :V

3 Likes

Em có tìm hiểu về phương thức infile.seekg( 1,ios::cur) để dịch con trỏ sang 1 byte thì cách đó có được không anh .
Em có chạy thử cách đó nhưng vẫn không đọc được Nguyen Van A ạ

So for a file opened in text mode, you can’t do any arithmetic on offsets. You can rewind to the beginning, position at the end, or return to the position you were at previously and captured with tellg (which ultimately calls ftell ). Anything else would exhibit undefined behavior.

khi open file ở text mode (ko phải binary mode) thì seekg chỉ hợp lệ khi rewind về đầu/cuối file hoặc trở về vị trí tellg cũ, còn mấy thứ khác như seekg(n, …) thì nó là ko xác định :V

Ký tự newline trong file ở Windows có thể là \r\n hoặc \n, ko biết seekg(2, …) hay seekg(1, …) mới đúng :V Xài ignore(100, ‘\n’) cho khỏe. Với lại nếu đọc code thì đọc thấy dòng ignore(…) hiểu ngay là bỏ qua các ký tự, còn đọc thấy seekg thì lại phải suy nghĩ xem dòng seekg này để làm gì, mất thời gian đọc hơn. Bỏ qua các ký tự thì xài hàm đúng tên gọi nó là ignore :V

vd viết

for (char c = infile.get(); c != '\n' && infile;) c = infile.get();
hoặc
for (char c = infile.get(); c != '\n' && c != std::char_traits<char>::eof();) c = infile.get();

thay cho infile.ignore(100, '\n'); cũng được nhưng viết ignore hiểu ngay là bỏ qua ký tự, vòng for kia lại phải đọc từng chữ để hiểu nó làm gì :V Chưa kể có thể quên mất kiểm tra infile còn hợp lệ ko đề phòng trường hợp đọc hết file mà vẫn chưa gặp ký tự newline thì infile ko còn ký tự để đọc, infile.get() nó trả về std::char_traits<char>::eof() (thông thường là -1) nó so sánh khác ‘\n’, lặp mãi mãi :V Xài ignore đỡ phải lo mấy vấn đề rắc rối này, na ná như xài seekg thì lại gặp vấn đề newline là \n hay \r\n ở Windows, hay seekg(n, cur) là undefined behavior trong text mode :V

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