Back to blog
Backend Systemsbeginner

C Basics: Types, Variables & Control Flow

Learn C from scratch: data types, variables, operators, conditionals, loops, and the compilation model. The foundation of systems programming.

Asma HafeezApril 17, 20266 min read
cbasicstypescontrol-flowsystems
Share:𝕏

C Basics: Types, Variables & Control Flow

C is the language everything is built on. It gives you direct control over memory and hardware, making it the foundation of operating systems, embedded systems, and performance-critical software.


Hello World & Compilation

C
#include <stdio.h>  // standard I/O library

int main(void) {
    printf("Hello, World!\n");
    return 0;  // 0 = success
}
Bash
gcc hello.c -o hello  # compile
./hello               # run

Data Types

C
// Integer types
char    c  = 'A';       // 1 byte, -128 to 127
short   s  = 32000;     // 2 bytes
int     i  = 2000000;   // 4 bytes (most common)
long    l  = 2000000L;  // 4 or 8 bytes depending on platform
long long ll = 9000000000LL;  // 8 bytes

// Unsigned (no negative values, double the positive range)
unsigned int  ui = 4000000000U;
unsigned char uc = 255;

// Floating-point
float  f = 3.14f;     // 4 bytes, ~7 decimal digits
double d = 3.14159;   // 8 bytes, ~15 decimal digits

// Boolean (C99+)
#include <stdbool.h>
bool flag = true;    // or use int: 0 = false, non-zero = true

// Void — no type (used for functions that return nothing)
void doSomething(void) { }

sizeof operator

C
#include <stdio.h>

int main(void) {
    printf("char:      %zu bytes\n", sizeof(char));    // 1
    printf("int:       %zu bytes\n", sizeof(int));     // 4
    printf("long:      %zu bytes\n", sizeof(long));    // 8 (on 64-bit)
    printf("double:    %zu bytes\n", sizeof(double));  // 8
    printf("pointer:   %zu bytes\n", sizeof(void*));   // 8 (on 64-bit)
    return 0;
}

Variables and Constants

C
// Variable declaration and initialization
int age = 25;
double pi = 3.14159265;
char grade = 'A';

// Multiple declarations
int x = 1, y = 2, z = 3;

// Constants — cannot be changed after initialization
const int MAX_SIZE = 100;
const double GRAVITY = 9.81;

// Preprocessor macro — textual substitution (no type)
#define BUFFER_SIZE 1024
#define PI 3.14159265358979

Operators

C
// Arithmetic
int a = 10, b = 3;
int sum    = a + b;    // 13
int diff   = a - b;    // 7
int prod   = a * b;    // 30
int quot   = a / b;    // 3 (integer division, truncates)
int rem    = a % b;    // 1 (modulo)
double div = (double)a / b;  // 3.333... (cast to float first)

// Increment / decrement
int x = 5;
x++;    // x = 6
x--;    // x = 5
int y = ++x;  // pre: y = 6, x = 6
int z = x++;  // post: z = 6, x = 7

// Compound assignment
x += 3;   // x = x + 3
x *= 2;   // x = x * 2

// Comparison (returns 1 or 0 in C)
int eq = (a == b);   // 0
int ne = (a != b);   // 1
int gt = (a > b);    // 1

// Logical
int and = (a > 0 && b > 0);  // 1
int or  = (a > 5 || b > 5);  // 1
int not = !(a == b);          // 1

// Bitwise
int bits = 0b1010 & 0b1100;  // AND: 0b1000 = 8
int bor  = 0b1010 | 0b1100;  // OR:  0b1110 = 14
int bxor = 0b1010 ^ 0b1100;  // XOR: 0b0110 = 6
int bnot = ~5;                // NOT: -6
int lsh  = 1 << 3;            // left shift: 8
int rsh  = 16 >> 2;           // right shift: 4

Input / Output

C
#include <stdio.h>

int main(void) {
    int age;
    char name[50];

    // Input
    printf("Enter your name: ");
    scanf("%49s", name);       // %s reads until whitespace

    printf("Enter your age: ");
    scanf("%d", &age);         // & gets the address of age

    // Output format specifiers
    printf("Name: %s\n", name);
    printf("Age:  %d\n", age);
    printf("Pi:   %.4f\n", 3.14159265);  // 3.1416
    printf("Hex:  %x\n", 255);           // ff
    return 0;
}

Conditionals

C
int score = 85;

if (score >= 90) {
    printf("A\n");
} else if (score >= 80) {
    printf("B\n");
} else if (score >= 70) {
    printf("C\n");
} else {
    printf("F\n");
}

// Ternary
const char* status = (score >= 50) ? "pass" : "fail";

// switch
int day = 3;
switch (day) {
    case 1: printf("Monday\n");    break;
    case 2: printf("Tuesday\n");   break;
    case 3: printf("Wednesday\n"); break;
    default: printf("Other\n");    break;
}

Loops

C
// for
for (int i = 0; i < 5; i++) {
    printf("%d ", i);  // 0 1 2 3 4
}

// while
int count = 0;
while (count < 3) {
    printf("%d ", count++);  // 0 1 2
}

// do-while (runs at least once)
int n = 0;
do {
    printf("%d ", n++);
} while (n < 3);  // 0 1 2

// break and continue
for (int i = 0; i < 10; i++) {
    if (i == 3) continue;  // skip 3
    if (i == 7) break;     // stop at 7
    printf("%d ", i);      // 0 1 2 4 5 6
}

Arrays

C
// Fixed-size arrays (stack allocated)
int primes[5] = {2, 3, 5, 7, 11};
char greeting[] = "Hello";  // {H, e, l, l, o, \0}

// Access
printf("%d\n", primes[2]);  // 5

// Iterate
int len = sizeof(primes) / sizeof(primes[0]);  // 5
for (int i = 0; i < len; i++) {
    printf("%d ", primes[i]);
}

// 2D array
int matrix[3][3] = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};
printf("%d\n", matrix[1][2]);  // 6

Strings

In C, strings are null-terminated arrays of char.

C
#include <string.h>

char name[] = "Alice";
char buffer[50];

// String functions
int len = strlen(name);               // 5 (not counting \0)
strcpy(buffer, name);                 // copy name into buffer
strcat(buffer, " Smith");             // append " Smith"
int cmp = strcmp("apple", "banana");  // negative (a < b)
char* found = strstr(buffer, "Smith"); // pointer to "Smith" in buffer

// Safe versions (limit bytes written)
strncpy(buffer, name, sizeof(buffer) - 1);
buffer[sizeof(buffer) - 1] = '\0';  // ensure null terminator

// sprintf for formatted strings
char msg[100];
sprintf(msg, "Name: %s, Age: %d", name, 30);

Type Casting

C
int a = 7, b = 2;

// Integer division — truncates
double wrong = a / b;           // 3.0 — division happened before cast

// Correct: cast first
double right = (double)a / b;   // 3.5

// Explicit narrowing
double pi = 3.14159;
int truncated = (int)pi;        // 3

// char ↔ int
char ch = 'A';
int ascii = (int)ch;            // 65
char back = (char)(ascii + 1);  // 'B'

Key Takeaways

  1. C has no automatic memory management — what you allocate, you free
  2. Arrays decay to pointers when passed to functions — sizeof won't work inside a function
  3. Integer division truncates — cast to double first: (double)a / b
  4. Strings are char arrays ending with \0 — always leave room for the null terminator
  5. Use const for values that shouldn't change — the compiler will catch accidental modifications

Enjoyed this article?

Explore the Backend Systems learning path for more.

Found this helpful?

Share:𝕏

Leave a comment

Have a question, correction, or just found this helpful? Leave a note below.