1337 | libft | Static library in C
This note was written to help my classmates understand the subject “libft” (school 1337).
The libft is the first project of the “common core” of school 1337. There are different concepts already seen during the entrance contest (also called “the pool”).
Get ready for some coding fun with Libft! It’s the first project you’ll tackle at 1337, and it’s all about creating a supercharged library of awesome functions in good ol’ C. We’re talking about functions that give the standard ones a run for their money!
To make things even more exciting, you’ll be using a Makefile to compile and run your library. Say goodbye to those ordinary standard functions because you won’t be needing them here. Libft is your new go-to resource for all your future 1337 adventures.
ince in most 1337 projects we can’t use any of the standard C library functions, the goal of this first project is to replicate some of the usual functions ourselves, as well as some additional functions.
We have to build a library that we will be able to use in our future projects.
Part 1 :
Alright, let’s kick off this project with a blast! In this first phase, your mission is to revamp a bunch of libc functions, just like the ones you find in their manual pages. But here’s the twist: you need to give them a funky makeover by adding “ft_” as a prefix to their names. So, for example, strlen becomes ft_strlen. Cool, right?
But wait, there’s a catch ! Your revamped functions should have the exact same prototypes and behaviors as the original ones. We’re talking about clones here! So, when someone uses your ft_strlen, they should get the same results and behavior as if they had used the original strlen.
It’s a challenge, but it’s also an opportunity to show off your coding skills and attention to detail. So, roll up your sleeves, put on your coding cap, and let’s give these libc functions a hip new vibe with the power of “ft_”!
ft_isalpha
Subject :
ISALPHA(3) (simplified)
NAME
isalpha -- alphabetic character test
SYNOPSIS
int isalpha(int c)
DECRIPTION
The isalpha() function tests for any character for which isupper(3) or
islower(3) is true. The value of the argument must be resprensentable as
an unsigned char or the value of EOF.
RETURN VALUES
The isalpha() function return zero if the character tests false and
returns non-zero if the character tests true.
Understandable explanation
For this function, the man is self-explanatory, but I’ll still explain it in other words. The
isalpha()
function returns a non-zero value if the character passed as anint
parameter is an alphabetical letter (lowercase or uppercase).If the character is not alphabetical, theisalpha()
function returns0
.
#include "libft.h"
int ft_isalpha(int c)
{
if ((c >= 65 && c <= 90) || (c >= 97 && <= 122))
return (c);
return (0);
}
ft_isdigit
Understandable explanation :
For this function, the man is self-explanatory, but I’ll still explain it in other words. The
isdigit()
function return a non-zero value if the character passed as anint
parameter is a decimal digit character (0 - 9). If the character is not a decimal digit character, theisdigit()
function return0
.
#include "libft.h"
int ft_isdigit(int c)
{
if (c >= 48 && c <= 57)
return (c);
return (0);
}
ft_islnum
Understandable explanation :
For this function, the man is self-explanatory, but I’ll still explain it in other words. The
isalnum()
function returns a non-zero value if the character passed as anint
parameter is alphabetical or a decimal digit character. If the character is not alphabetical nor a decimal digit character, theisalnum()
function returns0
.
#include "libft.h"
int ft_isalnum(int c)
{
/* This checks makes use of the 2 preceeding functions we built */
if (ft_isalpha(c) || ft_isdigit(c))
return (c); //If we reach this point we can return c as it will be a non-zero value
return (0);
}
ft_isascii
Understandable explanation :
For this function, the man is self-explanatory, even though it doesn’t tell you what the return values are…
The
isascii()
function returns a non-zero value if the character passed as anint
parameter is an ASCII character between 0 and octal 0177, this means characters between 0 and decimal 127, all characters displayed when you type theman ascii
command. If the character is not an ASCII character between 0 and octal 0177, theisascii()
function return0
.
#include "libft.h"
int ft_isascii(int c)
{
if (c >= 0 && c <= 127)
return (1);
return (0);
}
ft_isprint
Understandable explanation
For this function, the man is pretty self-explanatory, but I’ll give more details (i.e. what are the printing characters). The
isprint()
function returns a non-zero value if the character passed as anint
parameter is a printing character. If the character is not a printing character, theisprint()
function returns0
. The printing characters are all character between decimal 32 and decimal 126.
#include "libft.h"
int ft_isprint(int c)
{
if (c >= 32 && c <= 126)
return (c);
return (0);
}
ft_bzero
Understandable explanation
This function works the same way as the
memset()
function, except you don't have to specify what character to write, it'll always be0
(NUL
character). This function does not return anything and if the number of characters to write you passed assize_t n
is0
,bzero
does nothing.
#include "libft.h"
void ft_bzero(void *s, size_t n)
{
while (n--)
*(unsigned char *)s++ = 0;
}
ft_memset
Understandable explanation
As the man description says, this function writes
len
bytes of valuec
to the stringb
. The value ofc
will be converted to anunsigned char
, so to set this value in theb
string, we'll have to convert theb
string to a pointer tounsigned char
. But remember the return value, we have to return the first parameter of the function, thevoid *b
string. So how do we convert this parameter without changing the original one ? Think about temporary variables.
#include "libft.h"
void *ft_memset(void *b, int c, size_t len)
{
unsigned char *tmp_ptr;
tmp_ptr = (unsigned char *) b;
while (len > 0)
{
*(tmp_ptr++) = (unsigned char) c;
len--;
}
return (b);
}
ft_memcpy
Understandable explanation
The
memcpy
function copies maximum n bytes fromsrc
todst
. The man talks about memory overlapping, I'll explain this with details on thememmove
function page. As formemset
andbzero
we'll need some temporary pointers to manipulate our data. This functions works like thestrcpy
function, except thatmemcpy
acceptsvoid *
as parameters, so we can give it any type of pointer we want to copy.
#include "libft.h"
void *ft_memcpy(void *dst, const void *src, size_t n)
{
unsigned char *tmp_dst;
unsigned char *tmp_src;
// funtion return pointer void So convert 0 to (void *)
if (dst == (void *)0 && src == (void *)0)
return (dst);
tmp_dst = (unsigned char *) dst;
tmp_src = (unsigned char *) src;
while (n > 0)
{
*(tmp_dst++) = *(tmp_src++);
n--;
}
return (dst);
}
ft_memmove
Understandable explanation
The
memmove()
function does the same thing as thememcpy()
function but this time, the copy is made, as said in the man, in a non-destructive manner. This means that both strings (src and dst) can overlap in memory and this function does not overwrite part of, or the entirety of the string when making the copy.
I found a really good explanation so I’ll copy it here to explain what is memory overlapping.
#include "libft.h"
void *ft_memmove(void *dst, const void *src, size_t len)
{
char *c_src;
char *c_dst;
size_t i;
if (!dst && !src)
return (NULL);
c_src = (char *) src;
c_dst = (char *) dst;
i = 0;
if (c_dst > c_src)
while (len-- > 0)
c_dst[len] = c_src[len];
else
{
while (i++ < len)
c_dst[i] = c_src[i];
}
return (dst);
ft_memcmp
Understandable explanation
memcmp()
compares byte strings. It works similarly to thestrncmp()
function.The difference here is that
memcmp()
works with bytes strings so it take void pointers as parameter, plus a third character, representing, as said in the man, the assumed length of both strings. This means thatmemcmp()
will not compare more thann
bytes.The return value depends on what difference is found. If there is no difference between both strings, the return value will be 0.If there is a difference, and the first different character ins2
is greater than the character at the same place ins1
, the returned result will be negative. If there is a difference, and the first different character ins2
is less than the character at the same place ins1
, the returned result will be positive.
#include "libft.h"
int ft_memcmp(const void *s1, const void *s2, size_t n)
{
unsigned char *str1;
unsigned char *str2;
size_t i;
str1 = (unsigned char) *s1;
str2 = (unsigned char) *s2;
i = 0;
while (i < n)
{
if ((unsigned char) str1[i] != (unsigned char) str2[i])
return ((unsigned char) str1[i] - (unsigned char) str2[i]);
}
return (0);
}
ft_memchr
understandable explanation
The
memchr()
function works similarly as thestrchr()
function, the difference is thatmemchr()
works with byte string (void *
) wherestrchr()
works with 'litteral' strings (char *
). This means we can send whatever type of data we want tomemchr()
and it'll still work.memchr()
also has a third parameter,n
. This parameter tells the function how many bytes we want to search in. We need this parameter sinces
is not a 'litteral' string, it doesn't have a NUL-terminating character. If we didn't have this parameter, we would be reading a random number of bytes each time.
#include "libft.h"
void *ft_memchr(const void *s, int c, size_t n)
{
unsigned char *str;
size_t i;
unsigned char uc;
str = (unsigned char *) s;
uc (unsigned char) c;
i = 0;
while (i < n)
{
if (str[i] == uc)
return ((void *) &str[i]);
i++;
}
return (NULL);
}
ft_strlcpy
Understandable explanation
What this function does is pretty simple in that it’s made to copy one string to another but with a small catch, it alwaysNUL-terminate the string.If you give a
dstsize
long enough to NUL-terminate the string without truncating it,strlcpy()
will simply copy the string, as you'd do withstrcpy()
. If you don't give adstsize
long enough, it will copydstsize - 1
characters from the source into the destination, adding the NUL-terminating character after that. Thestrlcpy()
function always returns the length of the string that it tried to create, this is the length ofsrc
, even if you have to truncate the string to NUL-terminate it.
#include "libft.h"
size_t ft_strlcpy(char *dst, const char *src, size_t dstsize)
{
size_t src_len;
src_len = ft_strlen(src);
if (src_len + 1 < dstsize)
ft_memcpy(dst, src, src_len + 1);
else if (dstsize != 0)
{
ft_memcpy(dst, src, dstsize - 1);
dst[dstsize - 1] = 0;
}
return (src_len);
}
ft_strlcat
Understandable explanation
What this function does is pretty simple in that it’s made to concatenate two strings but with a small catch, it alwaysNUL-terminate the string. If you give a
dstsize
long enough to NUL-terminate the resulting concatenated string without truncating it,strlcat()
will simply concatenate the two string, as you'd do withstrcat()
. If you don't give adstsize
long enough, it will concatenatedstsize - strlen(dst) - 1
characters, adding the NUL-terminating character after that. Thestrlcat()
function always returns the length of the string it tried to create, this is the original length ofdst
plus the original length ofsrc
, even if you have to truncate the string to NUL-terminate it.
#include "libft.h"
size_t ft_strlcat(char *dst, const char *src, size_t dstsize)
{
size_t src_len;
size_t dst_len;
src_len = ft_strlen(src);
dst_len = ft_strlen(dst);
if (dst_len >= dstsize)
dst_len = dstsize;
if (dst_len == dstsize)
return (dstsize + src_len);
if (src_len < dstsize - dst_len)
ft_memcpy(dst + dst_len, src, src_len + 1);
else
{
ft_memcpy(dst + dst_len, src, dstsize - dst_len - 1);
dst[dstsize - 1] = '\0';
}
return (dst_len + src_len);
}
ft_strrchr
Understandable explanation
This function is fairly easy to understand, it does the same thing as
strchr()
, but locates the last occurence of c.
#include "libft.h"
char *ft_strrchr(const char *s, int c)
{
unsigned int i;
char *res;
char cc;
cc = (char) c;
res = NULL;
i = 0;
while (s[i])
{
if (s[i] == cc)
res = (char *) &s[i];
i++;
}
if (s[i] == c)
res = (char *) &s[i];
return (res);
}
ft_strchr
Understandable explanation
The
strchr()
function searches for one character in a string. If it finds the character, it returns a pointer to the first occurence of this specific character. If it don’t find any occurence of this character, it returnsNULL
. We also have to return a pointer to the character if the character is\0
.
#include "libft.h"
char *ft_strchr(const char *s, int c)
{
unsigned int i;
char cc,
cc = (char) c;
i = 0;
while (s[i])
{
if (s[i] == cc)
return ((char *) &s[i]);
i++;
}
if (s[i] == cc)
return ((char *) &s[i]);
return (NULL);
}
ft_strnstr
Understandable explanation
The
strnstr()
function works in the same way asstrchr()
but searches for a complete substring in maxn
characters instead of a single character.
#include "libft.h"
char *ft_strnstr(const char *haystack, const char *needle, size_t len)
{
size_t i;
size_t j;
i = 0;
j = 0;
if (needle[0] == 0)
return ((char *) haystack);
while (haystack[i] && i < len)
{
while (haystack[i + j] == needle[j] && haystack[i + j] && i + j < len)
{
j++;
if (needle[j] == 0)
return ((char *) haystack + i);
}
i++;
j = 0;
}
return (0);
}
ft_strdup
Understandable explanation
For once, the man is really clear on what the function does. So I don’t think I need to explain it with more details.
Hints : We have to use malloc for this since the returned value of this function must be ‘freeable’ with the free function.
#include "libft.h"
char *ft_strdup(const char *s1)
{
char *dest;
size_t i;
dest = (char *) malloc(ft_strlen(s1) + 1);
if (!dest)
return (NULL);
i = 0;
while (s1[i])
{
dest[i] = s1[i];
i++;
}
dest[i] = 0;
return (dest);
}
ft_calloc
Understandable explanation
By now you should have understand what the
malloc()
function does, at least I hope. Otherwise, understand howmalloc()
works and come back here. I will mainly base my explanation on comparingcalloc()
tomalloc()
.
calloc()
works in the same way asmalloc()
does, but the difference is thatcalloc()
sets all the memory bytes are set to0
instead of staying as the gibberish that was there in memory before we allocated it.
#include "libft.h"
void *ft_calloc(size_t count, size_t size)
{
unsigned char *tmp;
size_t i;
i = 0;
tmp = malloc(count * size);
if (!tmp)
return (NULL);
while (i < count * size)
tmp[i++] = 0;
return (tmp);
}
Part 2
Now, it’s time to take this project to the next level in the second phase! You’ll be flexing your coding muscles by implementing a range of functions that either don’t exist in the libc library or have a unique twist to them.
These additional functions serve multiple purposes and are like precious building blocks for creating even more awesome functions. They open up a world of possibilities and give your project a boost in utility and versatility.
But what do these functions do, you ask? Well, they can do all sorts of magical things! They might handle complex calculations, manipulate strings in creative ways, or even perform specialized tasks that are crucial for the overall development of your project. The sky’s the limit!
So, get ready to dive into the exciting world of these unique functions. Let your creativity run wild and show off your coding wizardry by bringing something truly extraordinary to the table. The more you explore and incorporate these functions, the more incredible your project will become!
ft_substr
Understandable explanation
ft_substr
returns a substring of the strings
passed as parameter.
Here’s an example
ft_substr("Bonjour comment ca va?", 5, 8);
=> "ur comme"
#include "libft.h"
char *ft_substr(const char *s, unsigned int start, size_t len)
{
size_t i;
char *str;
if (!s)
return (NULL);
if (start > ft_strlen(s))
return (ft_strdup(""));
if (len > ft_strlen(s + start))
len = ft_strlen(s + start);
str = ft_calloc(len + 1, sizeof(char));
if (!str)
return (NULL);
i = 0;
while (i < len)
{
str[i] = s[start + i];
i++;
}
return (str);
}
ft_strjoin
Understandable explanation
This function works basically the same way as
ft_strlcat
does, but instead of passing it adestination
string
that has to be correctly allocated as a parameter, we only pass twostrings
andft_strjoin
will allocate the required memory for both of them plus the NUL-terminating character.
s1
will be the first string in the result,s2
the second one.
#include "libft.h"
char *ft_strjoin(const char *s1, const char *s2)
{
char *res;
int i;
int j;
i = 0;
j = 0;
res = (char *) malloc((ft_strlen(s1) + ft_strlen(s2) + 1) * sizeof(char));
if (!res)
return (NULL);
while (s1[i])
res[j++] = s1[i++];
i = 0;
while (s2[i])
res[j++] = s2[i];
res[j] = 0;
return (res);
}
ft_strtrim
Understandable explanation
The
ft_strtrim()
function takes a string and trims it.What does trimming mean you might ask ? Let me explain. Trimming means removing the characters specified in the
set
string from the start AND the end of the strings1
, without removing the characters from theset
that are in the middle ofs1
. If we have the stringababaaaMy name is Simonbbaaabbad
and our set isab
, we'll get this result out of theft_strtrim()
function :My name is Simon
. We removed everya
andb
from the start and the end ofs1
, without touching at the a in the middle ofs1
.
#include "libft.h"
char *ft_strtrim(const char *s1, const char *set)
{
int i;
int j;
i = 0;
j = ft_strlen(s1) - 1;
if (ft_strlen(s1) == 0)
return (ft_strdup(""));
while (to_trim(set, s1[i]))
i++;
while (to_trim(set, s1[j]))
j--;
return (new_str(s1, i, j - (i - 1));
}
static char *new_str(const char *s1, size_t start, size_t len)
{
char *str;
size_t i;
if (len <= 0 || start >= ft_strlen(s1))
return (ft_strdup(""));
str = ft_calloc(len + 1, sizeof(char));
if (!str)
return (NULL);
i = 0;
while (i < len)
{
str[i] = s1[start + i];
i++;
}
return (str);
}
static int to_trim(const char *set, char c)
{
int i;
i = 0;
while (set[i])
{
if (c == set[i])
return (1);
i++;
}
return (0);
}
ft_split
Understandable explanation
The subject tells us that
ft_split()
must return an array of strings (=> an array of arrays, since strings are arrays of characters terminated by a NUL character).We can also phrase that as an array of words, we take the string
s
and we split it to get an array containing each words of it. Each word is separated by one or morec
, that's our word delimiter.It’s also said that our words array must be NUL-terminated. That means we have to allocate one more element in our array, that we can set to 0. By doing this we have an easy way to loop over our words array, the same as for a string:
while(words[i] != 0)
.The subject is not that hard to understand, the more complex thing is to your code do all that.
#include "libft.h"
static int count_word(char const *s, char c)
{
int f;
int count_word;
int i;
count_word = 0;
i = 0;
f = 0;
while (s[i])
{
if (s[i] == c)
f = 0;
else if (f == 0)
{
f = 1;
count_word++;
}
i++;
}
return (count_word);
}
static char *ft_create_word(char const *str, char c)
{
char *dest;
int i;
i = 0;
while (str[i] && str[i] != c)
i++;
dest = (char *)malloc(sizeof(char) * i + 1);
if (!dest)
return (NULL);
i = 0;
while (str[i] && str[i] != c)
{
dest[i] = str[i];
i++;
}
dest[i] = '\0';
return (dest);
}
static char **ft_free(char **split, int i)
{
while (--i)
free(split[i]);
free(split);
return (NULL);
}
char **ft_split(char const *str, char c)
{
char **dest;
int i;
if (!str)
return (NULL);
i = 0;
dest = (char **)malloc(sizeof(char *) * (count_word(str, c) + 1));
if (!dest)
return (NULL);
while (*str)
{
while (*str && *str == c)
str++;
if (*str && *str != c)
{
dest[i++] = ft_create_word(str, c);
if (dest[i - 1] == NULL)
return (ft_free(dest, i));
while (*str && *str != c)
str++;
}
}
dest[i] = NULL;
return (dest);
}
ft_itoa
Understandable explanation
The ft_itoa function converts the given integer into string representation. It first determines the sign of the number by checking if it is negative. It calculates the length of the resulting string by counting the number of digits in the absolute value of the integer. Memory is allocated to store the resulting string, including space for the sign and the null-terminator. The conversion is performed by iteratively extracting the digits from the integer using modulo and division operations. The digits are then converted to characters by adding the ASCII value of ‘0’. The digits are added to the string in reverse order to ensure the correct representation of the number. Finally, the sign is added if necessary, the null-terminator is appended, and the resulting string is returned.
#include "libft.h"
static int nbr_len(int nbr)
{
int len;
len = 0;
if (nbr < 1)
len++;
while (nbr)
{
nbr /= 10;
len++;
}
return (len);
}
static long long abs_val(long long n)
{
long long nb;
nb = 1;
if (n < 0)
nb *= -n;
else
nb *= n;
return (nb);
}
static char *str_new(size_t n)
{
char *str;
str = (char *)malloc(sizeof(char) * (n + 1));
if (!str)
return (NULL);
return (str);
}
char *ft_itoa(int n)
{
unsigned int nbr;
int sign;
int len;
char *str;
sign = 0;
if (n < 0)
sign = 1;
len = nbr_len(n);
str = str_new(len);
if (!str)
return (NULL);
*(str + len) = '\0';
nbr = abs_val(n);
while (len--)
{
*(str + len) = 48 + nbr % 10;
nbr /= 10;
}
if (sign)
*(str) = 45;
return (str);
}
ft_strmapi
Understandable explanation
This functions takes two parameters, the first one is a string, and the second one is a function.
What
ft_strmapi
does is apply the functionf
to every character of the strings
.It passes the index of the character in the string, and the character to the functionf
.The result of the functionf
is placed in the new string at indexi
. At the end, we return the new string resulting of the application off
on every character of the string.
#include "libft.h"
char *ft_strmapi(const char *s, char (*f)(unsigned int, char))
{
unsigned int i;
char *res;
res = malloc((ft_strlen(s) + 1) * sizeof(char));
if (!res)
return (NULL);
i = 0;
while (i < ft_strlen(s))
{
res[i] = (*f)(i, s[i]);
i++;
}
res[i] = 0;
return (res);
}
ft_striteri
Understamdable explanation
ft_striteri
works the same way asft_strmapi
does, take a look at the explanation forft_strmapi
and then come back here.The difference between
ft_striteri
andft_strmapi
is thatft_striteri
doesn't return anything and works directly on the original string.
#include "libft.h"
void ft_striteri(char *s, void (*f)(unsigned int, char*))
{
unsigned int i;
i = 0;
while (s[i])
{
(*f)(i, &s[i]);
i++;
}
}
ft_putchar_fd
Understandable explanation
This one is pretty straight forward, you already know how to write the
ft_putchar()
function, if you don't remember, look back at what you did during your Piscine.
#include "libft.h"
void ft_putchar_fd(char c, int fd)
{
if(id != -1 )
write(fd, &c, 1);
}
ft_putnbr_fd
Understandable explanation
This function works the same way as the
ft_putnbr()
function you had to do during the Piscine, it also takes thefd
parameter, likeft_putchar_fd()
,ft_putstr_fd()
,ft_putendl_fd()
.
#include "libft.h"
void ft_putnbr_fd(int n, int fd)
{
if (fd == -1)
return ;
if (n == -2147483648)
write(fd, "-2147483648", 11);
else if (n < 0)
{
write(fd, "-", 1);
n = -n;
ft_putnbr_fd(n, fd);
}
else
{
if (n > 9)
{
ft_putnbr_fd(n / 10, fd);
ft_putnbr_fd(n % 10, fd);
}
else
{
digit = n + 48;
write(fd, &digit, 1);
}
}
}