1.0.2 2026-04-06 10:42 2026-04-13 10:42 submit-* (limit: 3 per week) archi-* (limit: 2 per hour) epita-prepa-computer-science-prog-104-p-03-2030-firstname.lastname
├── functional_market
│ ├── Fundamentals
│ │ ├── calculator.c
│ │ ├── calculator.h
│ │ ├── crepe_stream.c
│ │ ├── crepe_stream.h
│ │ ├── intro.c
│ │ ├── intro.h
│ │ ├── toolbox.c
│ │ └── toolbox.h
│ └── Proficiencies
│ ├── list.c
│ ├── list.h
│ ├── visitor.c
│ └── visitor.h
├── .gitignore
└── README
firstname.lastname with your login. .gitignore file is mandatory. Tests folder. .gitignore file:*.a
*.lib
*.o
*.obj
*.out
.idea/
*~
*.DotSettings.user
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
fundamentals/intro.c input to a function pointer computer.int compute(int input, int (*executor)(int));
int next(int n)
{
return n + 1;
}
#include <stdio.h>
int main(void)
{
int n = 3;
printf("compute(%d, &next) = %d\n", n, compute(n, &next));
}
compute(3, &next) = 4
name.# name = "Isabelle":
Hello Isabelle!
# name = "Tom Nook":
Hi Tom Nook.
# name = "Blathers":
Good night Blathers!
# name = "Mr. Resetti":
How are you doing Mr. Resetti?
# Anything else (including NULL):
I don't know you!
void (*greet(char *name))(void);
int main(int argc, char *argv[])
{
(void)argc;
(*greet(argv[1]))();
}
$ ./greet Isabelle
Hello Isabelle!
$ ./greet Toto
I don't know you!
fundamentals/calculator.c if, for, while or switch.operator and put it into your calculator.h.a and b depending on op.enum operation
{
ADD,
SUB,
MUL,
DIV,
MOD,
};
int calculator(int a, int b, enum operation op);
#include <stdio.h>
int main(void)
{
int a = 4;
int b = 6;
enum operation op = ADD;
printf("calculator(%d, %d, %d) = %d\n", a, b, op, calculator(a, b, op));
}
calculator(4, 6, 0) = 10
fundamentals/toolbox.c toolbox.h header file.data itself is allocated on the heap, not its elements.NULL array is treated as an empty array, not an error.data of an array is a void * is to allow any type of element,char * to have an easy access to each byte.char *data = arr->data;
char *second_element = data + arr->elem_size;
char *fifth_element = data + 4 * arr->elem_size; // Don't forget array indexes are zero-based
#include <stddef.h>
typedef int (*comparator)(void *, void *);
typedef void (*mapper)(void *, void *);
typedef int (*predicate)(void *);
typedef void *(*reducer)(void *, void *);
typedef void (*acceptor)(void *);
struct array
{
void *data;
size_t len;
size_t elem_size;
};
f on every element of arr.acceptor is a function that takes a pointer to an element of the array.void foreach(struct array *arr, acceptor f);
#include <stdio.h>
#include <stdlib.h>
void print_int(int *n)
{
printf("%d\n", *n);
}
int main(void)
{
struct array arr = {
.data = calloc(4, sizeof(int)),
.len = 4,
.elem_size = sizeof(int),
};
int *data = arr.data;
data[0] = 0;
data[1] = 1;
data[2] = 2;
data[3] = 3;
foreach(&arr, (acceptor)&print_int);
free(arr.data);
}
0
1
2
3
arr sorted according to f.comparator is a function that takes two pointers to elements of the array,arr must change, you MUST return arr.struct array *sort(struct array *arr, comparator f);
#include <stdio.h>
#include <stdlib.h>
int reverse(int *a, int *b)
{
return *b - *a;
}
void print_int(int *n)
{
printf("%d\n", *n);
}
int main(void)
{
struct array arr = {
.data = calloc(4, sizeof(int)),
.len = 4,
.elem_size = sizeof(int),
};
int *data = arr.data;
data[0] = 0;
data[1] = 1;
data[2] = 2;
data[3] = 3;
foreach(sort(&arr, (comparator)&reverse), (acceptor)&print_int);
free(arr.data);
}
3
2
1
0
arr mapped according to f.mapper is a function that takes two pointers.arr must change, you MUST return arr.arr->data, and free the previous one.output_size is the size of an element after mapping.arr with it!struct array *map(struct array *arr, size_t output_size, mapper f);
#include <stdio.h>
#include <stdlib.h>
void next(double *res, int *n)
{
*res = *n + 1;
}
void print_double(double *n)
{
printf("%.1lf\n", *n);
}
int main(void)
{
struct array arr = {
.data = calloc(4, sizeof(int)),
.len = 4,
.elem_size = sizeof(int),
};
int *data = arr.data;
data[0] = 0;
data[1] = 1;
data[2] = 2;
data[3] = 3;
foreach(map(&arr, sizeof(double), (mapper)&next), (acceptor)&print_double);
free(arr.data);
}
1.0
2.0
3.0
4.0
arr filtered according to if f is true.predicate is a function that takes a pointer to an element of the array, and returns a value:arr must change, you MUST return arr.struct array *filter(struct array *arr, predicate f);
#include <stdio.h>
#include <stdlib.h>
int odd(int *n)
{
return *n % 2;
}
void print_int(int *n)
{
printf("%d\n", *n);
}
int main(void)
{
struct array arr = {
.data = calloc(4, sizeof(int)),
.len = 4,
.elem_size = sizeof(int),
};
int *data = arr.data;
data[0] = 0;
data[1] = 1;
data[2] = 2;
data[3] = 3;
foreach(filter(&arr, (predicate)&odd), (acceptor)&print_int);
free(arr.data);
}
1
3
arr reduced by f.reducer is a function that takes two pointers.void *reduce(struct array *arr, void *start_value, reducer f);
#include <stdio.h>
#include <stdlib.h>
int *add(int *res, int *n)
{
*res += *n;
return res;
}
void print_int(int *n)
{
printf("%d\n", *n);
}
int main(void)
{
struct array arr = {
.data = calloc(4, sizeof(int)),
.len = 4,
.elem_size = sizeof(int),
};
int *data = arr.data;
data[0] = 0;
data[1] = 1;
data[2] = 2;
data[3] = 3;
int res = 0;
reduce(&arr, &res, (reducer)&add);
printf("%d\n", res);
free(arr.data);
}
6
fundamentals/crepe_stream.c MUST use your previous functions.enum dough
{
WHEAT,
BUCKWHEAT,
};
enum topping
{
NOTHING,
// Sweet
SUGAR,
CHOCOLATE,
WHIPPED_CREAM,
// Savory
CHEESE,
MEAT,
EGG,
};
struct crepe
{
char *name;
enum dough dough;
enum topping inside;
enum topping outside;
int price;
};
<name>: $<price>
- Made out of <dough>
- Contains <inside topping> with <outside topping> on top
void print_menu(struct array *arr);
#include <stdlib.h>
int main(void)
{
struct array arr = {
.elem_size = sizeof(struct crepe),
.len = 4,
.data = calloc(4, sizeof(struct crepe)),
};
struct crepe *data = arr.data;
data[0] = (struct crepe){
.name = "Dairy",
.dough = BUCKWHEAT,
.inside = CHEESE,
.outside = EGG,
.price = 5,
};
data[1] = (struct crepe){
.name = "Raclette",
.dough = BUCKWHEAT,
.inside = CHEESE,
.outside = MEAT,
.price = 8,
};
data[2] = (struct crepe){
.name = "Choco",
.dough = WHEAT,
.inside = CHOCOLATE,
.outside = WHIPPED_CREAM,
.price = 6,
};
data[3] = (struct crepe){
.name = "Sugary",
.dough = WHEAT,
.inside = SUGAR,
.outside = NOTHING,
.price = 7,
};
print_menu(&arr);
free(arr.data);
}
Dairy: $5
- Made out of buckwheat
- Contains cheese with egg on top
Raclette: $8
- Made out of buckwheat
- Contains cheese with meat on top
Choco: $6
- Made out of wheat
- Contains chocolate with whipped cream on top
Sugary: $7
- Made out of wheat
- Contains sugar with nothing on top
struct array *sort_by_prices(struct array *arr);
#include <stdlib.h>
int main(void)
{
struct array arr = {
.elem_size = sizeof(struct crepe),
.len = 4,
.data = calloc(4, sizeof(struct crepe)),
};
struct crepe *data = arr.data;
data[0] = (struct crepe){
.name = "Dairy",
.dough = BUCKWHEAT,
.inside = CHEESE,
.outside = EGG,
.price = 5,
};
data[1] = (struct crepe){
.name = "Raclette",
.dough = BUCKWHEAT,
.inside = CHEESE,
.outside = MEAT,
.price = 8,
};
data[2] = (struct crepe){
.name = "Choco",
.dough = WHEAT,
.inside = CHOCOLATE,
.outside = WHIPPED_CREAM,
.price = 6,
};
data[3] = (struct crepe){
.name = "Sugary",
.dough = WHEAT,
.inside = SUGAR,
.outside = NOTHING,
.price = 7,
};
print_menu(sort_by_prices(&arr));
free(arr.data);
}
Choco: $6
- Made out of wheat
- Contains chocolate with whipped cream on top
Raclette: $8
- Made out of buckwheat
- Contains cheese with meat on top
Sugary: $7
- Made out of wheat
- Contains sugar with nothing on top
Dairy: $5
- Made out of buckwheat
- Contains cheese with egg on top
struct array *names(struct array *arr);
#include <stdlib.h>
void print_string(char **str)
{
puts(*str);
}
int main(void)
{
struct array arr = {
.elem_size = sizeof(struct crepe),
.len = 4,
.data = calloc(4, sizeof(struct crepe)),
};
struct crepe *data = arr.data;
data[0] = (struct crepe){
.name = "Dairy",
.dough = BUCKWHEAT,
.inside = CHEESE,
.outside = EGG,
.price = 5,
};
data[1] = (struct crepe){
.name = "Raclette",
.dough = BUCKWHEAT,
.inside = CHEESE,
.outside = MEAT,
.price = 8,
};
data[2] = (struct crepe){
.name = "Choco",
.dough = WHEAT,
.inside = CHOCOLATE,
.outside = WHIPPED_CREAM,
.price = 6,
};
data[3] = (struct crepe){
.name = "Sugary",
.dough = WHEAT,
.inside = SUGAR,
.outside = NOTHING,
.price = 7,
};
foreach(names(&arr), (acceptor)&print_string);
free(arr.data);
}
Dairy
Raclette
Choco
Sugary
struct array *vegetarian(struct array *arr);
#include <stdlib.h>
int main(void)
{
struct array arr = {
.elem_size = sizeof(struct crepe),
.len = 4,
.data = calloc(4, sizeof(struct crepe)),
};
struct crepe *data = arr.data;
data[0] = (struct crepe){
.name = "Dairy",
.dough = BUCKWHEAT,
.inside = CHEESE,
.outside = EGG,
.price = 5,
};
data[1] = (struct crepe){
.name = "Raclette",
.dough = BUCKWHEAT,
.inside = CHEESE,
.outside = MEAT,
.price = 8,
};
data[2] = (struct crepe){
.name = "Choco",
.dough = WHEAT,
.inside = CHOCOLATE,
.outside = WHIPPED_CREAM,
.price = 6,
};
data[3] = (struct crepe){
.name = "Sugary",
.dough = WHEAT,
.inside = SUGAR,
.outside = NOTHING,
.price = 7,
};
print_menu(vegetarian(&arr));
free(arr.data);
}
Dairy: $5
- Made out of buckwheat
- Contains cheese with egg on top
Choco: $6
- Made out of wheat
- Contains chocolate with whipped cream on top
Sugary: $7
- Made out of wheat
- Contains sugar with nothing on top
int total_price(struct array *arr);
#include <stdlib.h>
int main(void)
{
struct array arr = {
.elem_size = sizeof(struct crepe),
.len = 4,
.data = calloc(4, sizeof(struct crepe)),
};
struct crepe *data = arr.data;
data[0] = (struct crepe){
.name = "Dairy",
.dough = BUCKWHEAT,
.inside = CHEESE,
.outside = EGG,
.price = 5,
};
data[1] = (struct crepe){
.name = "Raclette",
.dough = BUCKWHEAT,
.inside = CHEESE,
.outside = MEAT,
.price = 8,
};
data[2] = (struct crepe){
.name = "Choco",
.dough = WHEAT,
.inside = CHOCOLATE,
.outside = WHIPPED_CREAM,
.price = 6,
};
data[3] = (struct crepe){
.name = "Sugary",
.dough = WHEAT,
.inside = SUGAR,
.outside = NOTHING,
.price = 7,
};
printf("%d\n", total_price(&arr));
free(arr.data);
}
26
proficiencies/list.c NULL is considered an empty list.typedef void (*acceptor)(void*);
struct list
{
void *data;
struct list *next;
acceptor print;
acceptor free;
};
l is NULL, don't do anything and return.void push_front(struct list **l, void *data, acceptor p, acceptor f);
l is NULL or empty, don't do anything and return.void pop_front(struct list **l);
void do_nothing(void *n)
{
(void)n;
}
void print_long(void *n)
{
printf("%ld", (long)n);
}
void print_int(int *n)
{
printf("%d", *n);
}
int main(void)
{
struct list *l = NULL;
push_front(&l, (void *)18, &print_long, &do_nothing);
int *on_heap = calloc(1, sizeof(int));
*on_heap = 42;
push_front(&l, on_heap, (acceptor)&print_int, &free);
int on_stack = 4;
push_front(&l, &on_stack, (acceptor)&print_int, &do_nothing);
// print_list(l);
pop_front(&l);
pop_front(&l);
pop_front(&l);
}
// Nothing
void print_list(struct list *l);
void do_nothing(void *n)
{
(void)n;
}
void print_long(void *n)
{
printf("%ld", (long)n);
}
void print_int(int *n)
{
printf("%d", *n);
}
int main(void)
{
struct list *l = NULL;
push_front(&l, (void *)18, &print_long, &do_nothing);
int *on_heap = calloc(1, sizeof(int));
*on_heap = 42;
push_front(&l, on_heap, (acceptor)&print_int, &free);
int on_stack = 4;
push_front(&l, &on_stack, (acceptor)&print_int, &do_nothing);
print_list(l);
pop_front(&l);
pop_front(&l);
pop_front(&l);
}
4 -> 42 -> 18
l is NULL, don't do anything and return.void destroy_list(struct list **l);
void do_nothing(void *n)
{
(void)n;
}
void print_long(void *n)
{
printf("%ld", (long)n);
}
void print_int(int *n)
{
printf("%d", *n);
}
int main(void)
{
struct list *l = NULL;
push_front(&l, (void *)18, &print_long, &do_nothing);
int *on_heap = calloc(1, sizeof(int));
*on_heap = 42;
push_front(&l, on_heap, (acceptor)&print_int, &free);
int on_stack = 4;
push_front(&l, &on_stack, (acceptor)&print_int, &do_nothing);
print_list(l);
destroy_list(&l);
}
4 -> 42 -> 18
proficiencies/visitor.c ast_node are its operands, there may be 0, 1 or 2 depending on the type.enum node_type
{
// 0 operand
NUM,
// 1 operand
POS,
NEG,
// 2 operands
ADD,
SUB,
MUL,
DIV,
MOD,
};
struct ast_node
{
int value;
enum node_type type;
struct ast_node *children;
};
typedef void(*visitor)(struct ast_node *);
MUST NOT use any if, while, for or switch!v on node.void visit(struct ast_node *node, visitor v);
a as the first operandb as the second operandop as the operatorBinary operators:
(a op b)
Unary operators:
opa
Number:
a
void print_infix(struct ast_node *node);
int main(void)
{
struct ast_node node = {
.type = MUL,
.children =
(struct ast_node[]){
{
.type = NUM,
.value = 6,
},
{
.type = NEG,
.children =
(struct ast_node[]){
{
.type = NUM,
.value = 7,
},
},
},
},
};
print_infix(&node);
}
(6 * -7)
a as the first operandb as the second operandop as the operatorBinary operators:
op a b
Unary operators:
op a
Number:
a
void print_prefix(struct ast_node *node);
int main(void)
{
struct ast_node node = {
.type = MUL,
.children =
(struct ast_node[]){
{
.type = NUM,
.value = 6,
},
{
.type = NEG,
.children =
(struct ast_node[]){
{
.type = NUM,
.value = 7,
},
},
},
},
};
print_prefix(&node);
}
* 6 - 7
a as the first operandb as the second operandop as the operatorBinary operators:
a b op
Unary operators:
a op
Number:
a
void print_suffix(struct ast_node *node);
int main(void)
{
struct ast_node node = {
.type = MUL,
.children =
(struct ast_node[]){
{
.type = NUM,
.value = 6,
},
{
.type = NEG,
.children =
(struct ast_node[]){
{
.type = NUM,
.value = 7,
},
},
},
},
};
print_suffix(&node);
}
6 7 - *
1.0.2 ] 2026-04-07 18:00:00 visitor.c > print: specified adding a newline 1.0.1 ] 2026-04-06 19:00:00 Guidelines > Includes: added authorized includes