1.0.0 2026-02-09 10:42 2026-02-16 10:42 submit-* (limit: 3 per week) archi-* (limit: 2 per hour) epita-prepa-computer-science-prog-103-p-04-2030-firstname.lastname
├── HolidayTrip
│ ├── Fundamentals
│ │ ├── my_strings
│ │ │ ├── Makefile
│ │ │ ├── main.c
│ │ │ ├── my_strings.c
│ │ │ └── my_strings.h
│ │ ├── radar
│ │ │ ├── Makefile
│ │ │ ├── main.c
│ │ │ ├── radar.c
│ │ │ └── radar.h
│ │ └── reap_and_tear
│ │ ├── Makefile
│ │ ├── demon.c
│ │ ├── demon.h
│ │ ├── main.c
│ │ ├── print.c
│ │ ├── villager.c
│ │ ├── villager.h
│ │ ├── weapons.c
│ │ └── weapons.h
│ └── Proficiencies
│ ├── animals
│ │ ├── Makefile
│ │ ├── animals.h
│ │ ├── fish.c
│ │ ├── insect.c
│ │ ├── main.c
│ │ ├── vector.c
│ │ └── vector.h
│ └── museum_restoration
│ ├── Makefile
│ ├── fossils.c
│ ├── fossils.h
│ └── main.c
├── .gitignore
└── README
firstname.lastname with your login. .gitignore file is mandatory. Tests folder. .gitignore file:*.a
*.lib
*.o
*.obj
*.out
.idea/
*~
*.DotSettings.user
<stddef.h>, <stdlib.h>, <stdio.h> and <string.h>.tar -xvf assets.tar.gz.structs to group variables and enums to represent states or constants.my_strings/my_strings.h \0 character.string and declares the set of functions (prototypes) you need to implement to make it work.char *data: A pointer to the character array (the actual string content).size_t size: The number of characters in the string.struct string
{
char *data;
size_t size;
};
struct string *my_str_init(const char* s, size_t size);
void my_str_destroy(struct string *str);
void my_str_puts(struct string *str);
struct string *my_str_n_cat(struct string *str1, const char *str2, size_t str2_len);
my_strings/my_strings.c malloc(3) and returns a pointer to it.size is zero or s is NULL, the data field is initialized to NULL and the size field to 0.data field with size bytes from s.my_strings.h header to use the struct string.s to data (shallow copy). The structure must own its own memory. Modifying the original string s afterwards should not affect your structure.struct string *my_str_init(const char* s, size_t size);
struct string *str = my_str_init("Hello World!", 12);
printf("data: %.*s\n", (int)str->size, str->data);
data: Hello World!
sizeof(struct string).str is NULL, the function does nothing.void my_str_destroy(struct string *str);
struct string *str = my_str_init("Hello World!", 12);
my_str_destroy(str);
(No output, just ensure there are no memory leaks with -fsanitize=address)
string structure to the standard output, followed by a newline.data field is NULL or the size is 0, it should simply print a newline.str pointer is NULL, the function does nothing.putchar(3) function.void my_str_puts(struct string *str);
struct string *str = my_str_init("Hello Alien World!", 18);
my_str_puts(str);
my_str_destroy(str);
Hello Alien World!
str2_len characters from str2 to the string structure.size field accordingly.string structure containing the concatenation.str1 is NULL, a new string structure must be initialized.str2 is NULL or the size is 0, no operation is performed.realloc(3) to resize the allocated memory.struct string *my_str_n_cat(struct string *str1, const char *str2, size_t str2_len);
struct string *str = my_str_init("Hello ", 6);
str = my_str_n_cat(str, "Alien World!", 13);
my_str_puts(str);
my_str_destroy(str);
Hello Alien World!
radar/radar.h radar.h file, you will find the definition of the struct point and the prototypes of the functions you need to implement.struct point
{
double x;
double y;
};
double compute_distance(struct point a, struct point b);
int is_in_area(struct point center, double radius, struct point point);
size_t detect_points(struct point center, double range, struct point* interesting_points, size_t nb_points);
radar/radar.c compute_distance to calculate the Euclidean distance between two points, a and b.math.h header-lm flag when compiling your code to link the math library.double compute_distance(struct point a, struct point b);
struct point p1 = { 0.0, 0.0 };
struct point p2 = { 3.0, 4.0 };
double dist = compute_distance(p1, p2);
printf("Distance: %.2f\n", dist);
Distance: 5.00
is_in_area that detects if a point is within the area defined by center and radius.int is_in_area(struct point center, double radius, struct point point);
struct point center = { 5.0, 5.0 };
double radius = 3.0;
struct point inside_point = { 7.0, 7.0 };
struct point outside_point = { 9.0, 9.0 };
int inside = is_in_area(center, radius, inside_point);
int outside = is_in_area(center, radius, outside_point);
printf("Inside: %d\n", inside);
printf("Outside: %d\n", outside);
Inside: 1
Outside: 0
interesting_points array of length nb_points to find locations within the specified range of the center."{x, y}\n"size_t detect_points(struct point center, double range, struct point *interesting_points, size_t nb_points);
struct point center = { 10.0, 10.0 };
double range = 5.0;
struct point points[] = {
{ 11.0, 11.0 },
{ 10.0, 10.0 },
{ 20.0, 20.0 },
{ 14.0, 13.0 }
};
size_t size = sizeof(points) / sizeof(struct point);
size_t found = detect_points(center, range, points, size);
printf("Total found: %zu\n", found);
{11.00, 11.00}
{10.00, 10.00}
{14.00, 13.00}
Total found: 3
reap_and_tear/weapons.h enum to approximate the range of weapons.enum distance
{
CLOSE,
NEAR,
FAR,
};
gun with the following attributes:name: A string of 50 characters at most (including the null terminator).damage: An int representing how much damage it deals.range: An enum distance representing the effective range.magazine_size: An int representing the maximum capacity.current_magazine: An int representing the current ammo count.struct gun *init_gun(char name[50], int damage, enum distance range, int magazine_size);
void reload(struct gun *gun);
void destroy_gun(struct gun *gun);
reap_and_tear/villager.h struct villager and the prototypes for their actions.struct demon (which isn't defined yet), you must add a forward declaration at the top of your file.struct demon;
struct villager represents the residents fighting alongside the Slayer.name: A string (max 50 chars) representing the villager's name.cur_HP: An int for current health points.HP_max: An int for maximum health points.gun: A pointer to a struct gun (can be NULL).gun_mastery: An int representing proficiency with firearms.medicines: An int representing the inventory count (Max 10).distance: An enum distance representing proximity to the demon.struct villager *init_villager(char name[50], int HP_max, struct gun *gun, int gun_mastery);
void pp_villager(struct villager *villager);
void destroy_villager(struct villager *villager);
void update_villager_hp(struct villager *villager, int amount);
void shoot(struct villager *villager, struct demon *demon);
void heal(struct villager *villager);
enum distance walk(struct villager *villager, int direction);
int prepare_medicine(struct villager *villager);
reap_and_tear/demon.h struct demon, the classification enum, and the AI prototypes.struct villager, ensure you have the proper forward declarations.struct villager;
enum demon_category
{
PARASITE = 1,
THREAT,
NIGHTMARE,
CALAMITY,
TOM_NOOK
};
struct demon with the following attributes:category: An enum demon_category representing the type.name: A string (max 50 chars).damage: An int for base damage.range: An enum distance for attack range.cur_HP: An int for current health.HP_max: An int for maximum health.struct demon *init_demon(enum demon_category category, char name[50], int HP_max, int damage, enum distance range);
void pp_demon(struct demon *demon);
void destroy_demon(struct demon *demon);
void basic_attack(struct demon *demon, struct villager *target);
void draining_attack(struct demon *demon, struct villager *target);
void heavy_attack(struct demon *demon, struct villager *target);
void chase(struct demon *demon, struct villager *villager);
void update_demon_hp(struct demon *demon, int amount);
void demon_action(struct demon *demon, struct villager *villager);
reap_and_tear/weapons.c struct gun.name argument into the structure.damage, range, and magazine_size with the provided arguments.current_magazine to be equal to magazine_size (a new gun is always fully loaded).strcpy(3) to copy strings.struct gun *init_gun(char name[50], int damage, enum distance range, int magazine_size);
char gun_name[50] = "BFG";
struct gun *gun = init_gun(gun_name, 50, FAR, 16);
printf("Gun name: %s\nDamage: %d\nRange: %d\nMagazine: %d/%d\n", gun->name,
gun->damage, gun->range, gun->current_magazine, gun->magazine_size);
Gun name: BFG
Damage: 50
Range: 2
Magazine: 16/16
current_magazine value to be equal to the magazine_size.gun pointer is NULL, the function does nothing.void reload(struct gun *gun);
char gun_name[50] = "BFG";
struct gun *gun = init_gun(gun_name, 50, FAR, 16);
gun->current_magazine = 2;
printf("Before reload: %d\n", gun->current_magazine);
reload(gun);
printf("After reload: %d\n", gun->current_magazine);
Before reload: 2
After reload: 16
gun structure.gun pointer is NULL, the function does nothing.void destroy_gun(struct gun *gun);
reap_and_tear/villager.c init_villager allocates and returns a pointer to a struct villager initialized with the given attributes.medicines must be set to 10.distance must be set to NEAR.cur_HP must be initialized to HP_max.struct villager *init_villager(char name[50], int HP_max, struct gun *gun, int gun_mastery);
amount from the villager's HP (can be negative for healing)."You died.\n"HP_maxvillager pointer is NULL, the function does nothing.void update_villager_hp(struct villager *villager, int amount);
char name[50] = "Isabelle";
char gun_name[50] = "BFG";
struct gun *gun = init_gun(gun_name, 50, FAR, 16);
struct villager *villager =
init_villager(name, 50, gun, 1);
update_villager_hp(villager, 100);
You died.
villager pointer is NULL, the function does nothing.void destroy_villager(struct villager *villager);
reap_and_tear/print.c villager pointer is NULL, the function does nothing.============================= Villager info =============================
Name: {name}
HP: {current_HP}/{HP_max}
Gun: {Gun_name} | Magazine: {current_magazine}/{magazine_size} | Mastery: {gun_mastery}
Medicine: {current_medicine}/10
Distance: {distance}
\n.distance, print Close, Near or Far depending on the distance of the villager.void pp_villager(struct villager* villager);
char name[50] = "Isabelle";
char gun_name[50] = "BFG";
struct gun *gun = init_gun(gun_name, 50, FAR, 16);
struct villager *villager = init_villager(name, 50, gun, 1);
pp_villager(villager);
destroy_villager(villager);
============================= Villager info =============================
Name: Isabelle
HP: 50/50
Gun: BFG | Magazine: 16/16 | Mastery: 1
Medicine: 10/10
Distance: Near
reap_and_tear/demon.c init_demon function returns a pointer to a struct demon with the given attribute.HP_max and damage of the demon by their category (that's why we wanted it to start at 1 and not 0).cur_HP must be initialized to HP_max.struct demon *init_demon(enum demon_category category, char name[50], int HP_max, int damage, enum distance range);
amount from the demon's HP."You killed the demon {demon_name} !!\n"demon pointer is NULL, the function does nothing.void update_demon_hp(struct demon *demon, int amount);
char demon_name[50] = "Cyberdemon";
struct demon *demon = init_demon(NIGHTMARE, demon_name, 40, 5, CLOSE);
update_demon_hp(demon, 200);
You killed the demon Cyberdemon !!
demon structure.demon pointer is NULL, the function does nothing.void destroy_demon(struct demon *demon);
reap_and_tear/print.c demon pointer is NULL, the function does nothing.============================= Demon info =============================
Name: {name} | Category: {category}
Base damage: {damage} | Range: {range}
HP: {current_HP}/{HP_max}
\n.category, print Parasite, Threat, Nightmare, Calamity or Tom Nook depending on the category of the demon.range, print Close, Near or Far depending on the range of the demon.void pp_demon(struct demon* demon);
char demon_name[50] = "Cyberdemon";
struct demon *demon = init_demon(NIGHTMARE, demon_name, 40, 5, CLOSE);
pp_demon(demon);
============================= Demon info =============================
Name: Cyberdemon | Category: Nightmare
Base damage: 15 | Range: Close
HP: 120/120
reap_and_tear/villager.c shoot function fires a shot with the gun that the villager is equipped with and lower the current_magazine of the gun by one.gun attribute is NULL) display the message "Equip a gun before trying to use one.\n" and return."Empty gun : You gotta reload.\n" and return.current_magazine by 1 and then :"No demon in range.\n" (use the villager's distance attribute and the gun's range attribute )damage of the weapon + the gun_mastery, the minimum damage you can deal is 0. Then display the message "BAM! {name_of_the_demon} lost {number_of_damage} HP.\n"villager or demon pointer are NULL, the function does nothing.void shoot(struct villager *villager, struct demon *demon);
char name[50] = "Isabelle";
char gun_name[50] = "BFG";
struct gun *gun = init_gun(gun_name, 50, FAR, 16);
struct villager *villager =
init_villager(name, 50, gun, 1);
// Init demon
char demon_name[50] = "Cyberdemon";
struct demon *demon = init_demon(NIGHTMARE, demon_name, 40, 5, CLOSE);
// // Shoot
shoot(villager, demon);
pp_villager(villager);
pp_demon(demon);
destroy_demon(demon);
destroy_villager(villager);
BAM! Cyberdemon lost 51 HP.
============================= Villager info =============================
Name: Isabelle
HP: 50/50
Gun: BFG | Magazine: 15/16 | Mastery: 1
Medicine: 10/10
Distance: Near
============================= Demon info =============================
Name: Cyberdemon | Category: Nightmare
Base damage: 15 | Range: Close
HP: 69/120
"No medicine left, maybe prepare some ?\n"1.HP_max (rounded down). Ensure cur_HP does not exceed HP_max."Nice, you healed {amount_healed} HP.\n"villager pointer is NULL, the function does nothing.void heal(struct villager *villager);
char name[50] = "Isabelle";
char gun_name[50] = "BFG";
struct gun *gun = init_gun(gun_name, 50, FAR, 16);
struct villager *villager =
init_villager(name, 50, gun, 1);
// Heal
villager->cur_HP -= 40;
pp_villager(villager);
putchar('\n');
heal(villager);
pp_villager(villager);
destroy_villager(villager);
============================= Villager info =============================
Name: Isabelle
HP: 10/50
Gun: BFG | Magazine: 16/16 | Mastery : 1
Medicine: 10/10
Distance: Near
Nice, you healed 12 HP.
============================= Villager info =============================
Name: Isabelle
HP: 22/50
Gun: BFG | Magazine: 16/16 | Mastery : 1
Medicine: 9/10
Distance: Near
direction integer."Too close.\n""I can't run away.\n""You decided to move.\n". A movement is considered successful if the villager actually moved.distance (enum).villager pointer is NULL, the function does nothing and return NEAR.enum distance walk(struct villager *villager, int direction);
char name[50] = "Isabelle";
char gun_name[50] = "BFG";
struct gun *gun = init_gun(gun_name, 50, FAR, 16);
struct villager *villager =
init_villager(name, 50, gun, 1);
// Walk
pp_villager(villager);
putchar('\n');
walk(villager, 1);
pp_villager(villager);
destroy_villager(villager);
============================= Villager info =============================
Name: Isabelle
HP: 50/50
Gun: BFG | Magazine: 16/16 | Mastery : 1
Medicine: 10/10
Distance: Near
You decided to move.
============================= Villager info =============================
Name: Isabelle
HP: 50/50
Gun: BFG | Magazine: 16/16 | Mastery : 1
Medicine: 10/10
Distance: Close
"Preparation ready !\n"villager pointer is NULL, the function does nothing and return 0.int prepare_medicine(struct villager *villager);
// Init Villager
char name[50] = "Isabelle";
char gun_name[50] = "BFG";
struct gun *gun = init_gun(gun_name, 50, FAR, 16);
struct villager *villager =
init_villager(name, 50, gun, 1);
// Prepare Medicine
villager->medicines -= 5;
pp_villager(villager);
prepare_medicine(villager);
pp_villager(villager);
destroy_villager(villager);
============================= Villager info =============================
Name: Isabelle
HP: 50/50
Gun: BFG | Magazine: 16/16 | Mastery: 1
Medicine: 5/10
Distance: Near
Preparation ready !
============================= Villager info =============================
Name: Isabelle
HP: 50/50
Gun: BFG | Magazine: 16/16 | Mastery: 1
Medicine: 6/10
Distance: Near
reap_and_tear/demon.c distance attribute of the villager:FAR, change it to NEAR.NEAR, change it to CLOSE.CLOSE, the distance does not change."The demon {demon_name} is chasing you.\n"villager or demon pointer are NULL, the function does nothing.void chase(struct demon *demon, struct villager *villager);
// Init Villager
char name[50] = "Isabelle";
char gun_name[50] = "BFG";
struct gun *gun = init_gun(gun_name, 50, FAR, 16);
struct villager *villager =
init_villager(name, 50, gun, 1);
// Init demon
char demon_name[50] = "Cyberdemon";
struct demon *demon = init_demon(NIGHTMARE, demon_name, 40, 5, CLOSE);
// Chase
pp_villager(villager);
chase(demon, villager);
pp_villager(villager);
destroy_villager(villager);
destroy_demon(demon);
============================= Villager info =============================
Name: Isabelle
HP: 50/50
Gun: BFG | Magazine: 16/16 | Mastery: 1
Medicine: 10/10
Distance: Near
The demon Cyberdemon is chasing you.
============================= Villager info =============================
Name: Isabelle
HP: 50/50
Gun: BFG | Magazine: 16/16 | Mastery: 1
Medicine: 10/10
Distance: Close
damage attribute to the target if he is in range."RAAAAAGH! {name_of_the_demon} attacks you to deal {number_of_damage} damage.\n"target or demon pointer are NULL, the function does nothing.void basic_attack(struct demon *demon, struct villager *target);
// Init Villager
char name[50] = "Isabelle";
char gun_name[50] = "BFG";
struct gun *gun = init_gun(gun_name, 50, FAR, 16);
struct villager *villager =
init_villager(name, 50, gun, 1);
// Init demon
char demon_name[50] = "Cyberdemon";
struct demon *demon = init_demon(NIGHTMARE, demon_name, 40, 5, FAR);
// Basic attack
basic_attack(demon, villager);
pp_villager(villager);
destroy_villager(villager);
destroy_demon(demon);
RAAAAAGH! Cyberdemon attacks you to deal 15 damage.
============================= Villager info =============================
Name: Isabelle
HP: 35/50
Gun: BFG | Magazine: 16/16 | Mastery: 1
Medicine: 10/10
Distance: Near
"SLURRRRP! {name_of_the_demon} attacks you to deal {number_of_damage} damage and regenerates {number_of_regenerated_hp} HP.\n"target or demon pointer are NULL, the function does nothing.void draining_attack(struct demon *demon, struct villager *target);
// Init Villager
char name[50] = "Isabelle";
char gun_name[50] = "BFG";
struct gun *gun = init_gun(gun_name, 50, FAR, 16);
struct villager *villager =
init_villager(name, 50, gun, 1);
// Init demon
char demon_name[50] = "Cyberdemon";
struct demon *demon = init_demon(NIGHTMARE, demon_name, 40, 5, FAR);
// Draining attack
demon->cur_HP -= 10;
draining_attack(demon, villager);
pp_villager(villager);
pp_demon(demon);
destroy_demon(demon);
destroy_villager(villager);
SLURRRRP! Cyberdemon attacks you to deal 7 damage and regenerates 3 HP.
============================= Villager info =============================
Name: Isabelle
HP: 43/50
Gun: BFG | Magazine: 16/16 | Mastery: 1
Medicine: 10/10
Distance: Near
============================= Demon info =============================
Name: Cyberdemon | Category: Nightmare
Base damage: 15 | Range: Far
HP: 113/120
double damage to the target, but the demon takes some recoil damage (10% of its own max HP)."BAM! {demon name} attacks you with all his strength to deal {nb of dommage} damage.\n"target or demon pointer are NULL, the function does nothing.void heavy_attack(struct demon *demon, struct villager *target);
// Init Villager
char name[50] = "Isabelle";
char gun_name[50] = "BFG";
struct gun *gun = init_gun(gun_name, 50, FAR, 16);
struct villager *villager =
init_villager(name, 50, gun, 1);
// Init demon
char demon_name[50] = "Cyberdemon";
struct demon *demon = init_demon(NIGHTMARE, demon_name, 40, 5, FAR);
// Heavy attack
heavy_attack(demon, villager);
pp_villager(villager);
pp_demon(demon);
destroy_demon(demon);
destroy_villager(villager);
BAM! Cyberdemon attacks you with all his strength to deal 30 damage.
============================= Villager info =============================
Name: Isabelle
HP: 20/50
Gun: BFG | Magazine: 16/16 | Mastery : 1
Medicine: 10/10
Distance: Near
============================= Demon info =============================
Name: Cyberdemon | Category: Nightmare
Base damage: 15 | Range: Far
HP: 108/120
villager or demon pointer are NULL, the function does nothing.void demon_action(struct demon *demon, struct villager *villager);
// Init Villager
char name[50] = "Isabelle";
char gun_name[50] = "BFG";
struct gun *gun = init_gun(gun_name, 50, FAR, 16);
struct villager *villager =
init_villager(name, 500, gun, 1);
// Init demon
char demon_name[50] = "Cyberdemon";
struct demon *demon = init_demon(NIGHTMARE, demon_name, 40, 5, CLOSE);
// Demon action
demon_action(demon, villager); // Distance = Near but its range is close
demon_action(demon, villager); // In range and high HP
demon->cur_HP = demon->HP_max / 2;
demon_action(demon, villager); // In range and mid HP
demon->cur_HP = 1;
demon_action(demon, villager); // In range and low HP
destroy_villager(villager);
destroy_demon(demon);
The demon Cyberdemon is chasing you.
BAM! Cyberdemon attacks you with all his strength to deal 30 damage.
RAAAAAGH! Cyberdemon attack you to deal 15 damage.
SLURRRRP! Cyberdemon attack you to deal 7 damage and regenerates 3 HP.
s to shoot with you gun.r to reload your gun.h to heal yourself.p to prepare medicine.w+ to walk towards the demon.w- to walk away from the demon.main.c and run your program.main function, otherwise you won't be able to compile#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "demon.h"
#include "villager.h"
#include "weapons.h"
#define PURPLE(string) "\x1b[35m" string "\x1b[0m"
#define MAX_BUFFER 1024
void villager_action(struct villager *villager, struct demon *demon, char *command)
{
if (!strcmp(command, "s"))
{
shoot(villager, demon);
}
else if (!strcmp(command, "r"))
{
printf("You reload your gun");
reload(villager->gun);
}
else if (!strcmp(command, "h"))
{
heal(villager);
}
else if (!strcmp(command, "w+"))
{
walk(villager, 1);
}
else if (!strcmp(command, "w-"))
{
walk(villager, -1);
}
else if (!strcmp(command, "p"))
{
prepare_medicine(villager);
}
else
printf(PURPLE("No such action\n"));
}
static void end_fight(struct villager *villager, struct demon *demon)
{
if (villager->cur_HP <= 0 || demon->cur_HP <= 0)
{
pp_villager(villager);
pp_demon(demon);
destroy_villager(villager);
destroy_demon(demon);
exit(0);
}
}
int main()
{
printf("\033[2J\033[1;1H");
// Init gun and villager
char name[50] = "Isabelle";
char gun_name[50] = "BFG";
struct gun *gun = init_gun(gun_name, 50, FAR, 16);
struct villager *villager =
init_villager(name, 50, gun, 1);
// Init demon
char demon_name[50] = "Cyberdemon";
struct demon *demon = init_demon(NIGHTMARE, demon_name, 40, 5, CLOSE);
pp_villager(villager);
pp_demon(demon);
char input[MAX_BUFFER];
while (fgets(input, MAX_BUFFER, stdin) != NULL)
{
printf("\033[2J\033[1;1H");
int i = 0;
while (input[i] != '\0')
{
if (input[i] == '\n')
{
input[i] = '\0';
break;
}
i++;
}
printf("\x1b[34m");
villager_action(villager, demon, input);
printf("\x1b[0m");
end_fight(villager, demon);
printf("\x1b[31m");
demon_action(demon, villager);
printf("\x1b[0m");
end_fight(villager, demon);
pp_villager(villager);
pp_demon(demon);
printf("> ");
}
destroy_demon(demon);
destroy_villager(villager);
return 0;
}
unions. Since this concept wasn't covered in class, we will explore it here.union is similar to a struct, but with a key difference: all its members share the same memory space. This means only one member can be stored (or "active") at a time.enums (a pattern called a Tagged Union). The enum acts as a "tag" to indicate which member of the union is currently set. Using this tag, you can safely determine which attribute to access.animals/animals.h enum animal_type
{
INSECT,
FISH,
};
struct fish
{
char* species;
int swimming_speed;
size_t size;
int lives_in_fresh_water;
};
struct insect
{
char* species;
size_t size;
int can_fly;
int can_swim;
};
union animals
{
struct insect* insect;
struct fish* fish;
};
struct animal
{
enum animal_type type;
union animals animal;
char* color;
};
struct fish* fish_init(const char* species, int speed, size_t size, int fresh_water);
struct animal* animal_from_fish(const char* color, struct fish* fish);
void free_fish(struct fish* fish);
struct insect *insect_init(const char *species, size_t size, int can_fly, int can_swim);
struct animal* animal_from_insect(const char* color, struct insect* insect);
void free_insect(struct insect* insect);
void free_animal(struct animal* animal);
struct animal uses a Union to store data. Unlike a struct where every field exists in memory at once, a union uses a single shared memory space for all its fields.struct animal can hold a struct fish* OR a struct insect*, but never both at the same time.type attribute of the animal to the correct enum value (e.g., FISH). This tells the program "The data currently stored in the union is a fish".value or data) and assign your pointer to the specific member: animal->data.fish = fish;.my_animal->animal.fish.animals/fish.c struct animal using unions.struct fish with the given argument.species string.strdup(3) to malloc and copy strings.struct fish *fish_init(const char *species, int speed, size_t size, int fresh_water);
struct fish *f = fish_init("Salmon", 10, 5, 1);
printf("Fish species: %s\n", f->species);
printf("Swimming speed: %d\n", f->swimming_speed);
printf("Size: %zu\n", f->size);
printf("Lives in fresh water: %d\n", f->lives_in_fresh_water);
Fish species: Salmon
Swimming speed: 10
Size: 5
Lives in fresh water: 1
struct animal from a specific struct fish.color string.NULL, do nothing and return NULL.struct animal *animal_from_fish(const char *color, struct fish *fish);
struct fish *f = fish_init("Trout", 8, 4, 1);
struct animal *a = animal_from_fish("Blue", f);
printf("Animal type: %d\n", a->type);
printf("Animal color: %s\n", a->color);
printf("Fish species from animal: %s\n", a->animal.fish->species);
Animal type: 1
Animal color: Blue
Fish species from animal: Trout
struct fish.fish pointer is NULL, the function does nothing.void free_fish(struct fish *fish);
struct fish *f = fish_init("Carp", 6, 3, 0);
free_fish(f);
(No output, just ensure no memory leaks occur with -fsanitize=address)
animals/insect.c struct animal.struct insect.species string.struct insect *insect_init(const char *species, size_t size, int can_fly, int can_swim);
struct insect *i = insect_init("Dragonfly", 2, 1, 0);
printf("Insect species: %s\n", i->species);
printf("Size: %zu\n", i->size);
printf("Can fly: %d\n", i->can_fly);
printf("Can swim: %d\n", i->can_swim);
Insect species: Dragonfly
Size: 2
Can fly: 1
Can swim: 0
struct animal from a specific struct insect.color string.NULL, do nothing and return NULL.struct animal *animal_from_insect(const char *color, struct insect *insect);
struct insect *i = insect_init("Butterfly", 1, 1, 0);
struct animal *a = animal_from_insect("Yellow", i);
printf("Animal type: %d\n", a->type);
printf("Animal color: %s\n", a->color);
printf("Insect species from animal: %s\n", a->animal.insect->species);
Animal type: 0
Animal color: Yellow
Insect species from animal: Butterfly
struct insect.insect pointer is NULL, the function does nothing.void free_insect(struct insect *insect);
struct insect *i = insect_init("Beetle", 3, 0, 1);
free_insect(i);
(No output, just ensure no memory leaks occur with -fsanitize=address)
animals/vector.h struct vector and the interface to manipulate it.struct vector
{
struct animal **animal;
size_t size;
size_t capacity;
};
struct vector *vector_init(size_t n);
struct vector *vector_resize(struct vector *v, size_t new_capacity);
struct vector *vector_append(struct vector *v, struct animal *animal);
void vector_destroy(struct vector *v);
int tab[10];, you cannot store an 11th element without causing a buffer overflow.realloc is computationally expensive (it may need to copy the whole array to a new memory location). size reaches the capacity (the vector is full), we don't just add +1 slot. Instead, we typically double the capacity. This minimizes the number of times we need to ask the system for more memory.animals/vector.c capacity of n.struct vector.size to 0.capacity to n.struct vector *vector_init(size_t n);
struct vector *v = vector_init(5);
printf("Initial size: %zu\n", v->size);
printf("Initial capacity: %zu\n", v->capacity);
Initial size: 0
Initial capacity: 5
capacity of the vector to new_capacity.realloc to resize the internal animal array to the new capacity.capacity attribute of the structure.vector pointer is NULL, the function does nothing and return NULL.struct vector *vector_resize(struct vector *v, size_t new_capacity);
struct vector *v = vector_init(2);
v = vector_resize(v, 4);
printf("Resized capacity: %zu\n", v->capacity);
Resized capacity: 4
animal to the end of the list and updates the size.vector_resize to double the current capacity.animal pointer at the correct index.size.struct vector *vector_append(struct vector *v, struct animal *animal);
struct vector *v = vector_init(2);
struct fish *f1 = fish_init("Salmon", 10, 5, 1);
struct animal *a1 = animal_from_fish("Blue", f1);
v = vector_append(v, a1);
struct fish *f2 = fish_init("Trout", 8, 4, 1);
struct animal *a2 = animal_from_fish("Green", f2);
v = vector_append(v, a2);
struct fish *f3 = fish_init("Carp", 6, 3, 0);
struct animal *a3 = animal_from_fish("Red", f3);
v = vector_append(v, a3);
printf("Vector size after appends: %zu\n", v->size);
printf("Vector capacity after appends: %zu\n", v->capacity);
Vector size after appends: 3
Vector capacity after appends: 4
struct animal.type attribute (the Tag) to know which specific free function to call:FISH: Call free_fish on the specific union member.INSECT: Call free_insect on the specific union member.color string, and finally the animal structure itself.void free_animal(struct animal *animal);
struct fish *f = fish_init("Salmon", 10, 5, 1);
struct animal *a = animal_from_fish("Blue", f);
free_animal(a);
(No output, just ensure no memory leaks occur with -fsanitize=address)
void vector_destroy(struct vector *v);
struct vector *v = vector_init(5);
struct fish *f = fish_init("Trout", 8, 4, 1);
struct animal *a = animal_from_fish("Green", f);
v = vector_append(v, a);
vector_destroy(v);
(No output, just ensure no memory leaks occur with -fsanitize=address)
museum_restoration/fossils.h enum body_part
{
SKULL,
TORSO,
TAIL,
WINGS,
LEGS,
COMPLETE,
};
struct fossil with the following attributes:species: char* representing the name of the species.body_part: enum body_part indicating which part this is (or COMPLETE).age: size_t representing the fossil's age in thousands of years (e.g., 10 = 10,000 years).has_wings: char acting as a boolean (1 if the species should have wings, 0 otherwise).struct fossil *init_fossil(char *species, enum body_part body_part, size_t age, char has_wings);
struct fossil *assemble_wingless(struct fossil *fossils[4]);
struct fossil *assemble_with_wings(struct fossil *fossils[5]);
struct fossil **assemble_all_fossils(struct fossil **fossils, size_t nb_fossils);
museum_restoration/fossils.c struct fossil initialized with the given attributes.species string and copy the provided string into it.struct fossil *init_fossil(char *species, enum body_part body_part, size_t age, char has_wings);
struct fossil.has_wings == 0. If not, return NULL.species and age.SKULL, TORSO, TAIL, LEGS.COMPLETE fossil (same age/species). You MUST free the 4 input parts and set their pointers to NULL in the array.NULL (do not free anything).struct fossil *assemble_wingless(struct fossil *fossils[4]);
struct fossil.has_wings != 0. If not, return NULL.species and age.SKULL, TORSO, TAIL, LEGS, WING.COMPLETE fossil. You MUST free the 5 input parts and set their pointers to NULL.NULL.struct fossil *assemble_with_wings(struct fossil *fossils[5]);
fossils) and its size (nb_fossils).COMPLETE fossils in a new array.NULL-terminated array containing pointers to all the completed fossils.struct fossil **assemble_all_fossils(struct fossil **fossils, size_t nb_fossils);