42 School Cheat Sheet by agavrel
Truth can only be found in one place: the code. – Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship
A minimalist c program that will puzzle beginners, write it in a file named a.c and create a.out with gcc a.c && ./a.out
#include <stdio.h>
void ft_putchar(char c)
{
write(1, &c, 1);
}
int main(void) {
ft_putchar(42);
return 0;
}
42 is more than just a disruptive educational model and coding school. What makes us unique and a major player in the tech world are the defining characteristics of the 42 culture. Every element of 42 shows our culture, from the students, to the curriculum structure and content, to the $0 tuition and innovative admissions process.
That's right, the school is FREE, originally funded and founded in Paris by generous philanthropist billionaire Xaviel Niel
“Nevertheless, C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.” ― Brian W. Kernighan, The C Programming Language
Most of the entrance exam and early cursus is done in C language.
"When you say 'I wrote a program that crashed Windows,' people just stare at you blankly and say 'Hey, I got those with the system, for free.'" ― Linus Torvalds
C is indeed one of the best language to understand the basis of programming: Conditions {if, elseif, else}, loops {while, do while, for}, pointers and memory allocation. C will hence act as an educational tool to develop your skill.
Later on you can specialize in other languages: Python will suit data scientists and devops, javascript for frontend developers and C# for those looking for a career in finance.
The piscine is the entrance exam that consists of 4 weeks fully dedicated at solving exercises and submitting group and solo projects.
Although the school advise you to "come as you are", and this is what I did, it does certainly help to prepare beforehand.
It does not matter if you fail a project, an exam or a day as long as you keep striving. Someone who has never been interested before in Computer Science would never be able to complete everything in time, yet he will not prevent from being successful.
-
0x00 Come as you are ... or forget this shit and prepare with subject on github, courtesy of my friend binary hacker.
-
0x01 Prepare to nail the exams on the 4 exams session, knowing that the 3 firsts exams are limited in term of how far you can go and it is not a big deal to miss the first 3 exams as the most important is IMHO the maximum level you can reach. Succeeding the first 4 exercises (36 pts) should be enough to make sure you quality.
-
0x02 Get an acceptable percentage of review from peers (probably 80% is enough, but you would get 90 to 97% if you are nice). Don't be too nice, but don't be a dick with vim .swp files and .DS_Store.
.DS_Store – The name of a file in the Apple OS X operating system for storing custom attributes of a folder such as the position of icons or the choice of a background image. These files are created when you manipulate your files with the Finder GUI.
-
0x03 The logging time has no or very little influence, I know it as a fact for seeing people constantly logged in (but slacking) failing the piscine and students barely present being accepted. However the more time you spend in 42 school will certainly directly influence your skills and positively impact other related topics
-
0x04 It is strongly recommended to succeed at least one group project, especially the first one that is really easy.
-
0x05 There is a special and unique achievement awarded to the most helpful/smart student. This achievement does not show up on the student profile until he asks for it.
"Do what you think is interesting, do something that you think is fun and worthwhile, because otherwise you won’t do it well anyway." ― Brian W. Kernighan
Name | Track | Hashtags | What you will learn |
---|---|---|---|
Fillit | General | Architecture, Parsing, Algo | Description from a student |
Printf | Algorithm | Architecture, Parsing, utf-8 | UTF-8 Conversion table Variadic Function |
Filler | Algorithm | Parsing, Algo, Bot | 42 forums have good threads on this project |
Lem-In | Algorithm | Parsing, Algo, Chained-Lists | Dijkstra's algorithm |
Corewar | Algorithm | Architecture, parsing, disassembler, virus, VM | About the original Game |
LS | System | Parsing, Recursion, Chained-Lists | The Good Old Manual |
Minishell | System | Environment Variables, Shell | Bourne Shell |
Malloc | System | Algo, Memory, HashCollision | The Good Old Manual |
FDF | Computer Graphics | Parsing, Creativity | Bresenham's line algorithm, Use of Graphics Library, Trigonometry, Rotations, 3D Projection, ARGB Color Space |
Fractol | Computer Graphics | Fractals, Mathematics, ARGB, HUV | Mandelbrot Set |
Wolfenstein 3d | Computer Graphics | Raytracing, Rotation | About the original Wolfenstein 3d |
NmOtool | System | Symbol Table, .dll .so | Implement List the symbols in a .so file |
LibftAsm | System | x86 Assembly Instructions | Refer to the Intel Bible |
How to choose your specialization There are currently 4 main branches: Infographics, Algorithms, System and Web. All branchs are interesting and you should try to explore each branch's initial project:
- If you are aiming to work in the video game industry and like Mathematics then you should go for Infographics. Remember that this path is tough and not necessarily as rewarding as the other ones, but you will have the luxury to work in the video game industry.
- Algorithm branch is/was mainly based on flawless parsing and not so much on algorithm quality. Fortunately with the nomination of Benny as the head of the Pedagogy there will be more efforts to reward smart algorithms. Algorithms is the best one if you want to join a prestigious company like Google
- System is the best for those who like security, network and how computers truly work since you will have to ultimately recode your own operating system.
- Web is good for those who like to build websites, perhaps mobile app as well (react native) and want to become a freelancer.
Only petty thieves would google "torrent" or "pdf" keywords, real Gentlemen would purchase a digital copy
"C is quirky, flawed, and an enormous success." ― Dennis Ritchie, Creator of the C language
Title | How Interesting | Author |
---|---|---|
The C Programming Language 2nd Ed Subsequent Edition | 💕 | by Brian Kernighan and Dennis Ritchie |
Are Global Variables Bad | ⭐ | StackOverFlow |
Obscure C Features | ⭐⭐⭐⭐⭐ | by Multun |
Characters, Symbols and the UTF-8 Miracle - Computerphile | ⭐⭐⭐⭐ | by Tom Scott |
Automatic Vectorization | ⭐⭐⭐⭐ | by Marchete |
Writing Solid Code | ⭐⭐⭐⭐ | by Steve Maguire |
The Practice of Programing | ⭐⭐⭐ | by Brian W. Kernighan and Rob Pike |
Duff's Device | ⭐⭐⭐ | by Tom Duff |
Title | How Interesting | Author |
---|---|---|
A curated list of Awesome Competitive Programming | ⭐⭐⭐ | by Inishan (Jasmine Chen) |
Nailing the Coding Interview | 🇰🇷 | by Antonin Gavrel |
A tour of the top 5 sorting algorithms with Python code | ⭐⭐ | by George Seif |
"The word bit is a contraction of binary digit that was coined by the statistician John Tukey in the mid 1940s." ― Brian W. Kernighan, D Is for Digital
Title | How Interesting | Author |
---|---|---|
Hacker's Delight | 💕 | by Henry S. Warren Jr. |
Bit Twiddling Hacks | 💕 | by Sean Eron Anderson |
De Bruijn Sequence | ⭐⭐ |
I would tell you a joke about UDP but I’m afraid you wouldn’t get it.
Title | How Interesting | Author |
---|---|---|
Next Generation Kernel Network Tunnel - WireGuard | 💕 | by JA Donenfeld |
TCP Meltdown | ⭐⭐ | by Computerphile |
Onion Routing | ⭐⭐⭐⭐ | by Computerphile |
"Never underestimate the determination of a kid who is time-rich and cash-poor." ― Cory Doctorow, Little Brother
Title | How Interesting | Author |
---|---|---|
Smashing The Stack For Fun And Profit | 💕 | by Aleph One |
Breaking the x86 Instruction Set | ⭐⭐⭐⭐⭐ | by Domas |
Buffer Overflow, Race Condition, Input Validation, Format String | ⭐⭐⭐⭐ | by Wenliang (Kevin) Du |
Secure Programming HOWTO | ⭐⭐⭐ | by David A. Wheeler |
Efficiently Generating Python Hash Collisions | ⭐⭐ | |
Stochastic Process Wikipedia | ⭐⭐ | |
Gimli: a cross-platform permutation | ⭐⭐ | |
LiveOverflow | ⭐⭐ |
Title | How Interesting | Author |
---|---|---|
Fast Inverse Square Root | 💕 | attributed to John Carmack (Quake III) |
3d Fractal Flame Wisps | ⭐⭐⭐ | by Yujie Shu |
Geometry Caching Optimizations in Halo 5 | ⭐⭐⭐ | by Zabir Hoque and Ben Laidlaw |
Exponentiation by Squaring | ⭐ | Wikipedia |
Light and Shadows in Graphics | ⭐⭐ | by John Chapman |
Screen Space Ambient Occlusion Tutorial | ⭐⭐ | by John Chapman |
Title | How Interesting | Author |
---|---|---|
OpenCV Tutorial | ⭐⭐⭐ |
"C++ is a horrible language. It's made more horrible by the fact that a lot of substandard programmers use it, to the point where it's much much easier to generate total and utter crap with it" ― Linus Torvalds 2007
Title | How Interesting | Author |
---|---|---|
C++ Features | ||
Optimizing software in C++ | 💕 | by Agner Fog |
Intel Intrinsics Guide What is it | ⭐⭐⭐⭐ | Intel |
"Low Latency C++ for Fun and Profit" | ⭐⭐⭐⭐ | by Carl Cook |
Why I Created C++ | ⭐⭐⭐ | Bjarne Stroustrup |
CppCon 2018 “High-Radix Concurrent C++” | ⭐⭐⭐ | Olivier Giroux |
"People say that you should not micro-optimize. But if what you love is micro-optimization... that's what you should do." ― Linus Torvalds
Title | How Interesting | Author |
---|---|---|
Optimizing subroutines in assembly x86 language | 💕 | by Agner Fog |
Intel® 64 and IA-32 architectures software developer’s manual | 💕 | Intel |
The Art of Assembly Language | ⭐⭐ | by Randal Hyde |
GDB Tutorial | ⭐⭐ | by Andrew Gilpin |
Tips for Golfing in x86/x64 Bytecode | ⭐⭐⭐ | by StackExchange |
"Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?" ― Brian W. Kernighan
Title | How Interesting | Author |
---|---|---|
A Super Mario 64 decompilation | ⭐⭐⭐⭐⭐ | by a bunch of clever folks |
Math for Game Programmers: Dark Secrets of the RNG | ⭐⭐⭐ | by Shay Pierce |
Why Java Suck | ⭐ | by Jonathan Gardner |
XOR Linked List – A Memory Efficient Doubly Linked List | ⭐ | Wikipedia |
XOR Linked List – C Implementation | ⭐ | StackOverFlow |
"Experience is the name everyone gives to their mistakes." – Oscar Wilde
In C the index of an array starts at 0. Because C does not perform boundary checking when using arrays, if you access outside the bounds of a stack based array it will just access another part of already allocated stack space, like in this example:
#include <stdio.h>
void somefunction3(void)
{
int a[5];
printf("%d\n", a[5]);
}
In this example, 5 is the size of the array and if you try to access it it will overflow. Remember that the maximum array index you can ever access is its size minus 1.
I would suggest to use as much as possible a const :
#include <stdio.h>
void somefunction3(void)
{
const int len = 5;
int a[len] = {1,3,5,7,9};
for (int i = 0; i < len; i++) // safe
printf("%d\n", a[i]);
}
"There are two ways to write error-free programs; only the third one works." – Alan J. Perlis
Many potential reasons for this...
One common mistake is that you had declared a loop and either:
int i = 0;
while (i < 10)
{
write(1, &i + '0', 1);
// but where is i++ ?
}
int i = 0;
while (i < 10)
{
write(1, &i + '0', 1);
i++;
}
int somevariable = 0;
while (42) // always True ! You will be 42 for life ;)
{
// call to some stuff that never succeed to set someVariable to 1;
if (somevariable == 1) // make sure that somevariable will equal 1 at some point.
break ;
}
#include <stdio.h>
int main(void) {
unsigned int x = 10;
while (--x != 0)
{
printf("0 0 0 1 0 1 0 1 0 ");
if (x = 1) { // oopsie !!
printf("* ");
x--;
}
}
return 0;
}
PS: will you be able to fix this code ?
Also classic with lists: you have a loop and its crucial condition that allows the function to return, but used an assignation instead of comparison
int i = 0;
while (list)
{
if (list = NULL) // You want to use if (list == NULL)
return i;
i++;
list=list->next;
}
return -1; // will always return -1
unsigned char c = 0;
while (c < 150)
{
write(1, &c, 1);
c++;
}
"Talk is cheap. Show me the code." ― Linus Torvalds
Another example with linked-lists
typedef struct s_list {
void *data;
t_list *next;
} t_list;
/*
** function to go 2 links further in a chained-list
*/
void somefunction(t_list *list)
{
if (list->next != NULL)
{
list = list->next->next;
}
}
if the current link of list is null you will get a segfault. The correct way is to always check the current link before the next one:
void somefunction(t_list *list)
{
if (list && list->next) // if both list and list->next exist
{
list = list->next->next;
}
}
int somefunction(int y_max, int x_max, int array[y_max][x_max]);
{
int y;
int x;
y = 0;
while (y < y_max)
{
x = 0;
while (x < x_max)
{
if (array[y][x-1] > array[y][x]) // don't you see there is a problem ?
{
array[y][x] = array[y][x-1];
}
if (array[y+1][x] > array[y][x]) // don't you see there is another problem ?
{
array[y][x] = array[y+1][x];
}
}
}
}
These lines should be corrected the following way:
if (x > 0 && array[y][x-1] > array[y][x])
if (y < y_max - 1 && array[y+1][x] > array[y][x]) // strictly inferior to last possible index which is y_max - 1,
// you may also write y <= y_max - 2
You may also notice that we can even do better by changing the starting value of x or the exit condition of the y loop in the case that we were to check only one of the two if conditions.
x = 1;
while (y < y_max - 1)
Local variable value are allocated on the stack, which is cleaned once you exit the function.
void increment_a(int a)
{
a++; // it will have no effect
}
int solve(void)
{
int a = 5;
increment_a(a);
}
Hence if you want to modify a value you either have to use a pointer to the memory address:
void increment_a(int *a)
{
*a++;
}
int solve(void)
{
int a = 5;
increment_a(&a);
}
or return the local value:
int increment_a(int a)
{
return a+1;
}
int solve(void)
{
int a = 5;
a = increment_a(a);
}
Do NOT leave a malloc unprotected:
int allocate_memory(void)
{
int *matrix;
matrix = malloc(sizeof(int) * 9))
return matrix;
}
int somefunction(void)
{
int *matrix;
matrix = allocate_memory();
}
Protect both the malloc and its return value: It is not good enough to protect the malloc in the callee function (the function called) if the returned value is not also protected in the caller function (the function 'above')
int allocate_memory(void)
{
int *matrix;
if (!(matrix = malloc(sizeof(int) * 9))) // this is short for matrix = malloc(sizeof(int) * 9; if (matrix == NULL)
return NULL; // the malloc is now protected,
return matrix;
}
int somefunction(void)
{
int *matrix;
if ((matrix = allocate_memory()) == NULL) // the return value is also protected
exit(); // note that often you can't or don't want to use exit() and will need to return 0 along all the functions up to the main function.
free(matrix);
}
In the previous example, if you don't need the variable matrix anymore you can free it.
However do not attempt to free twice or to free a stack based variable:
free(matrix);
free(matrix)
"Theory and practice sometimes clash. And when that happens, theory loses.
Every single time." ― Linus Torvalds
Global variables are forbidden in 42 School except for a few exceptions, see this interesting article: Are Global Variables Bad However many students, me including, found a way to circumvent this interdiction: you first declare a structure in the header that will contain all our variables:
"Don’t comment bad code—rewrite it." ― Brian W. Kernighan, The Elements of Programming Style
typedef struct s_env
{
int a;
int b;
int c[4];
// ... other variables you may need
} t_env;
And then using it the following way in the program:
void somefunction2(t_env *env)
{
env->b = 2;
}
void somefunction(t_env *env)
{
env->a = 1;
somefunction2(env);
}
int main(void)
{
t_env env;
somefunction(&env);
printf("%d\n", env.a);
printf("%d\n", env.b);
}
This is "legal" in 42 (it is not a global variable, it is a structure passed along functions), it "works", but it is a very poor architecture choice. It is okay for beginner to do this but as your skill grows you should find more clever ways to architecture your programs.
The following example is a VLA and this is bad for many reasons, the most critical being that the memory is allocated on the stack which has a limited size.
int somefunction(int y, int x, int array[y][x]);
Waiter! There's a VLA in my C!
ft_ is intended for functions you want to add to the libft project and use along your projects, not for specific program functions.
Now some guidelines that should hopefully help your coding style
“Don’t comment bad code, rewrite it.” Brian W. Kernighan, The Elements of Programming Style
If you are using coordinates it might be interesting to create a structure 'point' or 'coord'
typedef struct s_point
{
int y;
int x;
} t_point;
void somefunction(void){
t_point p;
p.x = 2;
p.y = 5;
//alternatively: p = {5, 2};
}
I once met a developer who was using hp and mp instead of x and y for coordinates.
It was surely funny, original and a very good reference to JRPG... but it was not suitable name.
The function name should always be:
- In English, forget about chauvinism!
- At least 5 letters. It is okay to have shorter exceptionally for well-known variables like int index -> int i, temporary -> tmp and pointer -> ptr.
- Self-explanatory: build_graph instead of graph or build_it
- For long name use either camel case (saveClientConfig) or snake case (save_client_config) and stick to one style.
For each project you will often have to parse flag input. In Linux the flag usually come after a '-' and allow for extra functionalities. It is quite useful know how you can store such critical information into only 4 bytes which is sizeof(integer)
static int ft_strchr_index(char *s, int c)
{
int i;
i = 0;
while (s[i])
{
if (s[i] == c)
return (i);
++i;
}
return (-1);
}
int get_flags(char *s, int *flags)
{
int n;
while (*(++s))
{
if ((n = ft_strchr_index("alRrtdG1Ss", *s)) == -1)
return (0);
*flags |= (1 << n);
}
return (1);
}
int main(int ac, char **av)
{
int i;
int flags = 0;
i = 0;
while (++i < ac && av[i][0] == '-' && av[i][1])
{
if (av[i][1] == '-' && av[i][2])
return (i + 1);
if (!get_flags(av[i], &flags))
return (-1);
}
return (i);
}
The a flag will be on bit 1, l on bit 2, R on bit 4, r on bit 8 etc. You can then test if the flag was on by using the following:
#define FLAG_A 0b001
#define FLAG_L 0b010
#define FLAG_RR 0b100
#include <stdio.h>
void somefunction(int *flags)
{
if (flags & FLAG_A)
printf("Flag a is set!\n");
}
You can unset a flag by clearing the corresponding bit the following way:
void somefunction2(int *flags)
{
flags &= ~FLAG_A;
}
"Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live." – John Woods
A more readable (aka: better) approach suggested by Nicolas Iragne from 42 is to declare a struct using bitfield:
struct flags_t
{
int a : 1;
int b : 1;
int c : 1;
//etc
}
#include <stdio.h>
int main(void) {
struct flags_t flags = {0};
t.a = 1;
if (t.a)
write(1, "flag a is set\n", 14);
return 0;
}
PS: Of course rename flags' name with more meaningful
gcc -Wall -Wextra -Werror -O2
- O2 will improve performance ##Create a new repository on the command line
- pedantic is not requested but is a good one to check ISO C compliance
Issue all the warnings demanded by strict ISO C and ISO C++; reject all programs that use forbidden extensions, and some other programs that do not follow ISO C and ISO C++. For ISO C, follows the version of the ISO C standard specified by any -std option used.
You can read the details about each flag on gccgnu website
You can improve the performance of your program by using what we call preprocessor macros
It can be done easily using the following command line:
reponame='docker'
mkdir $reponame
touch README.md
git init
git add README.md
git commit -m "[INIT] First commit"
git remote add origin [email protected]:agavrel/$reponame.git
git push -u origin master
Run Commands in Background (could be used to recompile automatically each time .c are saved)
You can have multiple processes running in the background at the same time with &
after the command.
However the background process will continue to write messages to the terminal from which you invoked the command.
To suppress the stdout and stderr messages use the following syntax:
command > /dev/null 2>&1 &
>/dev/null 2>&1
means redirect stdout
to /dev/null
and stderr
to stdout
Use the jobs utility to display the status of all stopped and background jobs in the current shell session:
jobs -l
NB: a Job is the process running thanks to the command execution
To bring the job to the foreground use :
fg %ID
NB: you can use bg
to do the reverse, from foreground to background.
To kill the process use:
kill -9 ID
Obviously replace ID
in the above examples with the job ID you got from jobs -l
.
Example with terraform:
sudo mkdir /opt/terraform
unzip ~/Downloads/terraform_0.12.13_linux_amd64.zip /opt/terraform
add to PATH environment variable:
export PATH="$PATH:/opt/terraform"
then create simlink in /user/bin
cd /usr/bin
sudo ln -s /opt/terraform terraform
Update path for current session
source ~/.profile
or
source ~/.bashrc
Email me or submit a pull request
Antonin GAVREL