"C programming can be quite tedious without access to the highly useful standard functions. This project aims to help you understand how these functions work by implementing them yourself..."
— Your libft.pdf Subject
This project is my very first C library, a rite of passage at 42 School. It's a collection of re-coded libc functions, plus other useful utilities that I'll carry with me throughout my C projects.
##What's Inside?
This library is divided into three parts, just like the subject demands:
These are my own implementations of standard C functions. The goal was to perfectly mimic the behavior (and protect against the same errors) as the originals.
| Character Tests | Memory Functions | String Functions |
|---|---|---|
ft_isalpha |
ft_memset |
ft_strlen |
ft_isdigit |
ft_bzero |
ft_strlcpy |
ft_isalnum |
ft_memcpy |
ft_strlcat |
ft_isascii |
ft_memmove |
ft_strchr |
ft_isprint |
ft_memchr |
ft_strrchr |
ft_toupper |
ft_memcmp |
ft_strncmp |
ft_tolower |
ft_calloc |
ft_strnstr |
ft_atoi |
ft_strdup |
These functions are not in the standard libc but are incredibly useful. This is where memory allocation (malloc) becomes critical.
| String Manipulation | Conversion & Output |
|---|---|
ft_substr |
ft_itoa |
ft_strjoin |
ft_putchar_fd |
ft_strtrim |
ft_putstr_fd |
ft_split |
ft_putendl_fd |
ft_strmapi |
ft_putnbr_fd |
ft_striteri |
This project wasn't just about coding functions. It was a deep dive into the why of C. Here are the biggest lessons I learned.
This project is where you truly face memory for the first time.
Memory Layout Example:
ft_memcpy - Fast but undefined with overlap:
┌─────┬─────┬─────┬─────┬─────┐
│src[0]│src[1]│ OVERLAP ZONE │dst[4]│
└─────┴─────┴─────┴─────┴─────┘
ft_memmove - Safe with overlap detection: ┌─────┬─────┬─────┬─────┬─────┐ │src[0]│src[1]│ OVERLAP ZONE │dst[4]│ └─────┴─────┴─────┴─────┴─────┘ ✓ Checks direction and copies safely
**Key Concepts:**
| Concept | Explanation |
|---------|-------------|
| **`unsigned char *` casting** | Ensures byte-by-byte operations regardless of data type |
| **`ft_calloc` overflow check** | `if (nmemb > SIZE_MAX / size)` prevents integer overflow attacks |
| **`dest > src` check** | Determines copy direction to prevent data corruption in `ft_memmove` |
#### Reflection Point
**My biggest challenge in the memory functions was...**
> *Example: handling the `(unsigned char *)` casts correctly to avoid pointer arithmetic issues.*
**The `ft_calloc` overflow check taught me that...**
> *Example: security isn't just about NULL checks, but also about preventing integer overflows that lead to allocating the wrong amount of memory and causing a heap overflow.*
---
### 2. The Nightmare of C-Strings (And How to Survive It)
I learned that a "string" in C is just a `char*` with a `\0` at the end, and that concept is both simple and incredibly dangerous.
#### My second Big Moment of realisation: Why `ft_strlcpy` and `ft_strlcat` are safer
String Safety Comparison:
❌ UNSAFE ✅ SAFE ALTERNATIVE strcpy(dest, src) → ft_strlcpy(dest, src, size) strcat(dest, src) → ft_strlcat(dest, src, size)
Why? They take the full buffer size as an argument, guaranteeing NUL-termination and preventing buffer overflows.
#### Reflection Point
**My `ft_split` function wasn't just about finding a delimiter. It was a masterclass in...**
> *Example: complex memory management. I had to allocate the main array `char**`, then allocate each individual string `char*`. The most critical part was the error handling: if any single allocation failed, my `ft_memfree` helper had to go back and free everything I had already allocated to prevent a massive memory leak.*
---
### 3. Pointing at Functions (Like a Boss)
Part 2 and the Bonus introduced me to one of C's most powerful (and weirdest) features: function pointers.
#### My third Big Moment of realisation: The `ft_striteri` vs. `ft_strmapi` challenge
```c
// ft_striteri - Modifies in-place
void ft_striteri(char *s, void (*f)(unsigned int, char*));
// Takes char* - can modify the original string
// s is NOT const
// ft_strmapi - Creates new string
char *ft_strmapi(char const *s, char (*f)(unsigned int, char));
// Takes char (by value) - creates new content
// s IS const - never changes original
Function Pointer Comparison:
| Function | Signature | Purpose |
|---|---|---|
ft_striteri |
void (*f)(unsigned int, char*) |
Modifies original string in-place |
ft_strmapi |
char (*f)(unsigned int, char) |
Creates new string, original stays const |
ft_lstmap |
void *(*f)(...), void (*del)(...) |
Two pointers: one to transform, one to clean up on failure |
The bonus ft_lstmap function took this to another level. It needed two function pointers, f and del, because...
Example:
fwas needed to create the new content for each new list node, but if an allocation failed mid-way, I needed thedelfunction to properly free the content of all the nodes I had already created for the new list. It was the ultimate test of leak-proof design.
This wasn't just a collection of .c files. It's a library.
Makefile Compilation Flow:
┌──────────┐ ┌──────────┐ ┌──────────┐
│ *.c │ --> │ %.o: %.c │ --> │ *.o │
│ files │ │ (rule) │ │ files │
└──────────┘ └──────────┘ └──────────┘
│
v
┌──────────┐
│ ar rcs │
│ command │
└──────────┘
│
v
┌──────────┐
│ libft.a │
│ (archive)│
└──────────┘
What each step does:
%.o: %.crule: Pattern rule that teaches make how to compile any.cfile into an object (.o) file$(NAME): $(OBJS)rule: Gathers all those.ofilesar rcs $(NAME) $(OBJS): Builds the static library (.afile = "archive") from all object files
git clone https://github.com/your-username/your-repo-name.git
cd your-repo-namemakeThis will create the libft.a file.
When compiling your project, you need to tell the compiler where to find the library (-L.) and which library to link (-lft).
Your project file (e.g., main.c):
#include "libft.h"
int main(void)
{
ft_putendl_fd("My Libft works!", 1);
return (0);
}Compile your project:
cc -Wall -Wextra -Werror main.c -L. -lft -o my_programThis function is my favorite because it's a perfect example of what libft teaches.
static char **ft_memfree(char **strs, int l_arr)
{
// THE MOST IMPORTANT PART!
int i = 0;
while (i < l_arr)
{
free(strs[i]); // Frees each individual word
i++;
}
free(strs); // Frees the main array
return (NULL);
}
char **ft_split(char const *s, char c)
{
// ... main logic ...
// Inside the fill_word loop:
*arr = ft_word_dup(s, start, end);
if (*arr == NULL)
return (ft_memfree(strs, i)); // <-- This is beautiful.
// ...
}Why this matters:
The logic to handle a malloc failure inside the loop is the definition of robust C programming. It ensures that the function will not leak memory, even if the system runs out of resources halfway through its execution.
Memory Allocation Flow in ft_split:
Allocate main array (char**)
│
├─> Allocate word 1 (char*) ✓
├─> Allocate word 2 (char*) ✓
├─> Allocate word 3 (char*) ✗ FAILS!
│
└─> ft_memfree is called:
├─> Free word 1
├─> Free word 2
└─> Free main array
Result: ZERO memory leaks!
- Memory is treacherous: Understanding pointers, allocation, and deallocation is critical
- Security matters: Overflow checks and proper bounds checking prevent vulnerabilities
- Robust code handles failure: Always assume
malloccan fail and handle it gracefully - Function pointers unlock power: They enable flexible, reusable code patterns
- Build systems matter: A proper Makefile makes your code a real, usable library
Built with dedication to understanding the fundamentals of C