What you'll learn
Every C object has a type, a region of storage, and a lifetime. This lesson turns those ideas into practical code: declarations, fundamental types, constants, expressions, conversions, and the rules that keep arithmetic well-defined.
By the end, you'll be able to:
- Declare and initialize variables with appropriate types
- Use arithmetic, comparison, logical, and assignment operators correctly
- Predict common implicit conversions and apply explicit casts deliberately
- Explain why type sizes and signed overflow require care
Variables & declarations
A variable is a named object whose type determines which values it can represent and which operations make sense. In C, declare a variable before using it. Initialize it immediately whenever you already know its first value.
#include <stdio.h>
int main(void) {
int age = 25; // declaration + initialization
double price = 19.95;
char grade = 'A';
age = 26; // assignment: replace the stored value
printf("Age: %d\n", age);
printf("Price: %.2f\n", price);
printf("Grade: %c\n", grade);
return 0;
}Uninitialized is not zero
int count = 0;.ageint25
typically 4 byte(s)
pricedouble19.95
typically 8 byte(s)
gradechar'A'
exactly 1 byte(s)
readybooltrue
implementation-defined byte(s)
Fundamental types
| Family | Examples | Purpose |
|---|---|---|
char | 'A' | Characters, small integers, and individual bytes |
short, int, long, long long | -42 | Signed whole numbers with increasing minimum ranges |
unsigned ... | 42U | Nonnegative modular integers and bit manipulation |
float, double, long double | 3.14 | Approximate real-number calculations |
bool | true | Boolean intent through stdbool.h |
void | no value | No return value or generic pointer base type |
C represents false as zero and true as nonzero. Including <stdbool.h>provides the readable aliases bool, true, and false.
#include <stdbool.h>
#include <stdio.h>
int main(void) {
bool enrolled = true;
bool can_graduate = enrolled && (120 >= 120);
printf("Can graduate: %s\n", can_graduate ? "yes" : "no");
return 0;
}Modifiers & fixed-width types
Modifiers let you request a different range or signedness. Exact sizes still depend on the implementation. When a binary format or protocol requires exactly 32 or 64 bits, use the optional fixed-width types from <stdint.h>.
Language standards matter
9'000 arrive in C23; they are invalid in C17. The corrected C17 version below uses suffixes that match the intended types.#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>
int main(void) {
unsigned int attempts = 3U;
long long distance = 9'000; // not valid in C17: use 9000
int32_t temperature = -12;
uint64_t stars = UINT64_C(10000000000);
printf("%u %lld %" PRId32 " %" PRIu64 "\n",
attempts, distance, temperature, stars);
return 0;
}#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>
int main(void) {
unsigned int attempts = 3U;
long long distance = 9000LL;
int32_t temperature = -12;
uint64_t stars = UINT64_C(10000000000);
printf("%u %lld %" PRId32 " %" PRIu64 "\n",
attempts, distance, temperature, stars);
return 0;
}Tip
<inttypes.h>, such as PRId32, provide portable printf formats for fixed-width integer types.Constants, literals & sizeof
Use const for an object your program should not modify. Preprocessor constants remain useful for compile-time sizes and conditional compilation, though they have no C type. The sizeof operator reports storage in bytes as a size_tvalue, printed with %zu.
#include <stdio.h>
#define MAX_STUDENTS 30
int main(void) {
const double tax_rate = 0.11;
int scores[MAX_STUDENTS] = {0};
printf("int: %zu bytes\n", sizeof(int));
printf("scores: %zu bytes\n", sizeof scores);
printf("elements: %zu\n", sizeof scores / sizeof scores[0]);
printf("tax: %.0f%%\n", tax_rate * 100.0);
return 0;
}Note
sizeof(char), which is always 1. A byte is at least eight bits, but the standard does not require every machine to use eight-bit bytes.Operators & expressions
An expression computes a value. Operators combine operands into larger expressions. Arithmetic on two integers produces an integer, so 17 / 5 is 3, not 3.4.
#include <stdio.h>
int main(void) {
int a = 17;
int b = 5;
printf("%d\n", a + b); // 22
printf("%d\n", a / b); // 3: integer division
printf("%d\n", a % b); // 2: remainder
a += 3; // same as a = a + 3
printf("%d\n", a);
printf("%d\n", a > b && b != 0);
return 0;
}| Category | Operators |
|---|---|
| Arithmetic | + - * / % |
| Comparison | == != < <= > >= |
| Logical | ! && || |
| Assignment | = += -= *= /= %= |
| Increment | ++ -- |
Equality uses ==
= assigns. Two equals signs, ==, compare. Compilers often warn about accidental assignment in a condition—another reason to keep warnings enabled.Conversions & casts
C automatically promotes smaller integer types and finds a common type for mixed operands. Assignment then converts the result to the destination type. An explicit cast should make a deliberate conversion visible, not silence a warning you do not understand.
#include <stdio.h>
int main(void) {
int total = 7;
int count = 2;
double wrong = total / count; // int division first: 3.0
double average = (double) total / count; // 3.5
int truncated = (int) 9.8; // 9
printf("%.1f %.1f %d\n", wrong, average, truncated);
return 0;
}Key idea
total / count would be too late because integer division has already discarded the fraction.Overflow & undefined behavior
Unsigned arithmetic is modular: it wraps within the type's range. Signed integer overflow is undefined behavior, meaning the C standard places no requirements on the result. Validate ranges before arithmetic when values may approach their limits.
#include <limits.h>
#include <stdio.h>
int main(void) {
unsigned int counter = UINT_MAX;
counter += 1U; // defined wraparound to 0
printf("%u\n", counter);
// Do not do this: signed overflow is undefined behavior.
// int broken = INT_MAX + 1;
return 0;
}Watch out
Recap & quick check
Key takeaways
- A C declaration gives an object a name and type; initialization supplies its first value.
- Type widths vary, so use sizeof, limits headers, or fixed-width types when size matters.
- Integer division discards the fractional part when both operands are integers.
- Implicit conversions happen throughout expressions; cast only when the intended conversion is clear.
- Unsigned arithmetic wraps, while signed integer overflow is undefined behavior.
Quick check
1. What value does 7 / 2 produce when both operands are int?
2. Which format specifier prints a size_t value?
3. What is true about signed integer overflow?
4. Why cast total before dividing by count?
You can now model and calculate with C values. Next up: Module 3 — Input, Output & Formatting, where your programs begin communicating with users.