C Syntax & Variables

Types, operators, control flow, functions, and the basics of header files in C.

Basic types

C
int age = 25;             // typically 32-bit signed integer
float price = 19.99f;     // 32-bit floating point
double precise = 3.14159; // 64-bit floating point
char grade = 'A';         // a single byte, usually holding an ASCII character

C's int doesn't have a fixed, guaranteed width — it's only guaranteed to be at least 16 bits, and is 32 bits on essentially every modern desktop/server platform. When the exact size actually matters (file formats, network protocols, embedded registers), use the fixed-width types from <stdint.h> instead:

C
#include <stdint.h>

int32_t userId = 1001;    // exactly 32 bits, on every conforming platform
uint8_t flags = 0;        // exactly 8 bits, unsigned
int64_t fileSize = 4294967296; // exactly 64 bits

sizeof tells you the actual size (in bytes) of a type on the current platform — useful because you should never assume a size without checking:

C
printf("%zu\n", sizeof(int));    // commonly 4
printf("%zu\n", sizeof(double)); // commonly 8

Operators

C
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 toward zero
int rem   = a % b;   // 1   — modulo, only defined for integers

int isEqual  = (a == b); // 0 (false)
int isBigger = (a > b);  // 1 (true)

int x = 5;
x += 3;  // x = 8
x++;     // x = 9 (post-increment)
++x;     // x = 10 (pre-increment)

7 / 2 evaluates to 3, not 3.5 — integer division always truncates. To get a fractional result, at least one operand must be a floating-point type: 7 / 2.0 gives 3.5.

Control flow

C
int n = 7;

if (n % 2 == 0) {
    printf("even\n");
} else if (n < 0) {
    printf("negative\n");
} else {
    printf("odd\n");
}

switch (n) {
    case 1:
        printf("one\n");
        break;
    default:
        printf("something else\n");
        break;
}

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

int i = 0;
while (i < 3) {
    printf("%d ", i);
    i++;
}

int j = 0;
do {
    printf("%d ", j); // runs at least once, even if the condition is false
    j++;
} while (j < 0);

Functions

A function's declaration (a prototype, telling the compiler its name/parameters/return type) can be separate from its definition (the actual body) — this is what lets you call a function before its body appears later in the file, or in a different file entirely.

C
// Declaration (prototype) — often placed in a header file
int add(int a, int b);

int main(void) {
    int result = add(2, 3); // legal — the compiler already knows add's signature
    printf("%d\n", result); // 5
    return 0;
}

// Definition — the actual implementation
int add(int a, int b) {
    return a + b;
}

Unlike C++, plain C has no function overloading — each function name must be unique within its scope, regardless of parameter types.

Header files, briefly

A header file (.h) typically holds function declarations, struct/typedef definitions, and macros shared across multiple .c source files — the actual function bodies live in a corresponding .c file.

math_utils.h:

C
#ifndef MATH_UTILS_H  // "include guard" — prevents this header being processed twice
#define MATH_UTILS_H

int add(int a, int b);
int multiply(int a, int b);

#endif

math_utils.c:

C
#include "math_utils.h"

int add(int a, int b) {
    return a + b;
}

int multiply(int a, int b) {
    return a * b;
}

main.c:

C
#include <stdio.h>
#include "math_utils.h" // quotes for your own headers, angle brackets for system ones

int main(void) {
    printf("%d\n", add(2, 3)); // 5
    return 0;
}
Bash
gcc -std=c17 -Wall -Wextra -o app main.c math_utils.c

The #ifndef/#define/#endif include guard prevents a compile error if the same header is (directly or indirectly) #included more than once in the same translation unit.

Common mistakes

  • Writing if (x = 5) instead of if (x == 5) — this is a legal assignment expression in C, not a comparison, and it's one of the most common real-world C bugs. -Wall warns about it; heed the warning.
  • Forgetting integer division truncates: 9 / 2 is 4, not 4.5.
  • Forgetting the include guard in a header file, causing "redefinition" errors as soon as the header is included from more than one place.
  • Assuming int is a specific bit width across all platforms instead of checking with sizeof or using <stdint.h> types.

Interview questions

Q: What's the difference between a function declaration and a function definition? A declaration (prototype) tells the compiler a function's name, parameter types, and return type so it can be called before the compiler has seen its actual body — typically placed in a header file. A definition is the actual implementation with a function body, and must exist exactly once across the whole program.

Q: Why does if (x = 5) compile in C, and why is it dangerous? = is the assignment operator and x = 5 is a valid expression that evaluates to 5 (which is non-zero, hence "true" in a boolean context) — C doesn't distinguish assignment from comparison at the type level the way some languages do. This means a typo (= instead of ==) silently assigns instead of comparing, and the resulting bug can be very hard to spot; compiling with -Wall surfaces it as a warning.