A Student's C Book: 1.4. Control Flow

Level 1. Introduction to C

1.4. Control Flow

Branching is a strategy to make perfect plans in the imperfect or incomplete world. 

The control flow of a program execution is the path of sequential instructions the computer executes while running the program. So far, you have seen a linear and non-branching control flow where the computer executes each instruction in the main() function. However, we can change this behavior and make the computer sometimes skip some instructions or decide between multiple execution paths depending on some conditions. Before moving to the next section, I would like to mention one thing about a new data type you will need to keep in mind for this tutorial. The new data type I would like to introduce is the boolean or bool type. The boolean type is used to represent logical truth values, such as true and false. All conditional expressions (e.g., 3 < 5, 4 > 4, and so on) in C are evaluated to one of these boolean values. I mean, a condition in math must either be true or false at the end of the day. It cannot be neither, and it cannot be both. In C programming, the truth values are represented as numbers. false is always represented as the number 0, and true is represented as any non-0 number. With this being said, you can now start reading the next sections more comfortably.

Branching on a condition

Let's say that according to the statistics on the population heights, the average height for men is 178 cm. So, anyone above 178 cm is considered taller than the average, and anyone below that is considered to have a relatively shorter height. Now, let's say you want to help people to know whether they are higher, average, or shorter than the average. Because you know the average height, anytime a random person would ask you if he is taller than the average, you would ask him his height and compare his height to the average, and then you would say things like "you're taller", "you're average", and "you're shorter" if his height is above the average, equal to it, and below the average, respectively. What you say to the person in front of you depends on his height, obviously. Now, you would like to write a C program that does exactly what you were doing. You need to tell the computer when to print what sentence. For that, you need to use branches. Branching means executing different commands or instructions depending on whether a given condition is satisfied or unsatisfied. In C language, one way of branching is by using the if block. Here is what the generic syntax for it looks like:

if ( CONDITION is satisfied ) {
    // do something
}

I will give you an example right away:

if(3 > 7) {
    printf("3 is greater than 7");
}

If you put the code snipped above inside the main function in a blank C program and ran it, it would not print "3 is greater than 7" on the screen because the computer would check the condition (i.e., if 3 > 7) and know that it is false. Since the condition was not satisfied, it would not execute the statements inside the if block (i.e., statements within the if's scope or body).

if-else block

We can specify the things the computer needs to do when a given condition is satisfied or true. Can we also specify what to do if the underlying condition is not true (i.e., false)? The answer is yes. All we have to do is to use the logical inverse of the condition in another if block. For example, if the initial condition is $3 < 7$, then the logical opposite of this is another condition reading $3 \geq 7$ (in programming, we denote the mathematical $\geq$ inequality operator by using >= and the $\leq$ operator by using <=). Let's look at a simple example that uses conditions on a variable:

if(x < 5) {
    printf("x is less than 5");
}
if(x >= 5){
    printf("x is not less than 5");
}

The order of the if blocks does not matter here since the conditions are mutually exclusive (i.e., whenever one of them is true, then the other one must be false, and vice versa). So, only one condition will be true at any given run-time, and hence, only one printf() will be executed. Let's suppose that $x = 3$. The computer will first check the first if block's condition (i.e., if x < 5) and proceed to print "x is less than 5" since the condition $3 < 5$ is true. Then, the computer will check the second if block's condition (i.e., if 3 >= 5) and skip printing the "x is not less than 5" string since 3 is not bigger than or equal to 5. If we switched the places of the two if blocks, nothing would change in the output. Here is the new snippet in the opposite order:

if(x >= 5) {
    printf("x is not less than 5");
}
if(x < 5){
    printf("x is less than 5");
}

The computer would skip the first block's printf() and execute the second block's printf() function, and a a result, the same text "x is less than 5" would appear on the screen regardless of the order. Again, this is true because the conditions are mutually exclusive. In the code snippet given below, both printf() functions would be executed if $x = 4$:

int x;
if(x >= 3) {
    printf("x is not less than 3");
}
if(x < 5){
    printf("x is less than 5");
}

In the code snippet above, "x is not less than 4" would be printed if and only if $x \geq 4$, and "x is less than 5" would be printed if and only if $x < 5$. This is obvious. However, there are specific intervals of $x$ for which either only one of the strings is printed or both of them are printed. To find the intervals, we should analyze the values and the mutually non-exclusive conditions. Both conditions ($x \geq 4$ and $x < 5$) are satisfied whenever $x \in [3, 5)$, and since $x$ must be an integer (by looking at its type int), the interval practically is $x \in [3, 4]$ (more rigorously, $x \in \{3, 4\}$). Then we have two other intervals, $x \in (-\infty, 3)$ and $x \in [5, +\infty)$. In the former interval, only the "x is less than 5" string would be printed, and in the latter interval, only the "x is not less than 3" string would be printed. Now, we understand the behavior of this little C code better than we did before.

Whenever you find yourself in a similar situation where you need to tell the computer to do one thing if some condition holds and another thing when the same condition does not hold, you can use if-else blocks instead of two consecutive if blocks, as shown previously. The else block always has to follow the if block, and the statements inside the else block are going to be executed if and only if the condition of the initial if block does not hold. Let's rewrite the previous code snipped using the if-else block for demonstration:

if(x < 5){
    printf("x is less than 5");
}
else{
    printf("x is not less than 5");
}

Notice how the else block does not have any conditional expression attached to it. This is because the computer automatically goes inside the else body whenever the condition attached to its preceding if block  is false.

else-if block

Now, we would like to detect and print something depending on whether $x < 5$, or $x > 5$, or $x = 5$ (in programming, single equality sign is used only for assignments and not conditionals, so, we need to use double equals == for checking if the left-hand side equals the right-hand side of the expression). We could do this as shown below:

if(x < 5){
    printf("x is less than 5");
}
else{
    if(x > 5){
        printf("x is bigger than 5");
    }
    else{
        printf("x is equal to 5");
    }
}


goto statement

There is actually a statement in the C language that you can use to change the control flow of the program execution arbitrarily in a very flexible and somewhat dangerous way. The statement I am talking about is the goto statement. Here's how it works:

  1. You put a label before a piece of code that will be executed when some condition is true;
  2. Somewhere appropriate in the code, you put an if block checking whether some condition is met, and you put a goto statement in the if body by using the same label you put before the piece of code that needed to be executed whenever the condition was satisfied.
For example,

#include <stdio.h>
int main(){
    int age;
    scanf("%d", &age);

    if(age < 18){
        goto MY_LABEL; // the goto statement
    }
    else{
        printf("You are an adult.\n");
        goto END; // another goto statement
    }

MY_LABEL: // this is a label
    printf("You are not an adult.\n");
    
END: // this is also a label
    return 0;
}

Let's take a careful look at the full code C program shown above. There are two goto statements and two labels. The goto statement, when executed by the computer, makes the computer jump directly to the given label's location in the program and continue the execution from that point. I should also mention that to put these labels in the code, all you have to do is type an arbitrary title (it cannot begin with special characters, such as ?, !, #, $, %, ^, -, +, (, ), *, &, @, ~, <, >, etc., or numbers but could be in small or capital letters and contain numbers and the _ character) and then put a colon (:) after it. If we analyze the code above, we will see that the first if block has a single goto statement in its body that jumps to the label named MY_LABEL. Jumping to the MY_LABEL location in the program means that the computer will start to execute the last printf() statements (i.e., it will print "You are not an adult.") after which it will go the next return 0; statement, which is under the label named END. Recall that the labels do not affect the program flow on their own without any goto statements; they are just location specifiers to be used with the goto statements. It is the goto statements that make the execution flow of the program change, not the labels themselves. So, if the age is less than 18, the computer will jump to MY_LABEL to print "You are not an adult." and then finish by returning 0. If the age is not less than 18 (i.e., the else block), then it will print "You are an adult." and jump to END to finish by returning 0. If we did not make the jump to where the return 0; statement was (i.e., the label named END), the computer would go to the next instruction after the else block (and that would result in printing "You are not an adult."), which is not the correct behavior that we expect to happen.

Branching back is called Looping

As you just learned about the goto statement, you may have probably thought how powerful (and potentially dangerous) that statement was. Unlike the if-else blocks, we can either jump forward or backward by using a goto statement. This capability makes goto a very powerful statement. Since we can jump backward in the code depending on some condition, we can write the following without breaking any rules of the C language:

#include <stdio.h>
int main(){
    int i = 0;
    
DO_THIS_10_TIMES:
    printf("%d\n", i);
    i = i + 1;
    if(i < 10){
        goto DO_THIS_10_TIMES;
    }
    printf("End.");

    return 0;
}

The program given above would produce the following output:

0
1
2
3
4
5
6
7
8
9
End.

We cannot produce such a behavior shown above by using only if-else statements. The if-else statements always jump forward in the program while choosing one of two or more possible execution paths. However, we need to jump backward if we want to re-execute the same set of instructions over and over again for some number of times.

Jumping back in the program execution to re-execute the same piece of code multiple times is called looping. Loops are an effective way for programmers to not repeat themselves in an utterly inelegant way while writing programs. If one needs to write a program that prints "Hello, World!\n" 5 times or a program that counts from 43 to 320, loops can be used to avoid typing out the whole thing that has a very obvious repetitive pattern to it. Although goto can be used for this purpose, it is potentially very unhinged and error-prone. The reason it is potentially dangerous is that you can jump anywhere (forward or backward) in the program, and the execution flow will continue sequentially from that point forward unless another goto is encountered. The fact that a human programmer needs to keep remembering and/or rereading the whole different sections of the code over and over again makes the use of goto potentially dangerous. It can cause a lot of "stupid" bugs because humans are not the best when it comes to keeping track of every little detail in different parts of the code simultaneously. Due to this issue, there are more hinged and sane looping mechanisms that are considered to be safe to use. Now, you'll see what safe looping looks like.

while() loop

The first safe looping mechanism includes the use of while block. This block is very similar to the if block. In fact, it is exactly the same as the if block syntactically. Semantically, the difference between them is that the if block executes the statements present in its body only once whenever the corresponding condition is met, whereas the while block executes the statements present in its body as long as the corresponding condition is met. Let's take a look at the generic format of the while block.

while ( CONDITION ) {
    // while body: do something
}

To demonstrate how it works in practice, let's write a simple program that prints the current iteration number and the string "Hello, World!" in a new line 10 times.

#include <stdio.h>

int main(){
    int i = 0;
    while(i < 10) {
        printf("Iteration: %d; ", i+1); 
        printf("Hello, World!\n");
        i = i + 1;
    }
    return 0;
}

The program shown above produces the following output when executed:

Iteration: 1; Hello, World!
Iteration: 2; Hello, World!
Iteration: 3; Hello, World!
Iteration: 4; Hello, World!
Iteration: 5; Hello, World!
Iteration: 6; Hello, World!
Iteration: 7; Hello, World!
Iteration: 8; Hello, World!
Iteration: 9; Hello, World!
Iteration: 10; Hello, World!

Obviously, you could do the same without using any sort of loop by writing printf("Iteration: 1; Hello, World!\n"); followed by printf("Iteration: 2; Hello, World!\n"); followed by another printf("Iteration: 3; Hello, World!\n");, and so on. This is possible, although very inelegant and error-prone. However, what you could not have done is to get the number of iterations dynamically from the user during the program execution and print "Hello, World!" text that many times on the screen. This is because you do not know which number the user would input while you are writing your program before the execution phase. That's when using a loop is unavoidable. Consider the following piece of code:

#include <stdio.h>
int main(){
    int n = 0;
    scanf("%d", n);

    int old = 0, curr = 1;
    int iter = 1;
    while(iter < n){
        int tmp = curr;
        curr = curr + old;
        old = tmp;
        iter = iter + 1;
    }
    
    if(n == 0){
        curr = 0;
    }
    printf("fib(%d) = %d", n, curr);
    return 0;
}

The program given above prints the Fibonacci number at the index specified by the user. For example, if the user input was the number 4, then the output would be 3. Let's try to unfold the while loop and understand how the computer would come up with the correct Fibonacci number.

n = 4;
old = 0; curr = 1;
iter = 1;
check if (1 < 4) (true) {
    int tmp = curr(1);          // tmp = 1;
    curr = curr(1) + old(0);    // curr = 1;
    old = tmp(1);               // old = 1;
    iter = iter(1) + 1;         // iter = 2;
}
check if (2 < 4) (true) {
    int tmp = curr(1);          // tmp = 1;
    curr = curr(1) + old(1);    // curr = 2;
    old = tmp(1);               // old = 1;
    iter = iter(2) + 1;         // iter = 3;
}
check if (3 < 4) (true) {
    int tmp = curr(2);          // tmp = 2;
    curr = curr(2) + old(1);    // curr = 3;
    old = tmp(2);               // old = 2;
    iter = iter(3) + 1;         // iter = 4;
}
check if (4 < 4) (false) {
    // END OF THE WHILE LOOP
}

if (n == 0) (false) { ... }
print on screen: fib(4) = curr(3);

As you have already learned about this, the computer stores only the last updates made on each variable. That is why the variables old, curr, and iter only refer to the numbers that they have been reassigned to the most recently. The semantic meaning of the variable old is to refer to the $\mathtt{fib}_{n-1}$, and the variable curr is to refer to the current $\mathtt{fib}_n$. Since $\mathtt{fib}_{n+1} = \mathtt{fib}_n + \mathtt{fib}_{n-1}$, we manipulated the old and curr variables to refer to different successive pairs of Fibonacci numbers in the sequence. This process can be once again illustrated as shown below:

old = 0, curr = 1 (Fibonacci sequence: 0, 1, 1, 2, 3, 5, ...)
old = 1, curr = 1 (Fibonacci sequence: 0, 1, 1, 2, 3, 5, ...)
old = 1, curr = 2 (Fibonacci sequence: 0, 1, 1, 2, 3, 5, ...)
old = 2, curr = 3 (Fibonacci sequence: 0, 1, 1, 2, 3, 5, ...)

Since to computer the next number in the sequence, the current number, and the number that comes right before it in the sequence is enough according to the Fibonacci formula, we update the curr variable to point to the current variable and the old variable to point to the number the comes right before it. As we compute the next number by doing curr = curr + old; inside the while block, now the curr variable points to the next number, and since its value is lost now, we keep it in another temporary variable tmp by writing int tmp = curr;. We use this temporary value (i.e., the value that the curr used to hold) to reassign the old variable to the one that used to be stored in the curr variable before the update, and hence, we write old = tmp;. Finally, we increment the iter by 1 in order to indicate the current iteration, which also refers to an index in the Fibonacci sequence.

Now you know how the while block works, it is time to mention one last thing about it. There is a slightly different version of while that is called the do-while block. The difference between them is that the former first checks the condition and then proceeds to execute the body if the condition is true whereas the latter first proceeds to execute the body (i.e., whether the condition in the while part is true or false) and then checks the condition in order to decide whether to re-execute the body again or break out of the loop. Its syntax is as follows:

do {
    // do something repeatedly
} while ( CONDITION );

So, even though the condition given to the do-while block is false initially, it will still execute the body once because the condition-checking part comes after the body (unlike the while block).

for( ; ; ) loop

Another way of looping in C is by using the for block. It is similar to the while block, and the main difference is that the for block may also deal with the temporary variable definitions and manipulations related to the condition based on whose truth value its body is executed. It has the following abstract syntax:

for ( VARIABLE_DEFINITIONS ; CONDITION ; VARIABLE_MANIPULATIONS ) {
    // do something repeatedly as long as the CONDITION holds
}

To illustrate it on a simple, practical example, let's suppose that we would like to print the "Hello, World!\n" string 10 times by using the for loop. The integer that we will need to declare and define is going to be iterated from 0 to 10, exclusive. With the while loop, we would need to define this variable (let's name it iter) before the condition of the block (outside the while block), which is iter < 10. Then, inside the while body we would need to write iter = iter + 1 as the last instruction to increment its value by one each time "Hello, World!\n" is printed onto the screen. These two things (i.e., the temporary variable definition - int iter = 0; and the variable manipulation - incrementing iter by one) can be moved inside the for block along with where the condition (i.e., iter < 10) is put. This is done as shown below.

for(int iter=0; iter<10; iter=iter+1){
    printf("Hello, World!\n");
}

It is worth mentioning that the VARIABLE_MANIPULATIONS that are passed right after the CONDITION of the for block are going to be executed only after all the instructions in the for body are executed. Since the VARIABLE_DEFINITIONS, CONDITION, and the VARIABLE_MANIPULATIONS are all optional (when the CONDITION is not passed, the for loop assumes that the non-existing condition is automatically true and, therefore, executes its body indefinitely as infinitum), we could also rewrite the code snippet shown above like this:

int iter = 0;
for( ; iter<10; ){
    printf("Hello, World!\n");
    iter = iter + 1;
}

This now looks more like a while block. Also note that how the iter = iter + 1; line is put after the last instruction in the original for block's body (that is, the printf("Hello, World\n"); statement). Let's now look at a different example.

#include <stdio.h>

int main(){
    int i = 0;
    for(int i=0; i<10; i=i+1){
        if(i%2 == 0){
            printf("%d is even\n", i);
        }
        else{
            printf("%d is odd\n", i);
        }
    }
    return 0;
}

This program will produce the following output:

0 is even
1 is odd
2 is even
3 is odd
4 is even
5 is odd
6 is even
7 is odd
8 is even
9 is odd

If you wonder about the % operator, it stands for the modulo or remainder obtained from the division of two numbers. So, 3%2 is 1 because the remainder is 1, and 6%2 is 0 for the likewise reason. 

Breaking out of the loop

There is an instruction called break that breaks out of any sort of while, do-while, and for loop. It does not work for the loops made possible by the goto statements. How the break works is pretty simple and very straight forward. The break statement breaks/jumps out of the loop in whose body it is directly present. Let's see the following example.

while(1){
    printf("Hello, World!");
    break;
}

The code snippet above prints the "Hello, World!" string only once and then goes out of the loop. Although the condition is always a non-zero number, which is evaluated to the boolean value of true automatically, the break instruction, when executed by the computer, will cause the termination of this otherwise infinite loop. Let's see another example where break will cause the inner loop to break but not the outer one.

for(int i=0; i<3; i=i+1){
    while(1){
        printf("Hello, World!");
        break;
    }
    printf("\n---\n");
}

The code snippet shown above produces the following output:

Hello, World!
---
Hello, World!
---
Hello, World!
---

The "Hello, World!" string is printed only three times because the break statement causes only the inner while loop to terminate immediately after printing. The reason it does not affect the outer for loop in this example is that it has been directly typed inside the while loop and, therefore, decides only the fate of the while loop. In contrast, we can break out of the outer for loop as shown below:

for(int i=0; i<3; i=i+1){
    int j = 0;
    while(1){
        printf("Hello, World!");
        break;
    }
    if(i == 1){
        break;
    }
    printf("\n---\n");
}

The output would look like this:

Hello, World!
---
Hello, World!

Notice how the "Hello, World!" string is printed only twice. This is because of the if condition inside the for loop that breaks when i equals 1 -- that is, i starts from 0 and the "Hello, World!" string is printed, then it is incremented to 1 and the same string is printed and the for loop terminates before i is incremented to 2). Also, notice how the "\n---\n" string is printed only once, and there are no triple dashes after the last "Hello, World!" unlike the previous example. This is because the break statement inside the if block is executed before the following printf("\n---\n"); instruction when i is equal to 1, and this causes the computer to jump out of the loop even though there might still be some instruction left to be executed for the current iteration.

As one last example, let's look at the following program:

#include <stdio.h>

int is_prime(unsigned int num){
    int divisor_found = 0;
    for(unsigned int i=2; i<num; i=i+1){
        if(num % i == 0){
            divisor_found = 1;
            break;
        }
    }
    return 1 - divisor_found;
}

int main(){
    unsigned int min, max;
    printf("Enter min number: ");
    scanf("%d", &min);
    printf("Enter max number: ");
    scanf("%d", &max);
    
    for(unsigned int num=min; num<max; num=num+1){
        if(is_prime(num)){
            printf("%u is prime\n", num);
            break;
        }
        else{
            printf("%u is not prime\n", num);
        }
    }
    return 0;
}

Before looking at the correct output, think about it by yourself as an exercise. Do you think you have found the correct answer? Go ahead and compare yours with the one shown below.

Enter the min number: 8
Enter the max number: 200
8 is not prime
9 is not prime
10 is not prime
11 is prime

So, the behavior of the program above is the print numbers starting from the min value (given by the user) until either a prime number has been found or the max value (also given by the user) has been reached without any primes in between the $[\mathtt{min}, \mathtt{max})$. It should be evident that the last printed number must always either be a prime or the max value itself.

Skipping an iteration

You have already learned about the break statement. It breaks out of the loops. Now, it is time to learn about another statement that just skips an iteration instead of breaking or jumping out of the loop that contains the statement. This statement is called continue. Whenever executed, it makes the computer to skip one iteration of the current loop. To be more clear, skipping an iteration means jumping to the beginning of the next iteration from the place the continue instruction is executed in the current iteration. Let's see a quick example.

for(int i=0; i<4; i=i+1){
    printf("Beginning of iteration %d\n", i);
    if(i >= 2){
        continue;
    }
    printf("End of iteration %d\n", i);
}

The code snippet above produces the following output:

Beginning of iteration 0
End of iteration 0
Beginning of iteration 1
End of iteration 1
Beginning of iteration 2
Beginning of iteration 3

Notice how the "End of iteration 2" and "End of iteration 3" strings are missing from the output. It is because when i reaches values above or equal to 2, the if block is executed, which has a single continue statement. As soon as this statement is executed, the execution flow jumps to the beginning of the next iteration without executing the instructions that came after the executed continue statement. However, for the first couple of iterations, everything is printed since the if condition is false (i.e., when i=0 and i=1), resulting in skipping the continue instruction. Like the break statement, the continue statement does not affect outer loops either. Let's see another simple example to demonstrate this.

for(int i=0; i!=2; i=i+1){
    for(int j=0; j<3; j=j+1){
        printf("i=%d, j=%d\n", i, j);
        continue;
        printf("This is never printed.\n");
    }
    printf("This is printed.\n");
}

The code snippet above produces the following output.

i=0, j=0
i=0, j=1
i=0, j=2
This is printed.
i=1, j=0
i=1, j=1
i=1, j=2
This is printed.

The "This is never printed.\n" string is not printed since there is an unconditional continue statement that is going to be executed in each iteration of the inner for loop. However, this statement does not affect the outer for loop, and that is why we see the "This is printed." text on the screen.

To demonstrate the difference between the break and continue statements explicitly, let's look at the example shown below.

for(int i=0; i<3; i=i+1){
    printf("Beginning of iteration %d\n", i);
    break;
    printf("End of iteration %d\n", i);
}
for(int i=0; i<3; i=i+1){
    printf("Beginning of iteration %d\n", i);
    continue;
    printf("End of iteration %d\n", i);
}

The first for loop will produce the following output:

Beginning of iteration 0

In contrast, the second for loop will produce the following output:

Beginning of iteration 0
Beginning of iteration 1
Beginning of iteration 2

I hope the distinction is obvious from this example. break jumps out of the loop, whereas continue jumps out of the iteration within the loop.

Table of Contents

  1. Preface
  2. Level 1. Introduction to C
    1. Hello, World!
    2. Basics
      1. Your computer can memorize things
      2. Your computer can "talk" and "listen"
      3. Compiling and Running programs
    3. Functions
      1. I receive Inputs, You receive Output
      2. Simple pattern matching
      3. Function calling and Recursion
    4. Control Flow $\leftarrow$ you are here
      1. Branching on a condition
      2. Branching back is called Looping
    5. Pointers
      1. Memory address of my variable
      2. Pointer Arithmetic
    6. Arrays
    7. Data Structures
      1. All variables in one place
      2. Example: Stack and Queue
      3. Example: Linked List
  3. Level 2. Where C normies stopped reading
    1. Data Types
      1. More types and their interpretation
      2. Union and Enumerator types
      3. Padding in Structs
    2. Bit Manipulations
      1. Big and Little Endianness
      2. Logical NOT, AND, OR, and more
      3. Arithmetic Bit Shifting
    3. File I/O
      1. Wait, everything is a file? Always has been!
      2. Beyond STDIN, STDOUT, and STDERR
      3. Creating, Reading, Updating, and Deleting File
    4. Memory Allocation and Deallocation
      1. Stack and Heap
      2. Static Allocations on the Stack
      3. Dynamic Allocations on the Heap
    5. Preprocessor Directives
    6. Compilation and Makefile
      1. Compilation Process
      2. Header Files and Source Files
      3. External Libraries and Linking
      4. Makefile
    7. Command-line Arguments
      1. Your C program is a function with arguments
      2. Environment variables
  4. Level 3. Becoming a C wizard
    1. Declarations and Type Definitions
      1. My pointer points to a function
      2. That function points to another function
    2. Functions with Variadic Arguments
    3. System calls versus Library calls
      1. User mode and Kernel mode
      2. Implementing a memory allocator
    4. Parallelism and Concurrency
      1. Multiprocessing
      2. Multithreading with POSIX
    5. Shared Memory
      1. Virtual Memory Space
      2. Creating, Reading, Updating, and Deleting Shared Memory
      3. Critical Section
    6. Safety in Critical Sections
      1. Race Conditions
      2. Mutual Exclusion
      3. Semaphores
    7. Signaling
  5. Level 4. One does not simply become a C master

Comments

Popular posts from this blog

0, 1, and beyond

The CoBra Project

Books