Variables, Data Types and I/O · Lesson 4 of 35
Variables and Data Types in C
A variable is a named piece of memory that holds a value. In C, every variable has a type fixed when you declare it: the type decides how many bytes it uses, what values it can hold and which operations make sense. Choosing types carefully avoids some of C's nastiest bugs – overflow and lost precision.
In this lesson
- Declaring and initialising variables
- The basic types and their sizes
- signed vs unsigned, and integer overflow
- Naming rules and good habits
Declaring variables
#include <stdio.h>
int main(void) {
int age = 20; // declare and initialise
float height = 5.6f; // f suffix: a float literal
double pi = 3.141592653589;
char grade = 'A'; // single quotes: one character
int a, b = 5, c; // several at once (a and c are uninitialised!)
a = 10;
c = a + b;
printf("age=%d height=%.1f pi=%.6f grade=%c\n", age, height, pi, grade);
printf("a=%d b=%d c=%d\n", a, b, c);
return 0;
}
age=20 height=5.6 pi=3.141593 grade=A a=10 b=5 c=15
Always initialise local variables
A local variable that isn't given a value contains whatever bytes were in that memory before – "garbage". Using it is undefined behaviour: the program may print random numbers or behave differently each run. Initialise every variable when you declare it.
Basic types and sizes
#include <stdio.h>
int main(void) {
printf("char : %zu byte\n", sizeof(char));
printf("short : %zu bytes\n", sizeof(short));
printf("int : %zu bytes\n", sizeof(int));
printf("long : %zu bytes\n", sizeof(long));
printf("long long : %zu bytes\n", sizeof(long long));
printf("float : %zu bytes\n", sizeof(float));
printf("double : %zu bytes\n", sizeof(double));
return 0;
}
char : 1 byte short : 2 bytes int : 4 bytes long : 8 bytes long long : 8 bytes float : 4 bytes double : 8 bytes
sizeof gives a size in bytes, printed with %zu. These are the sizes on 64-bit Linux and macOS. The C standard only guarantees minimums – on 64-bit Windows long is 4 bytes, and old 16-bit compilers like Turbo C have a 2-byte int. When you need an exact size, use int32_t, int64_t and friends from <stdint.h>.
| Type | Typical size | Typical range / precision | printf |
|---|---|---|---|
char | 1 byte | −128 to 127 (or 0–255) | %c / %d |
int | 4 bytes | −2,147,483,648 to 2,147,483,647 | %d |
unsigned int | 4 bytes | 0 to 4,294,967,295 | %u |
long long | 8 bytes | about ±9.2 × 10¹⁸ | %lld |
float | 4 bytes | about 6–7 significant digits | %f |
double | 8 bytes | about 15–16 significant digits | %f (printf), %lf (scanf) |
float vs double
#include <stdio.h>
int main(void) {
float f = 0.1f + 0.2f;
double d = 0.1 + 0.2;
printf("float : %.10f\n", f);
printf("double: %.17f\n", d);
printf("%s\n", d == 0.3 ? "equal" : "not equal");
return 0;
}
float : 0.3000000119 double: 0.30000000000000004 not equal
Decimal fractions like 0.1 can't be stored exactly in binary. Prefer double over float for accuracy, and never compare floating-point values with == – check whether the difference is tiny: fabs(a - b) < 1e-9.
signed, unsigned and overflow
#include <stdio.h>
#include <limits.h>
int main(void) {
printf("INT_MAX = %d\n", INT_MAX);
printf("INT_MIN = %d\n", INT_MIN);
printf("UINT_MAX = %u\n", UINT_MAX);
unsigned int u = 0;
u = u - 1; // unsigned arithmetic wraps around
printf("0u - 1 = %u\n", u);
long long population = 1400000000LL * 6; // too big for int: use long long
printf("big = %lld\n", population);
return 0;
}
INT_MAX = 2147483647 INT_MIN = -2147483648 UINT_MAX = 4294967295 0u - 1 = 4294967295 big = 8400000000
Interview angle: overflow
Unsigned integers wrap around predictably (modulo 2ⁿ). Signed overflow – e.g. INT_MAX + 1 – is undefined behaviour: the compiler may assume it never happens and the result can't be relied on. Use a wider type (long long) when values can grow large, such as factorials, sums of big arrays or money in paise.
Naming rules
- Letters, digits and underscores only; must not start with a digit; case-sensitive (
total≠Total). - Can't be a keyword (
int,return,while…). - Use meaningful names:
total_marks, nottm. C programmers usually writesnake_case. - Names starting with an underscore and a capital letter (
_Value) are reserved for the compiler – avoid them.
Practice
Try it yourself
Store a student's roll number, percentage and section letter, and print them on one line.
Show solution
#include <stdio.h> int main(void) { int roll = 42; double percentage = 87.25; char section = 'B'; printf("Roll %d | %.2f%% | Section %c\n", roll, percentage, section); return 0; }Roll 42 | 87.25% | Section B
Quick check
What is the value of an uninitialised local int?
Indeterminate ("garbage"); reading it is undefined behaviour.
Which format specifier prints a size_t from sizeof?
%zu.
Is signed integer overflow well defined in C?
No – it's undefined behaviour. Unsigned overflow wraps around.
Summary
- Every variable has a type that fixes its size and range; always initialise locals.
- Use int for counts, long long for big numbers, double for decimals, char for characters.
- Floating point is approximate; signed overflow is undefined – choose wide enough types.
Finished this lesson?
Mark it complete to track your progress, then carry on with the next lesson.