Quick Contact

✉
fahimkhan20148@gmail.com
📱
+971 507 286 133
Back to Notes
August 28, 2026
ctypesadvanced-cmoc

Advanced Datatypes

'#define' Constants

A preprocessor directive is a directive, rather than a keyword; it tells the preprocessor to perform a search-and-replace.

A preprocessor directive begins with # followed by spaces or tabs, then the directive name, the term, and the value; it ends as soon as it encounters the first newline.

Any \ followed by a newline, i.e. \n, is removed. These make directives logically only one line long.

#define PI 3.142
#define ARRY {1, \
2, \
3 \
}

Any \ followed by a newline, i.e. \n, are removed. These make #define only one line long.

typedef

A type alias is used to declare an alias for an existing type. For all computational purposes both are the same type; a type alias is largely just for syntax.

The original type is still valid; it's just another name for the type.

typedef is a keyword used to declare a type alias for an existing type. For all computational purposes both are the same type; typedef is largely just for syntax.

#include <stdio.h>

typedef int USD;

int main(void) {
    USD cur = 50;
    int num = 10;

    int total = cur + num; // Perfectly valid
    printf("Total: %d\n", total); // Outputs: Total: 60

    return 0;
}

USD is still valid; it's just another name for the type.

Typedef with Structs

typedef struct {} Point;

Point point = {};

struct Point2 {};
struct Point2 point2 = {};

With struct, the above pattern of naming an anonymous struct to Point using typedef is so we don't have to type struct Point the type and name each time we want to use point, unlike struct Point2.

Recursive Structs

typedef struct Node {
    int val;
    struct Node* left;
    struct Node* right;
} Node;

Node node = {};

We can use a typedef for a named struct when defining a recursive struct.

Variable Length Array

An array whose length is defined using a variable. The variable does not have to be known at compile time.

Not to be confused with an array of varying length, like a list, array list, or vector.

These features were introduced in C99, which lets you define an array's length using a variable.

#include <stdio.h>

int main(void) {
    int i;
    printf("enter the length of the array: ");
    scanf("%d", &i);

    int array[i];

    return 0;
}

The variable doesn't have to be known at compile time.

The feature is optional in C11, i.e. the compiler doesn't have to implement it. To check if your compiler supports it, you can check the __STDC_NO_VLA__ constant:

#ifdef __STDC_NO_VLA__
    printf("Variable length array not supported\n");
#else
    printf("Variable length array supported\n");
#endif

VLA in Function Arguments

We can use VLA in function arguments:

// C99
void print_matrix(int x, int y, int matrix[x][y]);

// C11
void print_matrix(int, int, int matrix[*][*]);

C11 lets you declare a function with only the type of parameters. Also, an array can't be the first parameter; in C99, it will be a compiler error because x and y would be undefined.

Flexible Array Members

A flexible array member is an unsized array declared as the last member of a struct to support contiguous variable-length payload allocation.

  • sizeof returns the size of the struct excluding the Flexible Array Member. Hence the need to add size * sizeof(type) in dynamic allocation.
  • The Flexible Array has to be the last member of the struct.
  • The Flexible Array can't be the only member of the struct.
#include <stdlib.h>

struct S {
    int size;
    int array[];
};

int main(void) {
    int size = 5;
    struct S* s;
    s = malloc(sizeof(struct S) + size * sizeof(int));

    return 0;
}

sizeof returns the size of struct S excluding the Flexible Array Member. Hence the need to add size * sizeof(int) in malloc. The Flexible Array has to be the last member of the struct. The Flexible Array can't be the only member of the struct.

Complex Numbers

Complex numbers represent mathematical quantities with real and imaginary components, along with arithmetic and manipulation functions.

#include <complex.h>

float complex point = 1.0 + 2.0*I;
double complex point2 = 1.0 + 3.0*I;

Also, there are a few functions in the <complex.h> headers; the rest just let us work with complex numbers.

Again, complex is an optional feature of C11, so check __STDC_NO_COMPLEX__.