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.
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.
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.
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 */
}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.
/* 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);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?
Why this lesson exists
Syllabus mapping
Searching a Database · Binary Files
Maps to course outcomes CO3, CO6.