Programming Language & Its Applications — Pointers, Structure and Data Files in C, NEC licence examination syllabus (Nepal Engineering Council).
Sequential access reads front to back; random access jumps straight to record number 4,182. The difference is fseek.
Every open file has a file position indicator — a byte offset that says where the next read or write will happen. Sequential access just lets it advance. Random access moves it deliberately with fseek, and because a fixed-size record file has a predictable layout, you can compute exactly where any record lives. That one multiplication turns a file into a database.
grep works, how a video plays. Random access is what happens when you drag the player to 42:30 and it starts instantly — the player computed a byte offset and seeked. It is also why an SSD changed everything: on a spinning disk a seek meant physically moving a head (~10 ms); on an SSD it is ~0.1 ms. Databases designed in the 1970s are still shaped by the assumption that seeks are expensive.#include <stdio.h>
#include <string.h>
typedef struct {
int roll;
char name[20];
float marks;
} Student;
/* read record n directly - O(1), no scanning */
int read_record(FILE *fp, long n, Student *out) {
if (fseek(fp, n * (long)sizeof(Student), SEEK_SET) != 0)
return 0;
return fread(out, sizeof(Student), 1, fp) == 1;
}
/* update record n IN PLACE - the file does not grow */
int update_record(FILE *fp, long n, const Student *s) {
if (fseek(fp, n * (long)sizeof(Student), SEEK_SET) != 0)
return 0;
return fwrite(s, sizeof(Student), 1, fp) == 1;
}
long record_count(FILE *fp) {
long here = ftell(fp);
fseek(fp, 0, SEEK_END);
long n = ftell(fp) / (long)sizeof(Student);
fseek(fp, here, SEEK_SET);
return n;
}
int main(void) {
/* build a 5-record file */
Student data[5] = {
{101,"Ram Bahadur", 87.5f},{102,"Sita Devi", 91.0f},
{103,"Hari Prasad", 76.5f},{104,"Gita Kumari",68.0f},
{105,"Bikash Thapa",94.5f}
};
FILE *fp = fopen("students.dat", "wb");
if (!fp) return 1;
fwrite(data, sizeof(Student), 5, fp);
fclose(fp);
/* "r+b" = read AND write, do not truncate */
fp = fopen("students.dat", "r+b");
if (!fp) { perror("open"); return 1; }
printf("sizeof(Student) = %zu\n", sizeof(Student));
printf("records in file = %ld\n", record_count(fp));
Student s;
/* jump straight to record 3 */
if (read_record(fp, 3, &s))
printf("rec 3: %d %-14s %.1f (ftell now %ld)\n",
s.roll, s.name, s.marks, ftell(fp));
/* modify it and write it back in place */
s.marks += 10.0f;
update_record(fp, 3, &s);
read_record(fp, 3, &s);
printf("rec 3 after +10: %.1f\n", s.marks);
/* the last record, via SEEK_END */
fseek(fp, -(long)sizeof(Student), SEEK_END);
fread(&s, sizeof(Student), 1, fp);
printf("last : %d %-14s %.1f\n", s.roll, s.name, s.marks);
/* backwards traversal - only possible with fseek */
printf("reverse order: ");
for (long i = record_count(fp) - 1; i >= 0; i--) {
read_record(fp, i, &s);
printf("%d ", s.roll);
}
printf("\n");
fclose(fp);
return 0;
}
Output:
sizeof(Student) = 28
records in file = 5
rec 3: 104 Gita Kumari 68.0 (ftell now 112)
rec 3 after +10: 78.0
last : 105 Bikash Thapa 94.5
reverse order: 105 104 103 102 101
#include <stdio.h>
typedef struct { int roll; char name[20]; float marks; } Student;
/* SEQUENTIAL search: must read every record until match */
long seq_find(FILE *fp, int roll, long *reads) {
rewind(fp); *reads = 0;
Student s;
for (long i = 0; fread(&s, sizeof s, 1, fp) == 1; i++) {
(*reads)++;
if (s.roll == roll) return i;
}
return -1;
}
/* RANDOM access when the roll number IS the position:
roll 101 -> record 0, roll 150 -> record 49 */
long direct_find(FILE *fp, int roll, long *reads) {
long idx = roll - 101; /* hashing, in effect */
if (idx < 0) return -1;
fseek(fp, idx * (long)sizeof(Student), SEEK_SET);
Student s;
*reads = 1;
if (fread(&s, sizeof s, 1, fp) != 1) return -1;
return s.roll == roll ? idx : -1;
}
int main(void) {
/* 50 records, rolls 101..150 */
FILE *fp = fopen("big.dat", "wb");
for (int i = 0; i < 50; i++) {
Student s = {101 + i, "", 60.0f + i};
snprintf(s.name, sizeof s.name, "Student%02d", i+1);
fwrite(&s, sizeof s, 1, fp);
}
fclose(fp);
fp = fopen("big.dat", "rb");
long reads;
printf("looking for roll 149:\n");
printf(" sequential: index %ld after %ld reads\n",
seq_find(fp, 149, &reads), reads);
printf(" direct : index %ld after %ld read\n",
direct_find(fp, 149, &reads), reads);
fclose(fp);
return 0;
}
Output:
looking for roll 149:
sequential: index 48 after 49 reads
direct : index 48 after 1 read
n × sizeof(Record) and its inverse size / sizeof(Record) are near-certain numericals — practise with SEEK_SET, SEEK_CUR and SEEK_END, including negative offsets. Know the three origin constants, that ftell after fseek(fp,0,SEEK_END) gives the file size, and that random access requires fixed-length records. Be ready to compare sequential O(n) with direct O(1) access and to say when sequential is still the right choice.Create a free account to tick topics off, take notes as you read, watch the video lessons and get a day-by-day study plan built around your exam date.
Loading…