Functional logic
- C course
- Intermediate
- Lesson 114/116
- 6 min
Write business logic with function pointers and callbacks.
Counting with a filter
The third lesson adds conditional counting with a function pointer. The TaskFilter typedef defines the type of functions that test whether a task meets a condition.
You define the filter type with typedef int (*TaskFilter)(const Task *);. The is_high_priority function returns 1 if the priority is 3 or greater. The task_count_if function walks the list, tests each task with the filter, and returns the count of matches. This pattern is a fine example of callback-based abstraction; the same task_count_if can be called with different filters. The code from the previous lesson is included in the starting code.
task_count_if implementation
task_count_if takes a TaskFilter and tests each task as it walks the list. For each matching task it increments the counter.
Implementation: int count = 0; const Task *cur = list; while (cur) { if (filter(cur)) count++; cur = cur->next; } return count;. Here filter(cur) calls the filter function; if it returns true, the task is counted. This shows the power of function pointers; task_count_if does not know the filter implementation, it only calls it. The same function can be used with is_low_priority or is_named_payment. This is the same callback pattern as qsort in real libraries.
Practice Add counting with a filter
Define typedef int (*TaskFilter)(const Task *);. Write int is_high_priority(const Task *t) returning t->priority >= 3. Write int task_count_if(const Task *list, TaskFilter filter); walk and count with the filter. In main add two tasks, call task_print(g_list);, count with int high = task_count_if(g_list, is_high_priority); and print printf("yüksek: %d\n", high);.
Starter code
#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;
}
}
// TaskFilter türünü typedef ile tanımla
// is_high_priority fonksiyonunu yaz
// task_count_if fonksiyonunu yaz
// main'de yüksek öncelikli sayısını yazdır
int main(void) {
task_push_front(&g_list, task_new("Ödeme", 1));
task_push_front(&g_list, task_new("Paketle", 3));
task_print(g_list);
return 0;
}Sample 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 main(void) {
task_push_front(&g_list, task_new("Ödeme", 1));
task_push_front(&g_list, task_new("Paketle", 3));
task_print(g_list);
int high = task_count_if(g_list, is_high_priority);
printf("yüksek: %d\n", high);
return 0;
}Expected output
Paketle: 3 Ödeme: 1 yüksek: 1
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 Complete the is_high_priority condition
return t->priority >= ____;
return t->priority >= 3;
Explanation: t->priority >= 3 is the threshold for high priority.
2 Match the filter parts
| Term | Meaning |
|---|---|
TaskFilter |
Filter type |
is_high_priority |
High priority |
task_count_if |
Conditional count |
filter(cur) |
Callback call |
3 Why does task_count_if take a function pointer?
- So it can be called with different filters Correct answer
- To use less memory
- To run faster
- To avoid compiler warnings
Explanation: The function pointer lets the same function work with different filters.