Variables

C language uses static typing, which means that you should specify type of variable on its declaration

This may look familiar to you

int a; // Create integer 'a'

You can assign value immediately

int k = 10;

Integer data types

Types arranged from the smallest to the biggest

  • char
  • short
  • int
  • long
  • long long

Unsigned and signed

You can attach prefix unsigned to denote that you want to use non-negative integers

unsigned long t = 0;

Prefix signed used to have guarantees, that variable can contain negative values as well

signed char p = 7;

Int

Note that unsigned or signed without type name means unsigned int and signed int respectively

unsigned amount = 150;
signed height = -1;
signed weight = 1300;

Floating point data types

Floating point literals can have suffix to avoid ambiguities in functions calls

name size (bits/bytes) suffix
float 32/4 f
double 64/8
long double 80/10 L

If no suffix specified for literal, double type used.

float width = 1.15;
float price = 1.0f;
long double frequency = 1.0L;
double temp = 0.0;

Functions

Here is the simplest function, which does nothing

void f() {
}

Every function should have strictly specified type of returned value

Sometimes it's needed to use function, which doesn't return any values — in this case you can use void type.

void f() {
    return; // This is correct too
}

Function return type

It's time to write something better than stub

int get_five() {
    return 5;
}

Almost like in Python

def get_five():

    return 5

Function parameters

Function parameters should have type too

int add(float a, long b) {
    return a + b;
}

A bit harder than in Python, but still good

def add(a, b):
    return a + b

Calling functions

Just like in Python, but don't forget about semicolons

add(2, 2);
int result = add(add(1.0f, 0) * 2f, 5);
float k = add(0.0, result);

See results of your code

C applications should be compiled to be executed

You cannot run it in interpreter

Print

Function printf in C behaves like print in Python

printf("Hello world!\n");

This function allows you to use formatted string

printf("Give me %d cup(s) of tea, mr. %s",
        3, "John");

Entry point

C application should have a function called main, which will be executed on application start

int main() {
    return 0;
}

Hello world

We need to include header file of library with printf function and here we are

#include <stdio.h>

int main() {
    printf("Hello world!\n");
    return 0;
}

Execute

In Linux you should have gcc installed in order to compile your code

gcc file.c -o app

and execute

./app

Conditions

Conditions in C are very similar to those in Python

if (true) {
    printf("That's true\n");
} else if (false) {
    printf("This shouldn't be done\n");
} else {
    printf("Are you kidding me?");
}

Switch-case

If you have checks like

int a = 5;
if (a == 0) printf("Zero\n");
else if (a == 5) printf("Five\n");
else printf("Another variant\n");

In C language you can do this

int a = 5;
switch(a) {
    case 0:
        printf("Zero\n");
        break;
    case 5:
        printf("Five\n");
        break;
    default:
        printf("Another variant\n");
}

Seems not so pretty, but it's better to use switch-case instead of if, when you want to check, for example, which key was pressed in your videogame

switch(key) {
    UP:
        move_hero_up(hero);
        break;
    DOWN:
        move_hero_down(hero);
        break;
    default:
        hero_stay(hero);
}

Loops

C language has following loop types

  • for
  • while
  • do-while

Increment and decrement

There's a shorthand for numbers increment or decrement by 1 in C language

i++; // Increment i
a--; // Decrement a
++b; // Increment b
--c; // Decrement c

Post and pre

Post increment like i++ means, that addition will be performed after other operations in current expression

int i = 5;
printf("%d\n", i++); // Will print 5
printf("%d\n", i); // Will print 6

Pre increment written ad ++i will increment before expression evaluation

int i = 5;
printf("%d\n", ++i); // Will print 6
printf("%d\n", i); // Will print 6

While

Just like in Python, but in C we have handy increment

int i = 0;
while (i < 10) {
    printf("%d\n", i);
    i++;
}

Python code

i = 0
while i < 10:
    print(i)
    i += 1

do-while

Like while, but condition check occurs not in the start, but in the end of loop

int i = 0;
do {
    printf("%d\n", i);
} while (++i < 10);

In Python

i = 0
while True:
    print(i)
    i += 1
    if i > 10: break

Goes to operator (not a goto, IYKWIM)

We can not only increment number by ++, but decrement with -- as well and this means, that following is correct

int i = 10;
while (i --> 0) {
    next_step();
}

What happens:

  • we have i equal to 10
  • on each loop iteration we compare it to 0 and decrement

For loop

This loop in C is not like for in Python

for (int a = 0; a < 10; a++)
    printf("Number %d\n", a);

This means

{
    int a = 0;
    while (a < 10){
        printf("Number %d\n", a);
        a++;
    }
}

Arrays

Arrays in C are not similar to lists in Python, because they should have fixed size and type of each element

Static arrays

Such arrays can have constant size, which cannot be defined during runtime

This is useful for strings, which is an array of char

char hello_world[] = "Hello world";

Also you can write

char hello_world[] = {'H', 'e', 'l', 'l', 'o', ' ',
                      'w', 'o', 'r', 'l', 'd', 0};

Also you may want to create an array of numbers

float steps[3] = {1.0, 2.0, 5.5};

You can fill not all values at one time and take care of them later

int numbers[5] = {0, -14, 17};
numbers[4] = 16;
numbers[3] = 5;

Loop through array

You can give size of static array by sizeof operator

It will give you size of all array in bytes and you will need to divide it by size of its elements

int n[] = {1, 2, 3};
for (int i = 0; i < sizeof(n)/sizeof(n[0]); i++)
    printf("%d\n", n[i]);

Pointer

Pointer is just a type of variable, which contains address of byte in memory

Address of variable

Every variable has an address and you can get it by & sign like &var_name

int a = 0;
printf("Address of a is %X\n", &a);

Creating pointer

You can store this address in separate variable

Pointer to variable of some type should have a type of that variable with * sign

float a = 1;
float* b = &a; // Now b contains address of a

Working with memory pointed by pointer

You can access the value pointer points to with * sign

double a = 0.5;
double* b = &a;
printf("%f = %f\n", a, *b); // 0.500000 = 0.500000
*b = 0.8; // Value of a will be changed
printf("%f = %f\n", a, *b); // 0.800000 = 0.800000

Passing pointer as function parameter

Such usage of pointers, as it was shown, is useless

Though, if you want to change value of the variable, pointer is your best friend

void change_me(int* a, int b) {

    *a += b;
}

Following example will change value of variable

int a = 5;

change_me(&a, 3);

printf("%d\n", a); // will print 8

Dynamic arrays

Now we are ready to see dynamic arrays

Size of dynamic array can be set during runtime, because it's just a pointer to allocated part of memory

Allocate memory

Function malloc (memory allocation) allocates memory for array and returns pointer to its start

It accepts needed memory size in bytes, so we need to multiply number of elements in array by size of its type

int* a = malloc(sizeof(int) * 10);

Use array

Usage of dynamic array is the same as of static

a[0] = 15;
printf("%d\n", a[0]);

The main difference is: you should free the memory after allocation to avoid memory leaks

free(a);