C Tips

Mallocing by reference

int main(int argc, char **argv)
{
    int *buffer;
    alloc_memory(&buffer); // pass by reference
}

// Notice we are applying an additional level of indirection
// We could have simply returned a pointer to the malloc'd
// memory like normally but we can do this via parameters as well
void alloc_memory(int **b)
{
    *b = (int *)malloc(10); // dereferencing gives us the
                            // original pointer
    assert(*b != NULL);
}

Function pointers

Useful for passing functions as parameters to a different function.

// Normal function
int addInt(int n, int m) {
    return n+m;
}

// Define a pointer to a function which receives 2 ints and returns an int.
int (*functionPtr)(int,int);
functionPtr = &addInt;           // Now we can safely point to our function
int sum = (*functionPtr)(2, 3);  // sum == 5

// Passing the pointer to another function is basically the same.
int add2to3( int (*functionPtr)(int, int) )
{
    return (*functionPtr)(2, 3); // function pointer is a parameter to add2to3
}

// this is a function called functionFactory which receives parameter n
// and returns a pointer to another function which receives two ints
// and it returns another int
int (*functionFactory(int n))(int, int)
{
    printf("Got parameter %d", n);
    int (*functionPtr)(int,int) = &addInt;  // func ptr -> &func
    return functionPtr;
}

// But it's much nicer to use a typedef function pointer
// myFuncDef is the name to replace
typedef int (*myFuncDef)(int, int);

// only the parameter and func name is retained
myFuncDef functionFactory(int n)
{
    printf("Got parameter %d", n);
    myFuncDef functionPtr = &addInt; // Alternate is func_ptr = addInt;
    return functionPtr;
}

typedef

// better this way
typedef struct S {} S;

// equivalent
struct S {};
typedef struct S S;

Indexing a 2D array with pointers

    u8 l_matrix[10][20];
    u8 (*matrix_ptr)[20] = l_matrix;

    matrix_ptr[0][1] = ...;

Debugging

void foo ()
{
    // __FILE___ and ___line___ are existing macros
    printf("Debug print: inside %s; at line %d\n", __FILE__, ___line___);
}
#include <string.h>
#include <errno.h>

fprintf(stderr, "ERROR: %s\n", strerror(errno));
perror("My error string") // Just use perror(), much easier
#define assert(expr) \
            if(!(expr)) \
            { \
                printf("Assertion failure: " #expr); \
                printf(" in %s at line: %d\r\n", __FILE__, __LINE__); \
                __sys_term(); \
            }

Types

  • 45U is an unsigned int constant.

  • 45UL is an unsigned long int.

Type
Storage size
Value range

char

1 byte

-128 to 127 or 0 to 255

unsigned char

1 byte

0 to 255

signed char

1 byte

-128 to 127

int

2 or 4 bytes

-32,768 to 32,767 or -2,147,483,648 to 2,147,483,647

unsigned int

2 or 4 bytes

0 to 65,535 or 0 to 4,294,967,295

short

2 bytes

-32,768 to 32,767

unsigned short

2 bytes

0 to 65,535

long

4 bytes

-2,147,483,648 to 2,147,483,647

unsigned long

4 bytes

0 to 4,294,967,295

float

4 bytes

1.2E-38 to 3.4E+38 (6 decimal places)

double

8 bytes

2.3E-308 to 1.7E+308 (15 decimal places)

long double

10 bytes

3.4E-4932 to 1.1E+4932 (19 decimal places)

Last updated