A C tutorial.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Leonora Tindall 48249f9fee
Arguments and pointers
1 year ago
.gitignore Initial commit 1 year ago
00-helloworld.c Basic example hello world 1 year ago
01-arguments.c Arguments and pointers 1 year ago
LICENSE Initial commit 1 year ago
README.md Arguments and pointers 1 year ago


C Musings

Some musings on C-family languages, by Nora for Ania!

History of the C Family

In the early days of computing, MIT, General Electric, and Bell Labs created MULITCS, the Multiplexed Information and Computing Service. This operating system introduced many ideas that are commonplace today. It also kind of sucked, and the project fell apart.

From the ashes rose UNIX, an operating system which, like all OSes at the time, was written entirely in non-portable assembly code for a specific machine, the DEC PDP-10. It used an interpreted language called B for some non-performance-critical code that needed to be easy to modify.

As it became popular in the early 1970s, Dennis Ritchie, Brian Kernighan, and others decided to port it to a number of other computers. To ease this task, they invented a computer language that abstracted over the specifics of machine language of any particular computer, but was close enough to the model exposed by most machines that, with a little machine-specific assembly code, the only thing that had to be ported to each new machine was the compiler.

The compiler is a “simple” piece of code that translates the C code to machine-specific instructions. Nowadays, compilers are extremely complex, as they perform optimization as well as simple compilation.

Because C is so low level, it is entirely imperative. All of its high-level features, such as structures and function pointers, come from the way the machine works, not from any magic (runtime) applied by the compiler.


C++ is an invention of Bjarne Stroustroup, a brilliant computer scientist who decided to apply object oriented principles to C. The result was an absolute mess of a language that is nonetheless very powerful and, as time goes on, is becoming more and more safe and easy to use.

It has somewhat more of a runtime then C, and the compiler does a lot more work, including permitting type-system level templating.


C# is Microsoft's answer to Java. It's really similar to Java and has very little to do with C.

The C Programming Language

That's the name of a terrible book that you shouldn't read. I did, it blew my mind and I learned nothing.

Anyway, what defines the C language?

C is statically typed. That means, like Java and unlike Python, a variable has to keep the same type throughout the program:

int a = 24;
a = "Hello, world!"; // Compiler error

C is weakly typed. That means, unlike both Java and Python, C will do it's very best to do something even when you give it types that make little sense, based on the way the PDP-10 would have done it in its CPU.

int a = 25;
char b = 'b';
a + b; // This is an integer of the value 25 plus the integer value of the letter b.

C is procedural. Its primary abstraction is the procedure call, or function call. This is as opposed to object-oriented languages, for example.

Finally, C is memory unsafe. Because it has no runtime and gives you access to the very lowest level of the machine (or at least does a good job of pretending), you can do silly things without anyone stopping you.

char[] c = "Hello, world!"; // A string is an array of characters.
char nonsense = c[134]; // This will cause a problem, probably.

This code won't throw an IndexOutOfBounds exception or anything; there's no runtime to check that. Instead, the compiler will very earnestly try to write code that does this; it will get the address of the start of the array c, compute the memory address 134 bytes later, and try to see what's there. This will certainly be gibberish and might cause the operating system to kill your program.

Setting Up a Development Environment

To develop C, you need a compiler, and it's nice to have a build system. I'll assume you're on Ubuntu; to install GCC, the GNU Compiler Collection, and make, a build system, on Ubuntu, run:

sudo apt install gcc make

Now make a directory to work in and open up a file. I'm going to call it 00-helloworld.c. Into that file, type:

#include <stdio.h>

int main(int argc, char** argv) {
        printf("Hello, world!\n");

(I'll explain it all in a sec!)

Now, in the terminal, in that folder, type:

# GCC, please compile the code in 00-helloworld.c
# and write the executable out to 00-helloworld.64
gcc 00-helloworld.c -o 00-helloworld.64

This should print out “Hello, world!” in your terminal. Let's dissect that.

#include <stdio.h>

Beginning with # means that this is a preprocessor directive, telling the compiler to look up and include a file called stdio.h in the standard search path (because of the < and >, as opposed to " and " which mean look in the current directory) and include its text here.

That file defines, among other things, the function printf that is used later.

int main(int argc, char** argv) {

This is the definition of the magic function main, which is run when the program starts. It returns an int, which should be zero for success or anything else for failure, and takes the number of command line arguments argc and an array of arrays of characters (an array of strings) argv. c stands for “count” and v for “vector” in this case.

printf("Hello, world!\n");

This calls the printf function, which prints a formatted string, although we're not using any of the formatting options here. The \n is a standin for the newline character.

Congratulations! This is your first C program, and demonstrates that your development environment is working.

Pointers and Looping

In a file called 01-arguments.c, write:

#include <stdio.h>

int main(int argc, char** argv) {
    printf("Given %d arguments.\n", argc);

    int index = 0;
    while (index < argc) {
        printf("Argument %d: %s\n", index, argv[index]);
        index = index + 1;

This is pretty similar, but has a few more complications.

printf("Given %d arguments.\n", argc);

Here, %d means “replace this placeholder with the first argument after the string, which should be an integer”. d stands for digit.

int index = 0;

This is the declaration of a variable “index”, which will be used to keep track of our place in the array.

while (index < argc) {

This means run the following code until the index variable becomes greater than or equal to argc, the number of command line arguments.

printf("Argument %d: %s\n", index, argv[index]);

This line has a few new things in it; %s is the placeholder for strings, and argv[index] is taking looking at the indexth element in argv, an array of strings.

Or, you can look at it a different way: argv is a char**, a * (pointer) to a * (pointer) to a char. A “pointer” is simply an unsigned integer which represents, instead of a number, a location in memory.

So, char** argv is the memory location of the first element in a list of pointers, each of which is the memory location of the first element in a list of chars. Those lists of chars all end with \0, the 0 byte, and represent the text of the program's command line arguments.