Phases through which a C program goes to be executed
.c).h).o)
.lib, .dll)
.exe file)#include <file.h>.
Compiler will include the contents of file.h with the
source codemainreturn 0 means the program exited normallyif, int
etc)int anInt;anInt = 5;char : 1 byteint : 4 bytes (machine-dependent)float : 4 bytesdouble : 8 bytesIn order of promotion hierarchy
long doubledoublefloatunsigned long intlong intunsigned intintshortcharCasting is the name given to converting type.
(newType) variableOfOldTypeCasting to a lower type leads to loss of precision.
Can get finer control over the integer size by using
int8_t, int16_t, int32_t,
int64_t, uint8_t, etc.
In order of reverse precedence
+-*/: division. Integer division truncates remainder
7/5 \rightarrow 1%: modulus. Returns the remainder 7%5
\rightarrow 2()For convenience, C also has:
+=, -=,
*=, /=, %=++: Increment--: Decrement++i: Update the variable. Then evaluate the
expressioni++: Execute the expression. Then update the
variable&&: and||: or!: not&: and|: or^: xor~: not<<: left shift>>: right shiftif, if...else, and
switchwhile, do...while,
and forif (...)
10==: equal to!=: not equal to>: Greater than<: Less than>=: Greater than or equal to<=: Less than or equal toif ( condition ){
statement;
}
else if( condition2 ) {
// else if is optional
}
else if( condition3 ) {
// can have multiple else ifs
}
else {
// no condition is specified
// else is optional
}switch ( variableWithDistinctValues ) {
case value1 :
statement1;
break;
case value2 :
statement2;
break;
case value3 :
case value4 :
statement3and4;
break;
default:
statementForTheRest;
break;
}for ( initialization; loopContinuationTest; increment ) {
statement;
}Can have multiple initializations, increments.
e.g. for (i = 0, j = 0; j+i <= 10; j++, i+=5) { ... }
initialization;
while ( loopContinuationTest ) {
statement;
increment;
}Same as while, but ensures that the body of the loop is executed at least once.
do {
statements;
} while ( condition );break : causes immediate exit from a
while, for, do...while or
switch statementcontinue : goes to the next iteration of the loopUnstructured control flow
goto (avoid, unless you really know what you’re doing
and it is the cleanest approach).
...
goto foo;
...
foo:
...They are useful for - breaking out of deeply nested loops - handling errors, exceptions - cleans up opened resources - jumping to some code if allocation fails
Exceptions are used to break out of a deep call stack quickly.
Similar to gotos for breaking out of loops, but here applied to function
calls. setjmp, longjmp
returnType functionName(type1 parameter1, type2 parameter2,...){
declarations;
statements;
return expression;
}returnType is void andreturn; orreturnTo call a function:
variable = functionName(argument1, argument2, ...)If the function returns void, then
functionName(argument1, argument2, ...)func(foo)
func(&foo)
&& (the array name
is already an address/reference (pointer))All C functions are technically pass-by-value. For the “pass-by-reference” concepts defined above, what actually happens is that a copy of the pointer is passed to the function. Incrementing the pointer inside the function, does not change the original pointer.
returnType functionName(type1 param1, type2 param2,...);#include <file> for system header files#include "file" for user header filesThe C preprocessor literally inlines the contents of the included file
// lib.h
int give_me_int();
---
// main.c
#include "lib.h"
int main() {
return give_me_int();
}becomes
// main.c
int give_me_int();
int main() {
return give_me_int();
}Header guards: macro definitions that allow the compiler to only ever execute the header files the first time they are seen. It’s good practice to include them on projects of any significant size.
// stdio.h
#ifndef _STDIO_H_
#define _STDIO_H_
// Lots of header code
#endif /* _STDIO_H_ */The next time stdio.h is included in the project, it
will skip over all the meat of this file since _STIOD_H_
will be defined.
The C standard library (or libc) provides macros, type definitions and functions for common tasks.
See https://en.wikipedia.org/wiki/C_standard_library.
An identifier’s storage class determines:
Types:
static: local variables defined in functions.
{...})#define NAME VALUENAME with
VALUE in the code before compilingDeclaration:
arrayType arrayName[ numberOfElements ];Initialisation:
An initialiser list:
int a[ 5 ] = { 1, 2, 3, 4, 5 };
int b[ 5 ] = { 1 }; // remaining four elements default to value 0
int c[ ] = { 1, 2, 3, 4, 5 }; // size of c will be set to 5Arrays and Functions:
returnType functionName(arrayType arrayArgument[], ...);
// To prevent the function from modifying the array, use const
returnType functionName(const arrayType arrayArgument[], ...);const to avoid any modificationchar myName[] = "Anton";
// this is equivalent to the 6 characters:
char myName[] = {'A','n','t','o','n','\0'};
// and is also mostly equivalent to:
char* myName = "Anton";'\0' terminates stringsmyName[0] is
'A'e.g.
char yourName[10];
scanf("%s", yourName); // Note: no &
// This reads characters until a whitespace is encountered.
// So if you enter "Anton Tang", yourName would just be
// Antone.g. This declares and initialises a 2 \times 2 matrix:
int my2dArray[2][2] = {{1, 2}, {3, 4}};
// my2dArray[1][0] is then 30Definition:
enum EnumName { item1, item2, item3, ...};Example:
// definition
enum Weekday { Mon, Tues, Wed, Thurs, Fri};
enum Weekday today; // declaration
today = Thurs; // assignment
if (today == Fri){
printf("It's the weekend! Nearly...");
}
typedef enum WeekDay weekday_t;
weekday_t blues = Mon;Collections of related variables (aggregates) under one name.
// definition
struct structName{
dataType1 varName1;
dataType2 varName2;
...
}; // NB: need ";" here!
// declaration and initialisation
struct structName structVar = {value1, value2, ...};
// note that above there are two parts to the struct type
// declaring and initialing pointer to a struct
struct *sPtr;
sPtr = &structVar;.): when you have the structure name
++C.x is C.x = C.x + 1->): when you have a pointer to the
structure.structVar.varName1 = value1;
(*sPtr).varName1 = value1;
sPtr->varName1 = value1;typedef// Option 1
struct coord {
double x;
double y;
};
typedef struct coord Point;
Point pa, pb;
// without typedef
struct coord pa, pb; // annoying// Option 2
typedef struct {
double x;
double y;
} Point;
Point pa, pb;We can also define an integer pointer type
typedef int * IntPtrType;
When structures are defined, the compiler is allowed to add padding (spaces without actual data) so that members fall in address boundaries that are easier to access for the CPU.
For example, on a 32-bit CPU, 32-bit members should start at addresses that are multiple of 4 bytes in order to be efficiently accessed (read and written).
struct S {
int16_t member1;
int32_t member2;
};With padding:
+---------+---------+
| m1 |~~~~| m2 |
+---------+---------+
With packing:
+---------+---------+
| m1 | m2 |~~~~
+---------+---------+
For packed, the compiler has to generate more code (which runs slower) to access the non-aligned data members. Packed structs are suited for storing data in binary formats.
Allows for the same memory space to be interpreted as multiple types.
union myunion {
int x;
struct {
char s1;
char s2;
} s;
};
union myunion y;Types of variables
Pointers:
Declaration:
pointerType *pointerName;
pointerType *pointer1, scalar;0, NULL, or an
address& returns address of operand* is used for pointer declaration* also provides access to memory/variable that its
operand points to
*) must be an
address& and * are inversesNULL, include stdio.h first
if (myPointer == NULL) { ... }Arithmetic operations can be performed on pointers
++, --+ or +=,
- or -=)<, ==,
>)Array elements can be accesed by:
*( arraypointer + i)arraypointer[ i ]*( array + i)array[ i ]The above is easy to remember once you realise that
array and arraypointer are just aliases.
float f[5];
float *fptr = &f[0];
fptr++; // moves the address 4 (8) bytes forward on 32 (64)-bit machinesconst dataType variableName = variableValue;
// compiler will complain if you try to change this variableCombinations possible
int *myPtr; // 1
const int *myPtr; // 2
int * const myPtr = &x; // 3
const int * const myPtr = &x; // 4When to use which combination?
int min(int a, int b);
int max(int a, int b);
int foo(bool do_min, int a, int b) {
int (*func)(int,int); // declaration
if (do_min)
func = min;
else
func = max;
// indirect call
return func(a, b);
}sizeof operatorint, myStructType)myInt,
myStructVar)19)sizeof( array ) returns amount of memory
consumed by all array elements.
sizeof cannot
determine the memory size used by the array.sizeof( myStructType ) or
sizeof( myStructVariable)asm("code");
asm("code": output); // asm to C
asm("code": ... : input); // C to C