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:
Đề bài: Cho danh sách các học sinh có trong lớp, biết thông tin 1 học sinh bao gồm: họ tên, số điện thoại, ngày sinh, điểm toán, lý hóa. Yêu cầu: Sắp xếp danh sách học sinh trong lớp giảm dần theo điểm trung bình biết công thức tính như sau:
Điểm trung bình = (toán + lý + hóa)/3
Dữ liệu đọc vào là từ file INPUT.TXT
Dữ liệu ghi ra là file OUTPUT.TXT
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 << ":
";
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
Up up up …
Check xem file đúng và đủ input chưa.
Đủ 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
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.
:c Tại mình test input đúng nó chả báo lỗi như trên hình.
À chỗ này e quên mất để
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
Quải thế nhỉ :v
Em dùng g++ để build, không biết compiler của a có khác ko ?
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ọ).
Đúng mà anh, có khi nào compiler của e nó dở chứng ko nhỉ
Hay là có khi nào do
.seekg()
không nhỉUpdate source code:
@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
Nó sai vì lý do gì a ?
E tính làm như thế để khỏi phải tốn công erase đó mà
Edit: Mà em xóa hết mấy dòng
.seekg();
nó vẫn lỗi vậy anh ơiEm 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À 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é :
http://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong
Đọc thấy nó sai sai rồi (while (!eof()) nhưng mà không ngờ lại sinh exception này mới lạ.
Em chưa hiểu chỗ này lắm, anh có thể nói kỹ hơn xíu dc ko ?
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
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 )Eidt: À, mà seekg và seekp có dùng được cho file văn bản ko nhỉ ?
Không phải seekg sai. 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é ):
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)
Windows là
\r\n
luôn bạnLà 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)
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?
E chưa hiểu lắm !
VD: Trong file.txt, khi e cho con trỏ tới trước khoảng trắng, giữ Shift rồi nhấn phím mũi tên qua phải, nó sẽ bôi đen cái ký tự khoảng trắng đó. Vậy trong trường hợp trên (như anh nói), ký tự khoảng trắng đó ko dùng cách Shift + -> để xác định dc ạ ?
hàm tellg bị bug là sao a ? Mà seekg liên qua j đến tellg nhỉ ?
VD e có đoạn code sau:
trong file INPUT.txt có:
thì nó vẫn in đủ ra màn hình 5 số …
vậy trường hợp này ko bị lỗi đó a, và còn nhiều trường hợp khác dùng .eof() vẫn ko bị lỗi