A Student's C Book: 1.2. Basics

Level 1. Introduction to C

1.2. Basics

Your computer can memorize things

One of the things that you can make your computer remember is integer numbers. As one would do in math, you can assign numbers to variables (usually to reuse them later on when needed). Roughly speaking, this is how computers remember things. You use a variable to make a computer remember a number. You may ask why there needs to be a variable to remember a number. Well, let's imagine that you were to be given multiple facts to memorize. For simplicity, I'll only assume two of them: Alice is 3 years old, and Bob is 5 years old. Now, you are asked about Bob's age. If you didn't associate 3 and 5 with the names Alice and Bob, respectively, then you wouldn't be able to answer this question with certainty. So, your mind probably did something similar to what we do in math -- use variables to represent those numbers, that is, Alice = 3 and Bob = 5. That's why you were able to answer the question correctly and with certainty: because you knew that Bob's age had to be a number assigned to the variable named Bob and not Alice. In fact, we always either implicitly (in our mind) or explicitly (in math) use abstract variable names to represent numbers. For this reason, computers are the same.

One little detail about computers memorizing different things is that they also need to be explicitly told the type of thing they are about to memorize. For example, to make your computer memorize an integer 3 as the age of Alice, you need to tell three pieces of information to the computer:

  1. the thing to be memorized is an integer;
  2. the variable name it is associated with is Alice;
  3. the integer is 3.

All three sentences above are packed into a single statement in the computer C language, as shown below.

int Alice = 3;

The general pattern to make your computer memorize something is the following:

[Type_Of_The_Thing_To_Memorize] [Variable_Name] = [The_Thing_To_Memorize];

It is also worth mentioning that to recall the thing memorized (e.g., the integer 3), we can and will use the associated variable (e.g., Alice) -- that is, asking the question "What number was the variable Alice equal to?" is enough to get the integer 3 as the answer from the computer. Now, it should be obvious why there needs to be variables and not just stand-alone numbers. If we did not have any variable or any association for the integer 3, then the only way to make the computer recall that number and say it back to you would be by asking the following question: What number was 3 equal to? That would be pretty dumb and meaningless, right? In real life, this would look like the scenario where you don't remember someone's phone number, but you also don't know who you want to call; it would be impossible for you to ask for any help from other people to find the phone number since no one would know whose phone number you are looking for. The only solution would be to ask for a phone number that is exactly the same as the phone number you are looking for. This is obviously paradoxical because if you knew the phone number in the first place, why would you try to ask it or "re-remember" it? Obviously, this is not how the recalling works. You can only recall things when there are certain associations that relate those things to some other things that you already know and can remember easily. Okay, okay... Enough with the philosophy. Let's see what other types of things computers can memorize and recall.

Data Types Description
intinteger type
float
double
real number type with less precision
real number type with more precision
charcharacter or symbol type (e.g., 'a' or '3' or '?')
unsigned int 0 and positive integer (i.e., natural number) type
long int big integer type
long double big real number type with more precision
short int small integer type
long long int very big integer type
unsigned short int small natural number type
unsigned long int big natural number type
unsigned long long int very big integer type
signed int same as int
signed short int same as short int
signed long int same as long int

Equality in programming is not the same as equality in mathematics

You can reassign different numbers to the same variable in programming. Keep in mind that the variable's content (its value) will change only after a new assignment statement (i.e., a statement assigning a new number to the same variable). This can be illustrated as follows:

int Alice = 3; // initial value of Alice is 3
Alice = 4; // Alice has the value 4 now
int Bob = 10; // Alice still equals 4
Alice = 7; // Alice's value is updated to 7, and Bob still holds 10
Bob = 11; // Alice has the same value 7 
Bob = 20; // Alice has the same value 7
Alice = 30;

Your computer remembers only the last updates on every variable. In between two updates or assignments, the variable's value stays the same as it was indicated on the right-hand side (RHS) of the previous assignment statement. That is why we did not see any change in Alice's value from line 4 up until line 7.

Now that you know about variable reassignments in C, it is time to blow up your mind for the first time. The following code is perfectly correct in C:

int age = 3;
age = age + 2;

Wait..? Whaaat?! Yes, you read that right. The code snipped given above is perfectly correct because the equality operator in C programming is not the same as the equality sign in mathematics. In math, equality between a variable x and an expression E in general stands for "x and E are evaluated to the same final number or result." In programming, it actually means something different: x now holds the value evaluated from E. So, saying "let $x=4$" and then "$x=4+1$" would be incorrect in math because you always define your variables ones, and their values are not supposed to change during the mathematical operations. However, in programming, variables can be modified to hold different values than what they initially held, and therefore, the same x = 4 + 1; statement in programming would mean that the variable x now holds its old value incremented by one. If we want to increment the old value by one but do not know what the old value is, we can instead write x = x+1;.

In mathematics, we don't typically have this notion of redefining things because we use ordered sets to keep track of each definition for each variable. For example, if we needed to simulate the variable reassignment shown previously (i.e., x = x + 1;) in mathematics, we would do something like this instead: $\text{let}\ x_0 = 4$ and $x_1 = x_0 + 1$. Here, $x_0$ represents the initial value of x, and $x_1$ the new incremented value. Then we could also use the initial or new value by using these indexed variables. However, we would not be able to use the initial value of x after reassigning it to a new number in programming; that is, that information would be lost. In mathematics, unlike the C programming, there is no information loss in this regard. That's why we use ordered sets (indexed variables) to "modify" variables.

Assignment in C programming works the way it does because of the memory efficiency. Since programming can be considered applied math, we don't want to store every step of the evolution of a variable unnecessarily. Instead, the default behavior is to put the new number back in the same old place of the variable, which makes the same variable hold a different number afterward. However, if we needed to do it in a mathy style where each modification is stored along with the initial assignment, we could also do it by using the concept of arrays that I will now talk about in this post. You'll learn about them a few posts later. Please just be patient.

To wrap up this subsection, just remember the following. It is assumed that variables in math are all conceptual and, hence, not tied to any physical location in the real world. In contrast, variables in C are tied to actual little memory cells in your computer. That is why saying "let $x=3$" means defining $x$ to be the same as the number 3 in math, and saying x=3; means putting the number 3 in the variable x's memory cell in programming. Due to this subtle difference, every new reassigned value to the same variable makes its original content be deleted from that particular memory location permanently, whereas reassignments to the exact same variable aren't even possible nor needed in mathematics because we can store infinitely many of them (a mathematical variable is not tied to any place physical). If you are still asking the "But why?" question, then go search about how classical mathematics is non-constructive and declarative and how C programming is constructive and imperative.

Your computer can "talk" and "listen"

In the previous post, we saw that two computer bots were talking to each other in a precise and somewhat rude way (that's fine). But how can we make our computer talk to us instead of other weirdos? An even better question is, how can WE talk to our computers... instead of other weirdos? You know, these are important questions if we are going to live our lives with our computers for many, many years. They say being able to communicate properly is the key to a happy marriage.

You have already seen one function that enables the computer to talk by displaying a message on the screen. Yes, that's the good ol' printf() function. Now, it is time to learn how a computer can listen to what we have to say to it. The function for that is scanf() function that scans a user's input to the computer by using a keyboard. So, printf() prints and scanf() scans. Makes sense. However, when the computer waits for user input, it also needs to be told where to keep or store the entered input in the memory. Pretty stupid, right? Computers have memory, but they also need to be told to use it for the good. At this point, we have to remind ourselves that our computers are pretty "stupid" for these obvious reasons.

The printf(...) function

Your computer does not have a mouth like we do. So, the simplest way of making your computer "talk" to you is by getting it to display something on its screen so that we can read what it says. The command that makes the computer display something on the screen is the printf() function. It is a printing function, so the name makes sense. It has multiple parameters (this is to say, it takes multiple arguments upon the function calling). However, you can just give it a single argument, and it will still work fine. In that argument, you should specify what you want the computer to print/display on the screen. For example, if you wanted your computer to print Hello, World! on the screen, then you would do something like this inside the main() function:

printf("Hello, World!");

Note that the thing that you want to be printed on the screen must be in between a pair of double quotes ("). If you did not put it in between " " (as in printf(Hello, World!);), it would not work and give you an error. The reason is that whenever you type anything that is not in between the double quotes, your computer does not treat it as plain, innocent text. Instead, it tries to interpret it either as a data type, a variable name, a number, a function, or a correct mixture of these or something else that directly commands the computer to do something. In our case, neither Hello, and World! inside the printf() function is a valid statement and actually causes the computer to think that they are two separate things due to the white space in between. On the other hand, printf("Hello, World!"); is perfectly understandable by the computer because it treats Hello, World! as a whole and as something that is neither a data type, a number, a function, a mixture of these, nor another command; it rather treats it as a plain text given as an argument to the printf() function. Then, the printf() function displays this text on your computer's screen. The printf() function is not a known command to the C program by default. To make things work as expected, you should also tell where your computer can find this function by using the #include keyword as shown below:

#include <stdio.h>
int main(){
    printf("Hello, World!");
    return 0;
}

What about the other arguments that we did not provide to the printf() function? What are they useful for? Well, I'll demonstrate with an example. Let's assume that there is a variable x in your program, and you would like to print the value it holds in the computer's memory. How would you do it? Here is what would not work:

#include <stdio.h>
int main(){
    int age = 34;
    printf("age");
    return 0;
}

The code above would just produce the following output on your screen:

age

Remember how putting quotes around symbols made your computer interpret it as plain text and not a variable name? That's the reason "age" is printed and not its value "34". If you think that we should get rid of those quotes, then (to let the computer know that it is the variable name and not an innocent piece of text), you are halfway there. The only thing, other than removing those double quotes, that needs to be done here is to tell the computer what type of variable we are trying to print the value of. This is done by passing a proper so-called format string as the first argument of the printf() function. We cannot just put int keyword as the first argument because it is a direct data type and not the format string that corresponds to the integer data type. This is how the printf() function works... It expects a format string and not the data type directly. As our variable could be int, float, double, or char, there is a different format string that corresponds to each one. The list of the format strings for different data types is given below in Table 2.

Data Types Format String
int"%d"
float
double
"%f"
"%lf"
char"%c"
unsigned int "%u"
long int "%ld"
long double "%Lf"
short int "%d"
long long int "%lld"
unsigned short int "%u"
unsigned long int "%zu"
unsigned long long int "%lld"
signed int "%d"
signed short int "%d"
signed long int "%ld"

Since the first argument of the printf() function always needs to be a format string, which is also a plain text (since it uses a pair of quotes), the variable (whose value we want to be printed on the screen) has to be put as the second argument. This is done as shown below:

#include <stdio.h>
int main(){
    int age = 43;
    printf("%d", age);
    return 0;
}

This code will produce the following output:

43

Now, we can make it more human-readable by also inserting some human-readable text inside the format string:

#include <stdio.h>
int main(){
    int age = 43;
    printf("My variable (age) has the value %d. It works!", age);
    return 0;
}

This code will produce the following output:

My variable (age) has the value 43. It works!

Now, you would probably be surprised if I told you that you can actually keep adding as many arguments as you want into the printf() function as long as their types are specified in the format string. Let's look at a simple example to demonstrate this real quickly:

#include <stdio.h>
int main(){
    int age = 43;
    printf("My variable (age) has the value %d. My height is %f meters.", age, 1.8);
    return 0;
}

The code above will produce the following output:

My variable (age) has the value 43. My height is 1.8 meters.

Now, let's have more printf's and see what happens:

#include <stdio.h>
int main(){
    int age = 43;
    printf("My variable (age) has the value %d. My height is %f meters.", age, 1.8);
    char c = 'A';
    printf("My first name starts with letter %c. My surname starts with %c.", c, 'B');
    return 0;
}

The code above will produce the following output:

My variable (age) has the value 43. My height is 1.8 meters. My first name starts with letter A. My surname starts with B.

It prints them on the same line... Why? Because computers are dumb. That's why. If you don't specify when to go to the new line on your screen it will keep staying on the same line forever. To specify a new line in the format string, you have to use \n character. Let's look at an example:

#include <stdio.h>
int main(){
    int age = 43;
    printf("My variable (age) has the value %d. My height is %f meters.\n", age, 1.8);
    char c = 'A';
    printf("My first name starts with letter %c.\nMy surname starts with %c.", c, 'B');
    return 0;
}

This code will produce the following output:

My variable (age) has the value 43. My height is 1.8 meters.
My first name starts with letter A.
My surname starts with B.

Notice how \n and the character M (in the text "My surname...") has no white space in between them. If we put a white space in between, then the text "My surname starts with..." would not only be printed in a new line, but also that new line would start with a white space and then the text following it. The output would look like this:

My variable (age) has the value 43. My height is 1.8 meters.
My first name starts with letter A.
 My surname starts with B.

All this being said about the printf() function, you should now be able to predict the outcome of the following piece of code easily:

#include <stdio.h>
int main(){
    int age = 43;
    printf("Hello, World!");
    printf(" My %s %c%c %d.\n", "age", 'i', 's', age);
    printf("\nBye%cbye...\n", ' ');
    return 0;
}

If you compiled and ran the C program above, the output on your screen would look like this:

Hello, World! My age is 43.

Bye bye...

The computer would first print the "Hello, World!" string (text) without putting a new line at the end (so we are still on the same line), then the second printf(" My...", ...); would cause putting a single white space after the first string ("Hello, World!") and then print "My age is 43.\n" on the screen. Notice that the string "age" was substituted for the format string "%s" in the first argument of the printf() function, the single characters 'i' and 's' were substituted for two consecutive "%c" and "%c" (thus resulting in having a substring "is"), and the value of the age variable was substituted for "%d" (that is why the second argument was put in between the double quotes and the last one was not). Then, the new line character '\n' was put at the end of the current line, meaning that the cursor has moved one line down. Reading the last printf("\nBye%cbye...\n", ' '); statement, another new line is immediately put (so now we have moved two lines down from the initial string), and the single white space character ' ' was substituted for the format string "%c" right in between "Bye" and "bye" (after the formatting/substitution, the string becomes "Bye bye"). Another new line is added at the end, but since the line was filled with any visible characters/symbols, we are not going to see anything in the last line (as is the case for the second line between the "Hello, World!..." and "Bye bye..." lines).

The scanf(...) function

As the printf() function you just learned about, the scanf() function needs to know what type of user input the computer is expecting (i.e., the so-called format string). It could be an integer, a real number, a single character (like 'a', a single white space ' ', or a new line character '\n'), or something else. However, we cannot just put the keywords int for an integer, float or double for a real number, char for a single character as an argument to this function. It expects them in a special format called a format string. The format string tells the scanf() function the type of input the user will enter (not the context of the input, just the type). However, we also need to remind the computer to not delete the input right after the user enters it and to keep it in some memory location for a while so that it can be used later on. That is going to be the second argument to this function: the memory address to be used by the computer to save (memorize) the user input. But how do we pass an address as an argument to a function in C? Let's see.

Memory in computers is indexed from 0 to some relatively big number M so that a specific memory address can be used by programmers. If you remember from the previous post, we should use a special keyword like intfloat, etc., to tell the computer that we are going to work with the numbers and we need storage to save the results. For example, whenever a programmer writes int a; in a C program, that commands the computer to allocate storage in the memory for a single integer called a. Telling your computer about the type of variable (without telling what is stored in its memory) is called variable declaration. When the programmer then writes a=1 in the same program after the variable declaration, it shouts at the computer to store/save the integer 1 at that location. Telling your computer which value to hold in its memory for the first time is called variable definition. Then, if the programmer wrote a+2, after the definition of a, the computer would be able to calculate this expression mathematically and reach the number 3 as the result of this calculation. It is also worth mentioning that it would not save this result anywhere in its memory since we didn't tell it to do so, and therefore, we would lose the result immediately without being able to print it, let's say.

The scanf() function takes multiple arguments. The first argument specifies the type of thing the user is expected to enter via the keyboard. It could be an integer, a real number (it is actually called a floating-point number in programming), a character, or something else. You probably should remember that there were some special keywords for these types already, as shown in Table 1. However, the first argument of the scanf() function expects to see not one of those data types but instead a so-called format string that can represent any one of them. The format strings for different types are shown in Table 2. The second argument is the variable with which the user input is associated. That is to say, after the user types an input on the terminal and presses the Enter or Return key on the keyboard, the input will be assigned to the variable specified in the second argument of the scanf() function.

Let's say we would like the computer to ask the user to enter his age as an integer. The following code would work just fine for this example:

#incude <stdio.h>
int main(){
    int age;
    scanf("%d", &age);
    return 0;
}

Notice how we passed "%d" as the format string since it is the one that corresponds to integers, and the ampersand (&) sign in front of the age variable. The "%d" indicates that the inputted value will be stored in a variable of type int, and the & sign tells the computer to store the user input in the memory address of the age variable as opposed to some random place. But why didn't we just put age as the second argument instead of &age? Now, I have more explaining to do. The short answer is, again, that computers are dumber than how smart you think they are or should be. A bit longer answer is that computers have internal memory (you might have heard the term "RAM" by now), and they use their little memory cells to store values. This is what memorization is all about in computers. Storing a value in some empty memory cell is analogous to memorizing that underlying value. Each of these memory cells is indexed from 0 to some large number. By using these indices, your computer is able to manipulate the values stored at those memory locations. Figure 1 depicts a computer memory for a better understanding.

Figure 1. Computer memory.

But wait! Is there any way for the C programmers to access those indices? The answer is yes. We have already talked about the importance of having variables to recall those values from the computer's memory. Frankly speaking, those variables are just names for the memory addresses (the terms "memory address," "memory location," and "memory index" refer to the same concept). We use names whenever we do not want to and need to deal with the memory addresses (because, you know, putting the number 31 in the age variable seems more natural to humans than trying to put that value in the memory address 3425238 and then trying to remember this address). That's why when you type something like int a = 1; your computer picks a "random" memory address (let's say 442133) and writes the value 1 into that memory cell. When you need to recall the value you assigned to the variable a, your computer goes into the memory address 442133 and fetches its content (the value 1) for you. However, there are certain cases where you might encounter a function in C that works with the raw memory addresses instead of the beautiful, human-readable variable names. There are strong reasons for that, but I am not going to talk about them here as the "Pointers" section is specifically dedicated to this matter. The scanf() function is one of those functions. Its first argument is the format string, and all the other arguments that you may put in this function explicitly need to be memory addresses (of your variables) and not the variable names. That's where the ampersand sign (&) comes into play. This operator tells your computer that you are interested in passing the raw memory address of your variable. So, while typing age refers to the thing that is stored at the memory address of the variable age, typing &age refers to that memory address where the age is stored. If we typed scanf("%d", age); then your computer would complain because age does not refer to the memory address. It refers to some integer number. Instead, typing scanf("%d", &age); would solve this issue because now your computer knows that whatever the user inputs via the keyboard, it will be stored at the particular memory location &age (whose human-readable name is age). 

But how come we can type int age = 23; but not scanf("%d", age);? The magic is in the = operator in the first statement. Since we cannot use it inside the scanf() function, we do not have the privilege of passing the variable name as opposed to its memory address. However, whenever we can and do use the equality sign in between a variable name (such as age) and a value (such as 23), the computer deals with the ampersand conversion automatically to ease our job. Otherwise, we would have to manually put 23 into the memory address of age by hand, which is time-consuming.

Compiling and Running programs

You have probably wondered, even if it was for a very brief moment, why we always need to first compile C programs and then run them? As a matter of fact, what is the difference between compiling and running a C program? Okay, we will have to extend our analogies further to understand these processes. Running a C program means executing the instructions/statements/commands specified in the source code. This process is also called execution of the program or run-time phase. However, your computer is not actually capable of executing the instructions directly from the C code. Now, what I am about to see may surprise you a bit: C is not the native language of a computer, meaning that it is actually an intermediary language that is easy for both programmers and computers to understand by using some sort of language translation tools. In our case, human programmers do not need any such external translation tool because we are smart enough to do the translation from the natural language to the C language by ourselves. As you are learning C by reading this tutorial is a practical proof of this. However, your computer is dumb. No hard feelings; mine is dumb, too. It needs an external tool (a program or software) to translate a text presented in a C language to the one that it understands in its own language. "But what is the native language of computers?" you might ask. It is non-ironically called the machine language. It is a language where you only use binary numbers as the means of communication. I will not go into the specifications of the machine language in this post, but I will say this to help you see the big picture here: gcc is one of those translator programs that converts a C code to a machine-native code/text. This translation process is called compilation. That is why we need to first compile our programs before making the machine actually execute the instructions specified in it. In the particular case of translator programs that translate programs to the machine language, we call them compilers. So, gcc is a C compiler as fasm is an Assembly compiler, g++ is a C++ compiler, and so on. Now, let's see how we can use gcc compiler to compile/translate our C programs.

gcc -o [EXECUTABLE_NAME] [SOURCE_CODE]

The template shown above illustrates a simple use case of the gcc compiler. According to this usage, when we type gcc -o translated_version_of_my_code code.c on the terminal and hit ENTER or RETURN, the gcc will read the source code inside the file named code.c and it will translate it to the machine-readable version (since this version of the code is executable by a computer, it is also called an executable). Here, -o [EXECUTABLE_NAME] is to tell gcc to rename our executable to whatever we specify after the -o flag. In our case, gcc will save the executable as translated_version_of_my_code. To run this executable (i.e., to make the computer to read it and execute the specified instructions), you should then type ./[EXECUTABLE_NAME], which, in our case, is ./translated_version_my_code and then hit ENTER or RETURN on the terminal once again. Now, the computer will start executing the program. Let's see an example.

Linux (Ubuntu)

Open up your terminal and type the following command, and hit RETURN:

gedit

This will open up a new empty text file. Copy-paste the following code into that text file: 

#incude <stdio.h>
int main(){
    int age = 3;
    printf("Alice's age is %d.", age);
    return 0;
}

Save the file as example.c and go back to your previously opened terminal again. Now, type the following and hit RETURN:

gcc -o exec example.c

This command will create a new machine-readable file (the so-called executable) named exec in the same directory. Type the following and hit RETURN:

./exec

You will see the following output on your screen:

Alice's age is 3.

Congratulations! That was it. Now, you can use these steps to compile and run your programs throughout this tutorial series. Hope you'll enjoy the ride.

MacOS

Open up your terminal and type the following command, and hit RETURN:

gedit

This will open up a new empty text file. Copy-paste the following code into that text file: 

#incude <stdio.h>
int main(){
    int age = 3;
    printf("Alice's age is %d.", age);
    return 0;
}

Save the file as example.c and go back to your previously opened terminal again. Now, type the following and hit RETURN:

gcc -o exec example.c

This command will create a new machine-readable file (the so-called executable) named exec in the same directory. Type the following and hit RETURN:

./exec

You will see the following output on your screen:

Alice's age is 3.

Congratulations! That was it. Now, you can use these steps to compile and run your programs throughout this tutorial series. Hope you'll enjoy the ride.

Windows (don't use it!)

Don't use Windows!

Table of Contents

  1. Preface
  2. Level 1. Introduction to C
    1. Hello, World!
    2. Basics $\leftarrow$ you are here
      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
      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