Unit 5 · Lesson 320 minAcademic review pending

Finding one record among many

Because binary records are all the same size, you can compute where any record lives and jump straight to it with fseek.

Choose explanation

After this lesson

You should be able to

  • Search a file of records sequentially for a matching key.
  • Use fseek and ftell to move to a chosen record.
  • Update a record in place without rewriting the whole file.
01

Sequential search through a file

The simplest search reads records one at a time and stops at the first match. It is linear search from Unit III, with fread in place of the array subscript, and it works no matter how the file is ordered.

Return whether it was found and hand the record back through an output parameter. That keeps the function usable by any caller, whether it wants to print, edit or count.

Linear search, reading records instead of array elements
int find_by_roll(FILE *fp, int roll, Student *out)
{
    rewind(fp);                       /* start from the beginning */

    while (fread(out, sizeof(Student), 1, fp) == 1)
        if (out->roll == roll)
            return 1;                 /* found */

    return 0;                         /* not found */
}
02

Jumping straight to a record

If records are numbered and all the same size, record i begins at byte i * sizeof(Student). fseek moves there in one step, so reading record 500 costs the same as reading record 1.

fseek takes an origin: SEEK_SET from the start, SEEK_CUR from the current position, SEEK_END from the end. ftell reports where you currently are, which divided by the record size gives the record number.

Direct access, and counting records without reading them
/* read record number 2 (the third one) directly */
fseek(fp, 2 * sizeof(Student), SEEK_SET);
fread(&s, sizeof(Student), 1, fp);

/* how many records does the file hold? */
fseek(fp, 0, SEEK_END);
long records = ftell(fp) / sizeof(Student);
03

Updating in place

Open with "rb+" to read and write the same file. Find the record, seek back to where it started, and write the changed version over it. Because the new record is the same size, it fits exactly.

After the read, the position sits just past the record, so you must seek backwards by one record size before writing. Forgetting that seek overwrites the following record instead — a bug that silently destroys the wrong student's data.

Try it yourself

Given a binary file of students, find one by roll number and add five grace marks to that record only.

Need a hint?

After fread the position is past the record, so seek back before you fwrite.

Check the worked solution

The fseek with a negative offset and SEEK_CUR is the whole trick — it steps back exactly one record so the write lands on the record just read. Opening with "rb+" rather than "wb" matters too: "wb" would empty the file before anything was found.

#include <stdio.h>

typedef struct {
    int  roll;
    char name[40];
    int  marks;
} Student;

int main(void)
{
    FILE *fp = fopen("students.dat", "rb+");
    Student s;
    int target = 102, found = 0;

    if (fp == NULL) { printf("Cannot open\n"); return 1; }

    while (fread(&s, sizeof(Student), 1, fp) == 1) {
        if (s.roll == target) {
            s.marks += 5;
            if (s.marks > 100) s.marks = 100;

            fseek(fp, -(long) sizeof(Student), SEEK_CUR);  /* step back */
            fwrite(&s, sizeof(Student), 1, fp);
            found = 1;
            break;
        }
    }

    fclose(fp);
    printf(found ? "Updated\n" : "Roll not found\n");
    return 0;
}

Quick check

Why can you jump directly to record 500 in a binary file of structures?

Select an answer to check your thinking.

Why this lesson exists

Syllabus mapping

Searching a Database · Binary Files

Maps to course outcomes CO3, CO6.