Gặp lỗi terminate called after throwing an instance of 'std::bad_alloc' trong code nhập/xuất file

E đang làm bài tập trên trường như sau:

Còn đây là source code của e:

/* INPUT:
Barack Obama - +84978817165 - 68/6 Red Street - 9.75 8.5 9
Donald Trump - +84947821558 - 11 Green Street - 8.75 9.5 8.75
Hillary Clinton - +841299992930 - 22 Yellow Street - 9.25 8 9
Bill Clinton - +84988345692 - 69/6 Pink Street - 9 8.75 8.5
George Washington - +84982584394 - 24/5 Brown Street - 9.25 9 8.75
*/
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <algorithm>

typedef struct {
    std::string name, phone_number, address;
    double Math, Physics, Chemistry, AveragePoint;
} stdinf;

std::vector<stdinf> ReadFile(std::fstream &); // Read data from a file to a vector
void SortStudent(std::vector<stdinf> &); // Sort the vector by average point
void WriteFile(std::fstream &, std::vector<stdinf>); // Write the vector to a file

std::vector<stdinf> ReadFile(std::fstream &FileIn)
{
    std::vector<stdinf> s;
    FileIn.open("INPUT", std::ios::in);
    while (!FileIn.eof()) {
        std::string Name, Phone_number, Address;
        double math, physics, chemistry, averagePoint;
        std::getline(FileIn, Name, '-'); Name.erase(Name.end() - 1); FileIn.seekg(1, std::ios::cur);
        std::getline(FileIn, Phone_number, '-'); Phone_number.erase(Phone_number.end() - 1); FileIn.seekg(1, std::ios::cur);
        std::getline(FileIn, Address, '-'); Address.erase(Address.end() - 1); FileIn.seekg(1, std::ios::cur);
        FileIn >> math >> physics >> chemistry;
        averagePoint = (math + physics + chemistry) / 3;
        stdinf f;
        f.name = Name; f.phone_number = Phone_number; f.address = Address; f.Math = math; f.Physics = physics;
        f.Chemistry = chemistry; f.AveragePoint = averagePoint;
        s.push_back(f);
    }
    return s;
}

void SortStudent(std::vector<stdinf> &s)
{
    int length = s.size();
    for (int i = 0; i < length - 1; ++i) {
        for (int j = i + 1; j < length; ++j) {
            if (s[i].AveragePoint > s[j].AveragePoint)
                std::swap(s[i].AveragePoint, s[j].AveragePoint);
        }
    }
}

void WriteFile(std::fstream &FileOut, std::vector<stdinf> s)
{
    FileOut.open("OUTPUT", std::ios::out);
    int length = s.size();
    for (int i = 0; i < length; ++i) {
        FileOut << "Student " << i + 1 << ":\n";
        FileOut << "Name: " << s[i].name << std::endl;
        FileOut << "Phone number: " << s[i].phone_number << std::endl;
        FileOut << "Address: " << s[i].address << std::endl;
        FileOut << "Math - Physics - Chemistry point: " << s[i].Math << " " << s[i].Physics << " " << s[i].Chemistry << std::endl;
    }
}

int main()
{
    std::fstream FileIn, FileOut;
    std::vector<stdinf> s;
    s = ReadFile(FileIn);
    SortStudent(s);
    WriteFile(FileOut, s);
    FileOut.close();
    FileIn.close();
    return 0;
}

Khi em compile và run lên bằng terminal thì nó lại bị lỗi như sau:

E kiểm tra lại code kỹ càng lắm rồi mà vẫn không hiểu sao lại bị lỗi đó, các pro giúp em với ạ !
Em cảm ơn trước :blush:

1 Like

Up up up …

Check xem file đúng và đủ input chưa.

2 Likes

Đủ rồi mà anh, trước đó em có in ra thử toàn bộ data trong file INPUT thì bình thường, sau đó mới tiến hành code :slight_smile:

bạn đổi dấu xét lại trong vòng điều kiện và swap hai phần tử chứ không swap 2 biến.
Vậy mới đúng với yêu cầu bài của bạn.

1 Like

:c Tại mình test input đúng nó chả báo lỗi như trên hình.

1 Like

À chỗ này e quên mất :sweat: để std::swap(s[i], s[j]) mới đúng đúng không anh ?
Cứ mãi tập trung tìm bug trong code mà quên mất luôn cái đề bài :sweat_smile:

Quải thế nhỉ :v
Em dùng g++ để build, không biết compiler của a có khác ko ?

:smiley: Mình dùng g++ luôn. GNU v5.4.0.
Mà check lại xem file INPUT có trong cùng thư mục chay chương trình chưa (lưu ý là đúng tên, đúng hoa thường, ko có đuôi này nọ).

1 Like

Đúng mà anh, có khi nào compiler của e nó dở chứng ko nhỉ :cry:

Hay là có khi nào do .seekg() không nhỉ :thinking:

Update source code:

/* INPUT:
Barack Obama - +84978817165 - 68/6 Red Street - 9.75 8.5 9
Donald Trump - +84947821558 - 11 Green Street - 8.75 9.5 8.75
Hillary Clinton - +841299992930 - 22 Yellow Street - 9.25 8 9
Bill Clinton - +84988345692 - 69/6 Pink Street - 9 8.75 8.5
George Washington - +84982584394 - 24/5 Brown Street - 9.25 9 8.75
*/

#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <algorithm>

typedef struct {
	std::string name, phone_number, address;
	double Math, Physics, Chemistry, AveragePoint;
} stdinf;

std::vector<stdinf> ReadFile(std::fstream &); // Read data from a file to a vector
void SortStudent(std::vector<stdinf> &); // Sort the vector by average point
void WriteFile(std::fstream &, std::vector<stdinf>); // Write the vector to a file

std::vector<stdinf> ReadFile(std::fstream &FileIn)
{
	std::vector<stdinf> s;
	FileIn.open("INPUT.txt", std::ios::in);
	while (!FileIn.eof()) {
		std::string Name, Phone_number, Address;
		double math, physics, chemistry, averagePoint;
		std::getline(FileIn, Name, '-'); Name.erase(Name.end() - 1); FileIn.seekg(1, std::ios::cur);
		std::getline(FileIn, Phone_number, '-'); Phone_number.erase(Phone_number.end() - 1); FileIn.seekg(1, std::ios::cur);
		std::getline(FileIn, Address, '-'); Address.erase(Address.end() - 1); FileIn.seekg(1, std::ios::cur);
		FileIn >> math >> physics >> chemistry; FileIn.seekg(2, std::ios::cur);
		averagePoint = (math + physics + chemistry) / 3;
		stdinf f;
		f.name = Name; f.phone_number = Phone_number; f.address = Address; f.Math = math; f.Physics = physics;
		f.Chemistry = chemistry; f.AveragePoint = averagePoint;
		s.push_back(f);
	}
	return s;
}

void SortStudent(std::vector<stdinf> &s)
{
	int length = s.size();
	for (int i = 0; i < length - 1; ++i) {
		for (int j = i + 1; j < length; ++j) {
			if (s[i].AveragePoint < s[j].AveragePoint)
				std::swap(s[i], s[j]);
		}
	}
}

void WriteFile(std::fstream &FileOut, std::vector<stdinf> s)
{
	FileOut.open("OUTPUT.txt", std::ios::out);
	int length = s.size();
	for (int i = 0; i < length; ++i) {
		FileOut << "Student " << i + 1 << ":\n";
		FileOut << "Name: " << s[i].name << std::endl;
		FileOut << "Phone number: " << s[i].phone_number << std::endl;
		FileOut << "Address: " << s[i].address << std::endl;
		FileOut << "Math - Physics - Chemistry point: " << s[i].Math << " " << s[i].Physics << " " << s[i].Chemistry << std::endl;
	}
}

int main()
{
	std::fstream FileIn, FileOut;
	std::vector<stdinf> s;
	s = ReadFile(FileIn);
	SortStudent(s);
	WriteFile(FileOut, s);
	FileOut.close();
	FileIn.close();
	return 0;
}

@drgnz em có thử debug thì phát hiện nó sai ở chỗ vòng lặp: while (!FileIn.eof()) {...} .
Khi chương trình đọc xong dòng cuối cùng (George Washington) trong file thì tự nhiên nó vẫn thực hiện được tiếp vòng lặp ??

Chạy trên 6.3 lòi ra bug. Đúng là do hàm seekg sai.
Bạn chỉ cần bỏ đi hết là được.

Còn vì sao thì getline bản thân nó cũng đã đọc dấu “-” của bạn và nó bỏ qua rồi, nên ko cần seek sang 1 byte từ vị trí đang trỏ nữa

1 Like

Nó sai vì lý do gì a ?

E tính làm như thế để khỏi phải tốn công erase đó mà :smiley:

Edit: Mà em xóa hết mấy dòng .seekg(); nó vẫn lỗi vậy anh ơi :cry:

Em nghĩ là do: while (!FileIn.eof()) ấy, vì hỗi nãy e debug thấy mặc dù tới cuối file rồi những vòng lặp vẫn tiếp tục thực hiện nên tới chỗ getline bị sai, nhưng e lại ko hiểu vì sao nó lại thực hiện tiếp mặc dù đã đến cuối file nữa :cry:

À rồi, eof() nó chỉ trả về true sau khi mà nó đọc hết filestream.
Vậy nên trường hợp trên, có thể data đã hết, nhưng filestream thì chưa -> Lỗi.
Thay bằng ntn xem fix được ko nhé :smiley: :

std::string Name, Phone_number, Address;
while (std::getline(FileIn, Name, '-')) {
  ...
}

http://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong

2 Likes

Đọc thấy nó sai sai rồi (while (!eof()) :smiley: nhưng mà không ngờ lại sinh exception này mới lạ.

2 Likes

Em chưa hiểu chỗ này lắm, anh có thể nói kỹ hơn xíu dc ko ? :slight_smile:

Anh trả lời giùm e câu này luôn nhé ^^ (vì sao nó wrong ấy)

Yeah, nó chạy được rồi, thì ra đây là exception :smiley:


Khi e mở file OUTPUT bằng sudo gedit ./OUTPUT thì nó vẫn hiện ra file OUTPUT bằng gedit nhưng trên terminal có mấy cái dòng warning này là sao nhể a @drgnz :

P/S: Mà hình như giữa chữ name với tên có \n thì phải:

E dùng seekg để xóa đi cái \n trước mỗi cái tên dc ko a @drgnz ? (vì a kêu seekg bị lỗi nên e ko dám dùng :smile:)
Eidt: À, mà seekg và seekp có dùng được cho file văn bản ko nhỉ ?

Không phải seekg sai. :smiley: Mà dùng cho file văn bản như vậy thg sẽ bị sai lệch do có nhiều ký tự sẽ ko hiển thị nhưng nó vẫn được đọc vào -> seek sai. Như ký tự xuống dòng, window nhận là \r\n, nhưng nhiều OS khác (Linux chẳng hạn) có khi chỉ nhận \n là đủ rồi. (Với có lẽ do cái GCC 6.3 trên Windows của mình bị bug hàm tellg dẫn tới việc seekg sai @_@)

Tới đây thì mình thực sự ko rành nữa rồi. Tuy nhiên đọc SO (link trên) với Ref thì nghĩ nó ntn (để chắc hơn bạn có thể hỏi mấy anh rành C++ hơn nhé :smiley: ):

eof() nó check eofbit chưa được bật thì nó return false, còn lại thì true.
Còn khi nào eofbit được bật? Đó là khi có lỗi xãy ra trong quá trình đọc file cụ thể là đọc lố file.
Thì ở th trên khi đọc xong hết các dữ liệu. Tuy nhiên vẫn chưa lỗi gì xảy ra -> eof mới hiểu là oh, chưa có lỗi gì cả vậy là chưa hết file, đọc tiếp. Tuy nhiên khi đọc thì lúc này mới lỗi, eofbit được bật, nhưng đã quá muộn rồi.

Nếu thấy vậy bạn có thể mở bằng gksudo gedit … (lệnh mở các ứng dụng GUI bằng quyền root, kdesudo cũng được, nhưng ubuntu có gksudo sẵn rồi)

2 Likes

Windows là \r\n luôn bạn :slight_smile:

1 Like

Là sao anh ? Trrong file văn bản cũng có ký tự ẩn ạ ?
Btw, e có thử lấy đoạn code trên test trên Codeblocks, bỏ seekg vào 1 vài chỗ rồi lúc in ra trong file OUTPUT, nó thiếu tùm lum hết (nghĩa là con trỏ chỉ vị nó nhảy lung tung) :cry:
vậy câu đó cũng đồng nghĩa với việc trong file nhị phân ko có ký tự ẩn hả an h?

Wow, e tưởng là eof nó check vị trí của con trỏ chỉ vị, nếu con trỏ chỉ vị đến cuối file thì nó return true, chứ ?

ừm, sao e thấy có một số code họ dùng eof: while (!File.eof()) vẫn an toàn vậy a ?

Các file text nó có các whitespace character nhiều cái bị ẩn đi mình ko thấy bằng mắt thg nên đọc hay seek thg dễ sai (vì nhiều kkhi mình thấy nó ko có gì nhưng nó lại sờ sờ ở đó). Với như nói ở trên, có vẻ như hàm tellg (xác định vị trí hiện tại của con trỏ trỏ trong file) bị bug trên windows (cụ thể là GCC do mingw biên dịch) nên dẫn tới việc nhảy lung tung @_@

Có thể trong đoạn code đọc, có 1 phần code khi đọc là luôn đảm bảo lố EOF? :thinking:

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