Reading — step 1 of 8
Learn
C++ is statically typed — every variable has a type fixed at declaration. The compiler catches type mismatches before your program runs. Coming from a dynamic language, this feels strict; the payoff is bugs caught at compile time and faster code.
The fundamental types
// Integer types (size depends on platform; common values shown):
short s = 100; // at least 16 bits
int count = 5; // typically 32 bits
long l = 1000000L; // at least 32 bits (often 64 on Linux)
long long big = 1234567890123LL; // at least 64 bits
// Unsigned variants — non-negative only, double the positive range:
unsigned int u = 42;
uint64_t exact = 100; // exactly 64 bits, from <cstdint>
// Floating point:
float f = 3.14f; // 32-bit, suffix f
double pi = 3.14; // 64-bit, the default for decimals
long double precise = 3.14L;
// Other:
bool flag = true; // 1 byte, true or false
char c = 'A'; // 1 byte, single quotes
For portable, exact-width integers use <cstdint>: int8_t, int32_t, uint64_t. Avoid raw int when size matters.
std::string for text
#include <string>
std::string name = "Alice";
name += " Smith";
std::cout << name.length();
Double quotes for strings, single quotes for char. std::string is the standard library's string class.
Initialization styles
C++ has FOUR ways to initialize, all common in real code:
int a = 5; // copy initialization
int b(5); // direct initialization
int c{5}; // brace initialization (C++11) — preferred
int d = {5}; // copy-list initialization
Brace initialization ({}) is recommended in modern C++:
- Prevents narrowing conversions (
int x{3.7}is an error) - Works uniformly for all types
- Avoids the most-vexing-parse pitfall
auto — type inference
Since C++11:
auto count = 5; // int
auto pi = 3.14; // double
auto name = std::string("Alice");
auto v = std::vector<int>{1, 2, 3};
auto deduces the type from the initializer. Useful for verbose template types: auto it = container.begin(); instead of typing out the whole iterator type.
const — immutability
const int MAX = 100;
MAX = 200; // ✗ compile error
const int& ref = count; // const reference — read-only view
int* const p = &count; // const pointer (can't repoint)
const int* p2 = &count; // pointer to const (can't modify *p2)
Convention: put const early in the type. Use it aggressively — anything that won't change should be marked.
⚠️ Uninitialized values are UNDEFINED
int x; // local — UNDEFINED value
std::cout << x; // undefined behavior!
C++ doesn't zero-init local primitives. Reading uninitialized memory is undefined behavior — anything can happen, including looking like it works.
Always initialize: int x = 0; or int x{}; (zero-init via brace).
Integer overflow
int x = INT_MAX;
int y = x + 1; // signed overflow — UNDEFINED behavior!
unsigned int u = UINT_MAX;
unsigned int v = u + 1; // unsigned overflow → wraps to 0 (defined)
Signed overflow is undefined behavior — the compiler can assume it won't happen and optimize accordingly. Unsigned overflow wraps around (defined). Watch for both.
Type conversions
int a = 5;
double b = a; // implicit widening — fine
int c = b; // implicit narrowing — works but loses info
int d = static_cast<int>(b); // explicit — clearer intent
Prefer static_cast<T>(value) over C-style (T)value — explicit, search-friendly, safer.
Common mistakes
- Reading uninitialized memory: undefined behavior. Initialize everything.
- Mixing signed and unsigned: comparison surprises (
-1 < 0uis FALSE —-1becomes huge unsigned). - Forgetting
const: misses optimizations and lets bugs in. - Using
intwhen size matters: portability bug. Useint32_tetc. - Floating-point equality:
0.1 + 0.2 == 0.3is false. Use a tolerance.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…