Last 30 Days
No notifications
A variable is a named box in memory that holds a value of a specific type. In C, you must tell the compiler the type before you use the variable. This is called declaration.
int age = 19; // a 4-byte integer
float price = 9.99f; // a single-precision decimal
char grade = 'A'; // a single character (1 byte)
double pi = 3.14159; // a higher-precision decimal (8 bytes)| Type | Stores | Typical size | Range (signed) | ||||
char | one character (or small int) | 1 byte | -128 to 127 | ||||
int | whole numbers | 4 bytes | ±2.1 billion | ||||
float | decimals (~7 digits) | 4 bytes | ±3.4 × 10³⁸ | ||||
double | decimals (~15 digits) | 8 bytes | ±1.7 × 10³⁰⁸ | ||||
void | "no type" | — | used for functions that return nothing | > Sizes can vary by platform. Use Type ModifiersYou can stretch or shrink the basic types: | Modifier | Effect | Example |
unsigned | only ≥ 0, doubles the positive range | unsigned int u = 4000000000; | |||||
short | smaller integer (often 2 bytes) | short s = 1000; | |||||
long | larger integer (often 8 bytes) | long big = 10000000000L; | |||||
long long | even larger (≥ 8 bytes) | long long n = 9LL; | Format Specifiers in printf / scanf | Type | printf | scanf | |
int | %d | %d | |||||
float | %f | %f | |||||
double | %lf | %lf | |||||
char | %c | %c | |||||
unsigned int | %u | %u | |||||
long | %ld | %ld | |||||
| hex | %x | %x |
> Trap: scanf for double is %lf (not %f). Mixing them up reads garbage.
score ≠ Score ≠ SCOREint, return, if, …)const float PI = 3.14159f; // can never be changed
#define MAX_USERS 100 // preprocessor constantEvery program is just data + the operations that move data around. Variables are how you give that data a name. In C, the type system is the contract between you and the compiler — once you declare a variable's type, that type is fixed for life.
These three words are used interchangeably in casual conversation but they mean different things:
int x; // declaration — "x is an int" (memory reserved, value is GARBAGE)
x = 42; // assignment — "put 42 into x"
int y = 42; // definition + initialisation in one step
extern int z; // declaration only — "z exists somewhere else, trust me"> Critical rule: an uninitialised local variable in C does not start at zero. It contains whatever bits were sitting in that memory slot. Reading it is undefined behaviour. Always initialise.
int x;
printf("%d", x); // ❌ might print 0, might print -873652, might crashSizes are not fixed by the C standard — they depend on the compiler and platform. To know the truth on your machine:
printf("int = %zu bytes\n", sizeof(int));
printf("char = %zu bytes\n", sizeof(char)); // ALWAYS 1 by definition
printf("float = %zu bytes\n", sizeof(float));
printf("double= %zu bytes\n", sizeof(double));%zu is the format specifier for size_t (an unsigned integer type returned by sizeof).
A signed 8-bit number uses one bit for the sign, so it stores -128 to 127. An unsigned 8-bit number uses all 8 bits for value, so it stores 0 to 255.
unsigned char u = 200; // fine
signed char s = 200; // ⚠️ overflows to -56 (depends on platform)Why this matters: if you mix signed and unsigned in the same expression, C silently converts the signed value to unsigned — and a negative number becomes a huge positive one.
unsigned int u = 5;
int s = -3;
if (s < u) printf("yes");
else printf("no"); // ❌ prints "no" — surprising!s (-3) is converted to a giant unsigned number before the comparison. Lesson: don't mix signed and unsigned.
float and double use the IEEE 754 format. They are accurate enough for most things, but not exact:
printf("%.20f\n", 0.1 + 0.2); // 0.30000000000000004440This is not a bug in C — it is fundamental to binary floating-point. Never use == to compare floats. Compare the difference instead:
if (fabs(a - b) < 0.0001) {
// close enough
}(fabs lives in — link with -lm on Linux.)
'A' is not a string — it's the integer 65 with the type char.
char c = 'A';
printf("%c %d\n", c, c); // A 65You can do arithmetic on chars:
char letter = 'a' + 3; // 'd'This is why ASCII tricks work — characters are numbers.
Sometimes you need to convert between types explicitly:
int total = 7;
int count = 2;
double avg = total / count; // ❌ 3.0 — integer division happens FIRST
double avg2 = (double)total / count; // ✅ 3.5The cast (double) happens before the division, so the division becomes float division.
| Cast | Effect |
(int)3.9 | 3 (truncates, doesn't round) |
(double)5 | 5.0 |
(char)65 | 'A' |
const double PI = 3.14159; // typed constant, lives in memory
#define MAX 1000 // preprocessor — pure text replacementconst | #define | |
| Has a type | ✅ | ❌ (just text) |
| Visible in debugger | ✅ | ❌ (gone before compilation) |
| Can be used in array sizes (C99+) | ❌ in old C | ✅ |
| Scope | normal C scoping | global, until #undef |
Rule of thumb: prefer const for values, #define for purely compile-time things and macros.
#include <stdio.h>int main(void) {
int age = 19;
float cgpa = 8.7f;
char grade = 'A';
const double PI = 3.14159;
printf("Age : %d\n", age);
printf("CGPA : %.2f\n", cgpa); // %.2f → 2 decimal places
printf("Grade : %c\n", grade);
printf("Pi : %lf\n", PI);
age = age + 1; // variables CAN change
// PI = 3.14; // ❌ compile error: assignment of read-only variable
return 0;
}
Master this and the rest of C reads like a sentence.