Karnataka II PUC Computer Science (KSEAB) study materials
Karnataka II PUC Computer Science (KSEAB) study resources

The Extra Record at the End of students.dat

Karnataka II PUC Computer Science (KSEAB) · Put your knowledge to work in context.

All case studies

The Extra Record at the End of students.dat

A II PUC student writes a C++ program to append student records to a binary file named students.dat. Each record is a structure with an int roll, a char name[20], and a float marks. The program writes three records, closes the file, and reopens it for reading. The read loop is while(!fin.eof()) { fin.read((char*)&s, sizeof(s)); cout << s.roll << ' ' << s.marks << endl; }. The output shows the three correct records and then a fourth line that repeats the last roll number with garbage marks. The student adds if(fin.eof()) break; immediately after the read, but now reports that the third record sometimes disappears. The file is exactly 84 bytes, and sizeof(record) is 28 bytes. A second program opens the same file with ofstream fout("students.dat"); in text mode and writes one record; afterwards the original three records are gone. The teacher asks for a diagnosis of the loop and the file mode, not a quick patch.

1. Explain why the fourth record appears and why the if(fin.eof()) break; after the read can make a valid record disappear. Refer to when eofbit is set.

Read the worked answer

eof() is a state flag, not a prediction. It becomes true only after an input operation has attempted to read past the end. With exactly three 28-byte records, the third read consumes the last byte but does not yet set eofbit. The loop condition !fin.eof() is still true, so a fourth read is attempted. That read fails, sets eofbit and failbit, and leaves s with its previous contents or a partial overwrite; printing s then repeats the last roll number with garbage. The patch if(fin.eof()) break; after the read is also fragile: it depends on eof() being set at exactly the right moment, and a short or partial read can set the flag after delivering some bytes. The reliable rule is to test the read operation itself, not the flag.

2. Rewrite the read loop correctly and show how to verify the record count without relying on eof().

Read the worked answer

Use the stream's boolean conversion, or check gcount():

record s;
int count = 0;
while (fin.read(reinterpret_cast<char*>(&s), sizeof(s))) {
    cout << s.roll << ' ' << s.marks << endl;
    ++count;
}
if (!fin.eof()) {
    // not a clean end: disk error or partial record
}
cout << "records read: " << count << endl;

read returns the stream; the loop stops when the read fails. A cleaner check for a partial final record is if (fin.gcount() != sizeof(s)) after the loop. To verify the expected count independently, seek to the end, use tellg(), and divide by sizeof(record)-but only if the file contains exactly fixed-size records with no header, padding variation, or truncation. Counting successful reads is the safer check.

3. The second program opens with ofstream fout("students.dat"); in text mode. Explain two consequences and the correct open mode for appending one binary record.

Read the worked answer

ofstream fout("students.dat"); uses the default open mode, which includes ios::trunc. It therefore erases the existing file before writing one record; the three original records are gone. Second, the default is text mode. On systems that translate line endings, byte values that look like a newline can be expanded or collapsed on write/read, shifting record boundaries and corrupting binary fields. The correct append is ofstream fout("students.dat", ios::binary | ios::app);, and the reader should use ifstream fin("students.dat", ios::binary);. If the record contains a std::string, it must not be written as raw bytes; write a fixed-size character array or length-prefixed data.