Variables and Data Types
Variables are like labeled boxes — each box has a name and a type, and can only hold the right kind of item. Put the wrong thing in, and things go wrong.
What Is a Variable
A variable is a named memory location in your program used to store data. Think of it as a box:
- Variable name: The label on the box, so you can find it
- Data type: What kind of items the box can hold
- Variable value: What's currently inside the box
- Memory address: The box's location in the warehouse
Variable Declaration and Initialization
Declaring a Variable
Declaring a variable tells the compiler: "I need a box, here's its name and what type of things it holds."
int age;
float weight;
char blood_type;
After declaration, the variable's value is undefined (a garbage value) — it contains whatever random data was left in that memory location. Never use an uninitialized variable!
Initializing a Variable
Initialization means giving a variable an initial value at the same time you declare it:
int age = 20;
float weight = 65.5f;
char blood_type = 'A';
Declare First, Assign Later
You can also declare first and assign later:
int age;
age = 20;
This has the same effect, but the two-step approach is more spread out, making it easier to accidentally use the variable between declaration and assignment while it's still uninitialized.
Declaring Multiple Variables of the Same Type
int a = 1, b = 2, c = 3;
Variable Naming Rules
C has strict rules for variable names:
Must follow:
- Can only contain letters (a-z, A-Z), digits (0-9), and underscores (_)
- Must start with a letter or underscore — cannot start with a digit
- Cannot be a C keyword (like
int,return,if, etc.) - Case-sensitive (
Ageandageare different variables)
Should follow:
- Names should be meaningful: use
student_countinstead ofsc - Use snake_case style (lowercase letters + underscores)
- Avoid names starting with double underscores (like
__count) — compilers use these internally - Avoid excessively long names (over 31 characters may not be supported by all compilers)
| Name | Valid? | Notes |
|---|---|---|
age |
Valid | Short and meaningful |
_count |
Valid | Starts with underscore |
student_name |
Valid | snake_case style |
2nd_place |
Invalid | Starts with a digit |
my-score |
Invalid | Contains hyphen (interpreted as subtraction) |
int |
Invalid | Keyword |
Age |
Valid but not recommended | Capital first letter usually reserved for type names |
Basic Data Types
A C data type determines how much memory a variable occupies, the range of values it can hold, and how the data is interpreted. Here are C99's basic data types:
Integer Types
| Type | Size (bytes) | Typical Range | Format Specifier |
|---|---|---|---|
char |
1 | -128 ~ 127 | %c or %d |
unsigned char |
1 | 0 ~ 255 | %u |
short |
2 | -32768 ~ 32767 | %hd |
unsigned short |
2 | 0 ~ 65535 | %hu |
int |
4 | -2147483648 ~ 2147483647 | %d |
unsigned int |
4 | 0 ~ 4294967295 | %u |
long |
4 or 8 | Platform-dependent | %ld |
unsigned long |
4 or 8 | Platform-dependent | %lu |
long long |
8 | -9223372036854775808 ~ 9223372036854775807 | %lld |
int is sufficient. Use long long when you need a larger range, and char for characters. short is rarely used on modern platforms because int is typically just as efficient.
int as 4 bytes, which is the case on most modern platforms. However, the C standard only requires int to be at least 2 bytes. The actual size depends on the platform — use sizeof to confirm.
Floating-Point Types
| Type | Size (bytes) | Significant Digits | Range (absolute value) | Format Specifier |
|---|---|---|---|---|
float |
4 | 6-7 | 1.2e-38 ~ 3.4e38 | %f |
double |
8 | 15-16 | 2.2e-308 ~ 1.8e308 | %lf |
long double |
8 or more | 18+ | Platform-dependent | %Lf |
Floating-point numbers have limited precision and cannot represent all decimals exactly. For example:
float f = 0.1f;
printf("%.20f\n", f);
0.10000000149011611938
0.1 is an infinitely repeating binary fraction, so float can't store it precisely. This is an inherent characteristic of floating-point representation, not a bug.
double by default when you need decimal numbers. It offers higher precision and is no slower than float on modern CPUs. Only prefer float on memory-constrained embedded systems.
The Character Type
The char type is essentially a 1-byte integer, typically used to store characters. Characters are stored in memory as ASCII codes:
char ch = 'A';
printf("%c\n", ch);
printf("%d\n", ch);
A
65
The ASCII code for 'A' is 65. Using %c prints the character, while %d prints the integer value. This shows that characters and integers are interchangeable in C.
'A' is a character (single quotes), while "A" is a string (double quotes, with a trailing \0). They are completely different — never mix them up.
The _Bool Type
C99 introduced the _Bool type, which can only store 0 and 1. Include <stdbool.h> to use bool, true, and false:
#include <stdbool.h>
bool is_valid = true;
bool is_empty = false;
The sizeof Operator
sizeof is a C keyword (not a function) that returns the number of bytes a data type or variable occupies:
Example
#include <stdio.h>
int main(void) {
printf("char: %zu bytes\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 bytes
short: 2 bytes
int: 4 bytes
long: 4 bytes
long long: 8 bytes
float: 4 bytes
double: 8 bytes
sizeof returns a size_t type, whose format specifier is %zu. If your compiler doesn't support %zu (some older versions), you can use %lu instead.
sizeof also works with variables:
int age = 20;
printf("%zu\n", sizeof(age));
Formatted Output in Detail
Integer Formatting
int n = 42;
printf("Decimal: %d\n", n);
printf("Octal: %o\n", n);
printf("Hex (lowercase): %x\n", n);
printf("Hex (uppercase): %X\n", n);
printf("Octal with prefix: %#o\n", n);
printf("Hex with prefix: %#x\n", n);
Decimal: 42
Octal: 52
Hex (lowercase): 2a
Hex (uppercase): 2A
Octal with prefix: 052
Hex with prefix: 0x2a
Floating-Point Formatting
double pi = 3.141592653589793;
printf("Default: %f\n", pi);
printf("2 decimal places: %.2f\n", pi);
printf("8 decimal places: %.8f\n", pi);
printf("Scientific notation: %e\n", pi);
printf("Width 12.2f: [%12.2f]\n", pi);
Default: 3.141593
2 decimal places: 3.14
8 decimal places: 3.14159265
Scientific notation: 3.141593e+00
Width 12.2f: [ 3.14]
Type Value Ranges
The C standard library provides header files for querying the range of each type:
limits.h (Integer Types)
#include <limits.h>
printf("int min: %d\n", INT_MIN);
printf("int max: %d\n", INT_MAX);
printf("char max: %d\n", CHAR_MAX);
Common macros:
| Macro | Meaning |
|---|---|
INT_MIN |
Minimum value of int |
INT_MAX |
Maximum value of int |
CHAR_MIN |
Minimum value of char |
CHAR_MAX |
Maximum value of char |
LONG_MAX |
Maximum value of long |
LLONG_MAX |
Maximum value of long long |
float.h (Floating-Point Types)
#include <float.h>
printf("float significant digits: %d\n", FLT_DIG);
printf("double significant digits: %d\n", DBL_DIG);
printf("float max value: %e\n", FLT_MAX);
Example
Example
#include <stdio.h>
#include <limits.h>
#include <float.h>
int main(void) {
char ch = 'Z';
int num = 100;
float f = 3.14f;
double d = 2.718281828;
printf("char '%c' = ASCII %d, size = %zu\n", ch, ch, sizeof(ch));
printf("int %d, size = %zu, range = [%d, %d]\n", num, sizeof(num), INT_MIN, INT_MAX);
printf("float %.6f, size = %zu, digits = %d\n", f, sizeof(f), FLT_DIG);
printf("double %.9f, size = %zu, digits = %d\n", d, sizeof(d), DBL_DIG);
return 0;
}
char 'Z' = ASCII 90, size = 1
int 100, size = 4, range = [-2147483648, 2147483647]
float 3.140000, size = 4, digits = 6
double 2.718281828, size = 8, digits = 15
Example
#include <stdio.h>
int main(void) {
char lower = 'a';
char upper = lower - 32;
printf("Lowercase: %c (ASCII %d)\n", lower, lower);
printf("Uppercase: %c (ASCII %d)\n", upper, upper);
printf("\nDigit characters:\n");
char digit = '0';
printf("Character '%c' ASCII code = %d\n", digit, digit);
printf("Character '%c' numeric value = %d\n", digit, digit - '0');
return 0;
}
Lowercase: a (ASCII 97)
Uppercase: A (ASCII 65)
Digit characters:
Character '0' ASCII code = 48
Character '0' numeric value = 0
'0' from a digit character gives its numeric value — this is the basis for converting characters to numbers.
❓ FAQ
📖 Summary
- Variables are named memory locations; specify the type and name when declaring, and always initialize
- Names must start with a letter or underscore, are case-sensitive, and cannot use keywords
- Integer types: char (1 byte), short (2), int (4), long (4 or 8), long long (8)
- Floating-point types: float (4 bytes, 6-7 digits precision), double (8 bytes, 15-16 digits precision)
- sizeof returns the byte size of a type or variable; limits.h and float.h provide value ranges
📝 Exercises
- Write a program that uses sizeof to print the byte sizes of all integer and floating-point types on your computer. Compare with a classmate's results to see if they match.
- Write a program that prints the ASCII codes for letters 'a' through 'z', five per line, using %-5d for alignment.
- Calculate and print the result of INT_MAX + 1 (integer overflow). Compare the output with INT_MIN and think about why this happens.



