C Variables — Data Types, Declarations, and Memory Size Explained
In this tutorial, you will learn about C Variables. We cover key concepts, practical examples, and best practices to help you master this topic.
C variables are named memory locations that store data of specific types. Understanding how different types use memory is fundamental to writing efficient C programs.
Why It Matters
Unlike higher-level languages, C requires you to declare the type of every variable before using it. This type system determines how much memory is allocated, how values are stored, and what operations are allowed. Choosing the right type affects program correctness, memory usage, and performance. In systems programming where every byte counts, understanding exact type sizes and ranges is critical.
Real-World Use
Embedded Systems with 2 KB of RAM need to store sensor readings in the smallest possible type. A temperature reading that fits in a char (1 byte) should never use an int (4 bytes). Network protocols specify exact field sizes in bits -- C's fixed-width integer types map directly to protocol specifications. Durga Antivirus Pro uses unsigned char arrays for buffer scanning and fixed-width int32 types for file offsets.
What You Will Learn
- Declaring and initializing variables in C
- Integer types: int, short, long, signed, unsigned
- Floating-point types: float and double
- The char type and its dual role as character and small integer
- Using sizeof to determine type sizes
- Type ranges and what happens when values overflow
Learning Path
flowchart LR A[Hello World] --> B[Variables
You are here] B --> C[Constants] C --> D[Operators] D --> E[Control Flow] style B fill:#f90,color:#fff
Variable Declaration and Initialization
In C, you must declare a variable before using it. Declaration tells the compiler the variable's name and type. Initialization assigns it a starting value.
#include <stdio.h>
int main() {
// Declaration
int age;
// Initialization
age = 25;
// Declaration + initialization in one statement
int count = 100;
double price = 19.99;
char grade = 'A';
printf("Age: %d, Count: %d, Price: %.2f, Grade: %c\n",
age, count, price, grade);
// Age: 25, Count: 100, Price: 19.99, Grade: A
return 0;
}
Expected output: Age: 25, Count: 100, Price: 19.99, Grade: A
Integer Types
C provides several integer types with different sizes and ranges:
#include <stdio.h>
#include <limits.h>
int main() {
char c = 'A'; // 1 byte, typically -128 to 127
unsigned char uc = 255; // 1 byte, 0 to 255
short s = 32000; // 2 bytes, typically -32,768 to 32,767
unsigned short us = 65000; // 2 bytes, 0 to 65,535
int i = 1000000; // 4 bytes, typically -2B to 2B
unsigned int ui = 4000000000U; // 4 bytes, 0 to 4.2B
long l = 1000000000L; // 4 or 8 bytes depending on platform
long long ll = 1000000000000LL; // 8 bytes, very large
printf("char: %zu bytes\n", sizeof(char));
printf("int: %zu bytes\n", sizeof(int));
printf("long: %zu bytes\n", sizeof(long));
printf("long long: %zu bytes\n", sizeof(long long));
printf("INT_MAX: %d\n", INT_MAX);
printf("INT_MIN: %d\n", INT_MIN);
return 0;
}
Expected output (64-bit system):
char: 1 bytes
int: 4 bytes
long: 8 bytes
long long: 8 bytes
INT_MAX: 2147483647
INT_MIN: -2147483648
Type Sizes Are Platform-Dependent
The C standard does not specify exact sizes for most types. It only guarantees:
charis at least 8 bitsshortis at least 16 bitsintis at least 16 bits (usually 32 on modern systems)longis at least 32 bits (64 on Unix, 32 on Windows)long longis at least 64 bits
Always use sizeof to check sizes on your platform.
The char Type
In C, char is both a character type and the smallest integer type. Characters are stored as their ASCII numeric values:
#include <stdio.h>
int main() {
char letter = 'A';
printf("Character: %c\n", letter); // A
printf("ASCII value: %d\n", letter); // 65
// char as a small integer
char small = -10;
unsigned char positive = 200;
printf("Small integer: %d\n", small); // -10
printf("Unsigned char: %u\n", positive); // 200
// Beware: char can be signed or unsigned depending on platform
signed char sc = -128; // always signed
unsigned char usc = 255; // always unsigned
return 0;
}
Expected output:
Character: A
ASCII value: 65
Small integer: -10
Unsigned char: 200
The fact that char is a tiny integer is important for memory-efficient data storage. An array of 1000 characters uses only 1 KB of memory.
Floating-Point Types
Floating-point types represent real numbers with fractional parts:
#include <stdio.h>
#include <float.h>
int main() {
float f = 3.14159f; // 4 bytes, ~7 decimal digits
double d = 3.141592653589793; // 8 bytes, ~15 decimal digits
long double ld = 3.141592653589793238L; // 10/16 bytes, more precision
printf("float: %zu bytes, value: %.7f\n", sizeof(float), f);
printf("double: %zu bytes, value: %.15f\n", sizeof(double), d);
printf("long double: %zu bytes\n", sizeof(long double));
printf("FLT_MAX: %e\n", FLT_MAX);
printf("DBL_MAX: %e\n", DBL_MAX);
return 0;
}
Expected output:
float: 4 bytes, value: 3.1415901
double: 8 bytes, value: 3.141592653589793
long double: 16 bytes
FLT_MAX: 3.402823e+38
DBL_MAX: 1.797693e+308
Use float when memory is constrained and you do not need high precision. Use double for general-purpose scientific computing. The f suffix on 3.14159f makes it a float literal; without the suffix, it is a double.
Variable Naming Rules
Variables in C follow naming rules:
- Must start with a letter or underscore
- Can contain letters, digits, and underscores
- Case-sensitive:
ageandAgeare different variables - Cannot use C keywords like
int,return,if - Avoid leading underscores (reserved for system use)
The sizeof Operator
sizeof is a compile-time operator that returns the size of a type or variable in bytes:
#include <stdio.h>
int main() {
int arr[10];
struct Point { int x; int y; };
printf("sizeof(int): %zu\n", sizeof(int));
printf("sizeof(arr): %zu\n", sizeof(arr));
printf("sizeof(struct Point): %zu\n", sizeof(struct Point));
printf("Number of elements: %zu\n", sizeof(arr) / sizeof(arr[0]));
return 0;
}
Expected output:
sizeof(int): 4
sizeof(arr): 40
sizeof(struct Point): 8
Number of elements: 10
The formula sizeof(arr) / sizeof(arr[0]) is the standard way to get the element count of an array.
Type Overflow
When a value exceeds the maximum for its type, it wraps around (unsigned) or produces undefined behavior (signed):
#include <stdio.h>
#include <limits.h>
int main() {
unsigned int u = UINT_MAX;
printf("Max unsigned: %u\n", u);
printf("Plus one: %u\n", u + 1); // Wraps to 0
signed int s = INT_MAX;
printf("Max signed: %d\n", s);
printf("Plus one: %d\n", s + 1); // Undefined behavior!
return 0;
}
Unsigned overflow wraps around predictably (modulo arithmetic). Signed overflow is undefined behavior -- the compiler may optimize it in unexpected ways.
Common Mistakes
1. Using Uninitialized Variables
int x;
printf("%d", x); // Uses garbage value
Always initialize variables before reading them.
2. Integer Overflow
int x = 2000000000;
int y = x * 2; // Overflow, undefined behavior for signed
Use larger types or check bounds.
3. Assuming Fixed Type Sizes
long x = 1000000000000; // OK on 64-bit, overflow on 32-bit
Use int32_t, int64_t from <stdint.h> for fixed sizes.
4. Confusing char Signedness
char c = 200; // If char is signed, this overflows
Use unsigned char or signed char explicitly when the signedness matters.
5. Forgetting the f Suffix on Float Literals
float f = 3.14; // 3.14 is a double, converted to float
float f2 = 3.14f; // Explicit float literal
The f suffix prevents unnecessary double-to-float conversion warnings.
Practice Questions
What does
sizeof(int)return on your system? Runprintf("%zu", sizeof(int))to find out. Typically 4 bytes on modern systems.What is the difference between
charandunsigned char?charmay be signed or unsigned depending on the platform.unsigned charalways holds values 0 to 255.What happens when an unsigned integer overflows? It wraps around modulo (max + 1). For example, UINT_MAX + 1 equals 0.
Why might you choose
floatoverdouble? To save memory when high precision is not needed. A float uses 4 bytes versus double's 8 bytes.Challenge: Write a program that prints the size and range of every integer type in
<limits.h>.
Mini Project: Type Size Printer
Write a program that reports the exact sizes and ranges of all fundamental types:
#include <stdio.h>
#include <limits.h>
#include <float.h>
int main() {
printf("Type Bytes Min Max\n");
printf("---- ----- --- ---\n");
printf("char %-5zu %-20d %-20d\n",
sizeof(char), CHAR_MIN, CHAR_MAX);
printf("unsigned char %-5zu %-20d %-20d\n",
sizeof(unsigned char), 0, UCHAR_MAX);
printf("short %-5zu %-20d %-20d\n",
sizeof(short), SHRT_MIN, SHRT_MAX);
printf("int %-5zu %-20d %-20d\n",
sizeof(int), INT_MIN, INT_MAX);
printf("unsigned int %-5zu %-20d %-20u\n",
sizeof(unsigned int), 0, UINT_MAX);
printf("long %-5zu %-20ld %-20ld\n",
sizeof(long), LONG_MIN, LONG_MAX);
printf("float %-5zu %-20e %-20e\n",
sizeof(float), FLT_MIN, FLT_MAX);
printf("double %-5zu %-20e %-20e\n",
sizeof(double), DBL_MIN, DBL_MAX);
return 0;
}
FAQ
What is Next
Now that you understand variables, proceed to Constants in C to learn about const qualifiers, #define macros, enum constants, and literal suffixes.