Some notes about C
Basic C program
Pre processor directives
#INCLUDE ...
At the top of a C file, includes other files.
Main function
int main() { statement; ... statement; }
Variables
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;
Assignment
Assign a constant value
myvar = 0;
Assign another variable
myvar = othervar;
Scope
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
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
register int var;
Hints the compiler to store the variable in register memory (which has the fastest access time).
Static
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
Integer
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>);
Character
char
. Holds one character at time and its size in one byte. Use ''
to declare a character.
Float
Can be float
, double
or long double
. They represente floating
point fractional numbers and differ by their precision. Size is
architecture dependent.
Constants
#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).
Operators
Arithmetic
+, -, *, /, %
All associate left to right; +
and -
have lowest precedence.
Increment/Decrement
++, --
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.
Relational
==, !=, <=, >=, <, >
Logical
&&, ||, !
&&
and ||
operators short circuit, meaning the evaluation ends as
soon as a result of the expression is available.
Bitwise
&, |, ~, ^, <<, >>
The first four operators are bitwise and, or, not and xor.
var << n
Shifts
var
byn
bits to the left; rightmost positions are filled with zeros. It is equivalent tovar * pow(2,n)
.var >> n
Shifts
var
byn
bits to the right; leftmost positions are filled with zeros. It is equivalent tovar / pow(2,n)
.
Assignment
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.
Precedence
Determines in which order operators are evaluated.
Associativity
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.
Conditionals
if - else
if (condition) { statement; ... } else { statement; ... }
if
can be nested and the else
block is optional.
if - else if
if (condition) { statement; ... } else if (condition) { statement; ... }
switch
switch (exp) { case val1: statement(s); break; ... case valn: statement(s); break; default: statement(s); }
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.
Loops
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 { statements; } while(expression);
Evaluates statements as the while
loop, but statements are evaluated
at least once.
Control statements
break
Terminates the loop.
continue
Forces the next iteration of the loop.
Functions
Declaration
<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
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.
Recursion
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.
Arrays
Collections of elements of the same type.
Declaration
<data_type> myarray[N];
N
is the number of elements and must be a positive integer
constant. N
chunks of contiguous memory are allocated.
Initialization
myarray[] = {val0, ..., valN-1};
Accessing elements
myarray[i]
I must be between 0
and N - 1
included.
Multidimensional arrays
<data_type> myarray[N1][N2]...[Nn];
Are arrays of arrays.
Initialize
myarray[N1]...[Nn] = {{val00, ..., val0N-1} ... {valN0, ..., valNN-1}};
Access elements
myarray[index0]...[indexN]
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.
Pointers
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
*ptr
The *
(dereference) operator acts on the value of the object
referenced by ptr
. It must not be applied to an uninitialized
pointer!
Assignment
*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];
Addition
p + x
Moves pointer p
x
elements forward from its initial position.
Subtraction
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.
Comparison
Usual relational operators are allowed. Comparison is possibile only if both pointers point to the same array.
Miscellanea
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.
Strings
Literals
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.
Output
printf("%s", string);
puts(string);
Input
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>;
Copy
strncpy(str2, str1, sizeof(str2))
Copies sizeof(str2)
bytes into str1
. Manually add a string
terminator to str2
.
Length
strlen(str)
Returns the length of str
, without counting the the string
terminator.
Concatenation
strncat(str1, str2, n)
Appends up to n
chars from str2
at the end of str1
.
Comparison
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
Declaration
<type> (*ptr)(<paramenters>)
Points to a function with the given prototype.
Assignment
ptr = &<function>;
Usage
res = *ptr(<actual parameters>)
Structures
Basics
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
typedef <existing_type> <new_type> typedef struct { <type1> var1; <type2> var2; ... <typeN> varN; } mytype mytype var;
Defines a new data type.
Initialization
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.
Access
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
.
Unions
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.
Enumerations
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.