Some notes about C

Basic C program

Pre processor directives


At the top of a C file, includes other files.

Main function

int main() {


Declaration & Definition

Variables are declared only once, before usage and can be initialized by assigning a value. They must have a type and name:

int var;


  • Assign a constant value

    myvar = 0;

  • Assign another variable

    myvar = othervar;


A variable has a block scope. It is visibile in the block it is declared and in all blocks internal to that block - where it can be redefined and thus masks the one in the outer blocks. It is not available to any block external to its declaration, and it is automatically destroyed at the end of its scope.

A variable defined at file level is global (to that file) and it is initialized to 0 by default.

A variable defined at block level is local (to the block) and overrides any global variable of the same name. It is initialized with a random value.

Automatic variables

auto int var;

auto is the default modifier for variables. Automatic variables are destroyed as soon as their scope ends.


extern int var;

Variables declared as extern are accessibile but defined in a different scope (usually in a different file). No memory is allocated.


register int var;

Hints the compiler to store the variable in register memory (which has the fastest access time).


static int var;

Initialized to zero if not explicitly assigned (can only be initialized with constant values). Are not destroyed at the end of their scope and are not visible outside the file (extern modifier raises an error).

Basic output

printf(<format_string>[, var1, ..., varN]);

format_string can contain placeholders for variable information, which will be replaced by by var1, .., varN variables value.

Fundamental data types


Can be int, short or long. unsigned prepended to type force the variable to strore only unsigned values.

The actual size depends on the architecture: sizeof(<type>);


char. Holds one character at time and its size in one byte. Use '' to declare a character.


Can be float, double or long double. They represente floating point fractional numbers and differ by their precision. Size is architecture dependent.


#define MYCONST val

Pre-processor will replace MYCONST with val (name should be in uppercase). Once defined cannot be modified later.

~const type myconst [ = val ];

Defines a specific type of constant.

Basic input

scanf(<format_string>, &var1 [,&var2, ..., &varN]);

Accepts the same format specifiers as printf(). & is the address-of operator (vars are passed by reference).



+, -, *, /, %

All associate left to right; + and - have lowest precedence.


++, --

Increment/decrement the value of a variable by one. Operate only on lvalues.

  • pre-increment

    ++<var>: var is incremented then used.

  • post-increment

    <var>++: var is used then incremented.


==, !=, <=, >=, <, >


&&, ||, !

&& and || operators short circuit, meaning the evaluation ends as soon as a result of the expression is available.


&, |, ~, ^, <<, >>

The first four operators are bitwise and, or, not and xor.

  • var << n

    Shifts var by n bits to the left; rightmost positions are filled with zeros. It is equivalent to var * pow(2,n).

  • var >> n

    Shifts var by n bits to the right; leftmost positions are filled with zeros. It is equivalent to var / pow(2,n).


var = value

The following shorthand assignment operators are available: +=, -=, *=, /=, %=, <<=, >>=, &=, |=, ^=.

Other operators

Conditional operator

<boolean expression> ? <true expression> : <false expression>

Evaluates the boolean expression and returns the result of the corresponding true or false expression.

Comma operator


Returns the rightmost operand in an expression (other operands are first evaluated then rejected). Has the least precedence of all operators.


Determines in which order operators are evaluated.


Comes into place when operators have the same precedence. It can be left to right or right to left. Operators with the same precedente have the same associativity.


if - else

if (condition) {
} else {

if can be nested and the else block is optional.

if - else if

if (condition) {
} else if (condition) {


switch (exp) {
  case val1:
  case valn:

exp evaluation must result in an integer constant value, and val must be an integer constant or an integer expression (or a macro). Duplicate cases are not allowed. break stops the evaluation of cases and the default case is optional.


while loop

while (expression) {
  statement 1;
  statement n;

Evaluates statements until expression is true.

for loop

for (initialization; condition; increment/decrement) {
  statement 1;
  statement n;

Performs initialization, then evaluates condition and repeat statements until condition is true. increment/decrement is performed after each iteration.

do - while loop

*do {
} while(expression);

Evaluates statements as the while loop, but statements are evaluated at least once.

Control statements


Terminates the loop.


Forces the next iteration of the loop.



<return_type> myfunction (<type_1> <arg_1>, ..., <type_n> <arg_n>);

This is called function prototype; arguments list is optional and statements are not included.


Definition is like the prototype, with arguments listed and statements included.

Calling a function

myfunction (<actual arguments>);

Arguments passed by value

The caller passes a copy of The Arguments to the function; original argument values can't be altered.

Parameters passed by reference

<return_arg> myfunction (<arg_1> *<name_1>, ..., <arg_n> *<name_n>);

The prototype must specify that the arguments are passed by reference by using the dereference operator *:

myfunction (&<arg_1>, ..., &<arg_n>);

Use the address operator & to pass the actual arguments.

The caller passes the memory location of the arguments to the function, which can thus be altered.

Static functions

static function ...

The static keyword restricts the access to the function to the file it is declared into.


A function calls itself directly or indirectly. To avoid infinite loops always specify a base condition to stop the recursion.

Direct recursion

function1 calls itself again.

Indirect recursion

function1 calls function2 which in turns calls function1 again.

Tail recursion

The recursive call is the last statement evaluated.

Non-tail recursion

The recursive call is not the last statement evaluated.


Collections of elements of the same type.


<data_type> myarray[N];

N is the number of elements and must be a positive integer constant. N chunks of contiguous memory are allocated.


myarray[] = {val0, ..., valN-1};

Accessing elements


I must be between 0 and N - 1 included.

Multidimensional arrays

<data_type> myarray[N1][N2]...[Nn];

Are arrays of arrays.


myarray[N1]...[Nn] = {{val00, ..., val0N-1} ... {valN0, ..., valNN-1}};

Access elements


Constant arrays

const <data_type> myarray[N1][N2]...[Nn];

Variable length

<data_type> myarray[n]

The lenght n is set at runtime, and can be provided by the user or can be the result of a calculation. Variable length arrays can't be set as static variables and can't be initialized.


Store the memory address where the first byte of the object it points to is located.

Declaration & Initialization

<type> *mypointer;

type is the type of value mypointer will point to, and must be initialized before use.

Accessing memory


The * (dereference) operator acts on the value of the object referenced by ptr. It must not be applied to an uninitialized pointer!


*q = p

p and q are pointers to the same type of data. After the assignment both p and q point to the same memory location.

*q = *p

The memory segments pointed by p and q now contain the same value.

Returning pointers

return &var;

Never return pointers to local variables.

Pointers and Arrays

p = &a[0];


p + x

Moves pointer p x elements forward from its initial position.


p - x

Moves pointer p x elements backward from its initial position.

p - q

Subtracts q from p; the result is the distance between pointers. p and q must refer to the same array.

Increment and Decrement

p++; ++p

Moves p forward by one element.

p--; --p

Moves p backward by one element.


Usual relational operators are allowed. Comparison is possibile only if both pointers point to the same array.


a[0] == *a;

Array names can be used as pointers to the first element, for example when passing arrays as function argument.

<type> (*p)[N] = &a;

p is a pointer the the whole a N-elements array. **p returns the value of the first element.



char *ptr = "Hello World!";

It is a sequence of characters enclosed in double quotes, stored as an array of characters. It is terminated by \0.

Declaration & Initialization

char s[12];

Declares a string of 11 characters (one extra character is needed for the string terminator).

char s[12] = "Hello World";

Declares and initializes the string. The literal can be shorter than the array length, but must not be equal or longer.

char s[] = "A long string";

If the string is initialized from a literal, and the diminsion is not specified, the compiler will set the correct length of the array.


  • printf("%s", string);
  • puts(string);


scanf("%s", string);

Reads a string from standard input. Treats a whitespace character as the end of the string (%[^\\n]s instead of %s can be used as a workaround). Does not check if the string exceeds the allocated length, but the number of characters to read can be made explicit: %10s.

Strings library

#include <string.h>;


strncpy(str2, str1, sizeof(str2))

Copies sizeof(str2) bytes into str1. Manually add a string terminator to str2.



Returns the length of str, without counting the the string terminator.


strncat(str1, str2, n)

Appends up to n chars from str2 at the end of str1.


strcmp(str1, str2)

Array of strings

char array[][N];

Declares an array of strings of length N. All strings have the same length (so memory space can be wasted).

char *array[]

Declares an array of pointers to character. Strings may have different lengths.

Function pointers


<type> (*ptr)(<paramenters>)

Points to a function with the given prototype.


ptr = &<function>;


res = *ptr(<actual parameters>)



struct {
  <type1> var1;
  <type2> var2;
  <typeN> varN;

It is a user defined data type which groups elements of different types.

User defined types

Structure tag

struct mytype {
  <type1> var1;
  <type2> var2;
  <typeN> varN;

struct mytype var;

Identifies a particular kind of structure.


typedef <existing_type> <new_type>

typedef struct {
  <type1> var1;
  <type2> var2;
  <typeN> varN;
} mytype

mytype var;

Defines a new data type.


struct mytype x = {val1, ..., valN};
struct mytype x = {.val1 = ..., .valN = ...};

The first kind of initialization requires that the values of the struct are initialized in order, while the second one allows order free initialization.


val = x.varN;

Values can accessed with the . operator.

Array of structure

struct mytype arr[N];

Pointer to structure

struct mytype *ptr;

Values can be accessed using the shorthand ptr->x.


union mytype {
  <type1> var1;
  <type2> var2;
  <typeN> varN;

Are a special type of structure where all members share the same memory location. The size of the union is the size of its largest member, and only one member can have a meaningful value at any given time.


enum Bool {False, True};
enum Point {x = 10, y = 5};

It is a user defined type which assigns name to integral constants. Two or more names can have the same value. All unassigned names will be assigned the value of the preceding name plus 1.

Only integral values are allowed and constants must be unique within their scope.

© Alessandro Dotti Contra :: VAT # IT03617481209 :: This site uses no cookies, read our privacy policy for more information.