C
File I/O
Save and load data to/from files.
Saving tasks
The fourth lesson adds saving tasks to a file and loading them back. task_save writes the linked list to a text file; task_load reads the file and rebuilds the list.
task_save opens the file for writing with fopen, writes each task's name and priority with fprintf, and closes with fclose. task_load reads name and priority with fscanf, creates a task with task_new and inserts it with task_push_front. This is the basis of persistent storage; data survives in the file even when the program exits. The code from the previous lesson is included in the starting code.
Save and load
Saving and loading work together. Saving writes each task to a file; loading reads the file and rebuilds the list. Between the two you free the list for a clean start.
Flow: save with task_save(g_list, "tasks.txt");. Free the list and set g_list = NULL;. Then reload with task_load(&g_list, "tasks.txt");. Loading uses task_push_front, so the order reverses; this is the natural behavior of a linked list. This test confirms that save and load are symmetrical; you get back what you saved.
Exercise Add save and load
Write int task_save(const Task *list, const char *path); open with fopen(path, "w"), write with fprintf(f, "%s %d\n", ...), close with fclose(f). Write int task_load(Task **list, const char *path); open with fopen(path, "r"), read with fscanf(f, "%31s %d", ...), insert with task_push_front. In main add two tasks, call task_save(g_list, "tasks.txt");, free the list, call task_load(&g_list, "tasks.txt");, print the high count.
Show example solution
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Task {
char name[32];
int priority;
struct Task *next;
} Task;
Task *g_list = NULL;
Task *task_new(const char *name, int priority) {
Task *t = malloc(sizeof(Task));
strncpy(t->name, name, 31);
t->name[31] = '\0';
t->priority = priority;
t->next = NULL;
return t;
}
void task_push_front(Task **list, Task *t) {
t->next = *list;
*list = t;
}
void task_print(const Task *list) {
const Task *cur = list;
while (cur) {
printf("%s: %d\n", cur->name, cur->priority);
cur = cur->next;
}
}
typedef int (*TaskFilter)(const Task *);
int is_high_priority(const Task *t) {
return t->priority >= 3;
}
int task_count_if(const Task *list, TaskFilter filter) {
int count = 0;
const Task *cur = list;
while (cur) {
if (filter(cur)) count++;
cur = cur->next;
}
return count;
}
int task_save(const Task *list, const char *path) {
FILE *f = fopen(path, "w");
if (!f) return 0;
const Task *cur = list;
while (cur) {
fprintf(f, "%s %d\n", cur->name, cur->priority);
cur = cur->next;
}
fclose(f);
return 1;
}
int task_load(Task **list, const char *path) {
FILE *f = fopen(path, "r");
if (!f) return 0;
char name[32];
int priority;
while (fscanf(f, "%31s %d", name, &priority) == 2) {
task_push_front(list, task_new(name, priority));
}
fclose(f);
return 1;
}
int main(void) {
task_push_front(&g_list, task_new("Ödeme", 1));
task_push_front(&g_list, task_new("Paketle", 3));
task_save(g_list, "tasks.txt");
Task *cur = g_list;
while (cur) { Task *n = cur->next; free(cur); cur = n; }
g_list = NULL;
task_load(&g_list, "tasks.txt");
int high = task_count_if(g_list, is_high_priority);
printf("yüksek: %d\n", high);
return 0;
}
Test yourself
-
Which function does task_save use to write to a file?
Show answer
fprintf — fprintf writes formatted output to a file stream.
-
Match the file I/O functions
- fopen
- Open file
- fprintf
- Write to file
- fscanf
- Read from file
- fclose
- Close file
-
Complete the fopen call
FILE *f = fopen(____, "w");
Show answer
FILE *f = fopen(path, "w");
Next lesson: Putting it together