ref: https://github.com/0voice/cpp-learning-2025
I. Variables and Data Types
1. Basic Data Types
C++ provides fundamental data types to store different kinds of data for various scenarios:
| Type Category | Specific Type | Description | Example |
|---|---|---|---|
| Integer | int |
Basic integer (typically 4 bytes) | int age = 25; |
short |
Short integer (2 bytes, smaller range) | short score = 95; |
|
long |
Long integer (4/8 bytes, system-dependent) | long population = 1000000L; |
|
long long |
Very long integer (8 bytes, larger range) | long long bigNum = 12345678901234LL; |
|
| Unsigned | unsigned int (only non-negative, doubled positive range) |
unsigned int count = 100; |
|
| Floating-point | float |
Single-precision (4 bytes, lower precision) | float pi = 3.14f; (f suffix required, otherwise defaults to double) |
double |
Double-precision (8 bytes, recommended) | double salary = 12345.67; |
|
| Character | char |
Stores single character (1 byte, ASCII value) | char ch = 'A'; (single quotes) |
wchar_t |
Wide character (supports multi-byte characters) | wchar_t wch = L'中'; (L prefix) |
|
| Boolean | bool |
Stores only true (1) or false (0) |
bool isPass = true; |
2. Constant Qualifier const
- Purpose: Defines read-only variables (constants) that cannot be modified after initialization, enforced at compile time.
- Key Features:
- Must be initialized; cannot be reassigned later.
- Local
constvariables are stored on the stack, globalconstvariables are typically in read-only memory (modification leads to crashes).
- Example:
1
2
3const int MAX_AGE = 100; // Constant, cannot be modified
// MAX_AGE = 200; // Compilation error: assignment to read-only variable
const double PI = 3.1415926;
3. Type Alias typedef
- Purpose: Creates an alias for an existing data type, simplifying complex type declarations (e.g., pointers, structs).
- Syntax:
typedef OriginalType Alias; - Example:
1
2
3
4
5typedef int Score; // Alias 'Score' for 'int'
Score math = 90; // Equivalent to int math = 90;
typedef char* String; // Alias 'String' for 'char*' (C-style string)
String name = "Tom"; // Equivalent to char* name = "Tom"; - Note: In C++11 and later,
usingis recommended overtypedef(cleaner syntax, supports template aliases), buttypedefremains a fundamental exam topic.
II. Operators and Expressions
1. Arithmetic Operators
Used for numerical calculations; note the behavior of integer division and modulo:
| Operator | Function | Example | Result |
|---|---|---|---|
+ - |
Addition, Subtraction | 5+3 5-3 |
8, 2 |
* / |
Multiplication, Division | 5*3 5/3 |
15, 1 (Integer division: fractional part discarded) |
% |
Modulo (Remainder) | 5%3 7%4 |
2, 3 (Only for integer types) |
- Common Pitfalls:
- Division by zero causes a runtime crash.
- Floating-point division requires explicit casting:
(double)5/3yields1.666....
2. Relational Operators
Compare two values, returning a bool result (true/false):
| Operator | Function | Example | Result |
|---|---|---|---|
== |
Equal to | 5==3 |
false |
!= |
Not equal to | 5!=3 |
true |
> < |
Greater than, Less than | 5>3 5<3 |
true, false |
>= <= |
Greater than or equal to, Less than or equal to | 5>=5 3<=2 |
true, false |
- Interview Trap: Do not confuse
==(equality) with=(assignment). For example,if (a=5)assigns 5 toa, and the expression evaluates to 5 (non-zero, i.e.,true), causing a logical error.
3. Logical Operators
Used for logical operations (AND, OR, NOT); feature short-circuit evaluation (frequent interview topic):
| Operator | Function | Short-circuit Rule | Example | Result |
|---|---|---|---|---|
&& |
Logical AND (true only if both operands are true) | Right operand not evaluated if left is false |
(3>5)&&(++a) |
false (a not incremented) |
| ` | ` | Logical OR (true if at least one operand is true) | Right operand not evaluated if left is true |
|
! |
Logical NOT (negation) | No short-circuit | !(3>5) |
true |
4. Compound Assignment Operators
Shorthand for “variable = variable operator expression”; slightly more efficient than standard assignment.
| Operator | Equivalent Form | Example | Result |
|---|---|---|---|
+= |
a = a + b |
a=2; a+=3; |
a=5 |
-= |
a = a - b |
a=5; a-=2; |
a=3 |
*= /= %= |
Similar | a=4; a*=2; |
a=8 |
5. Increment/Decrement Operators (Prefix vs. Postfix)
Key Concept: Behavior differs in when the value is returned:
| Type | Syntax | Execution Logic | Example | Result |
|---|---|---|---|---|
| Prefix | ++a --a |
Increment/decrement first, then return the variable’s new value | a=2; b=++a; |
a=3, b=3 |
| Postfix | a++ a-- |
Return the variable’s original value first, then increment/decrement | a=2; b=a++; |
a=3, b=2 |
- Example:
1
2
3int a = 1;
int b = a++ + ++a; // Evaluation: 1 (a++ returns 1) + 3 (++a increments a to 3) → b=4
cout << b; // Output: 4
III. Control Flow
1. Branching: if-else
Executes different code blocks based on conditions; supports nesting.
- Syntax:
1
2
3
4
5
6
7if (condition1) {
// Executes if condition1 is true
} else if (condition2) {
// Executes if condition1 false and condition2 true
} else {
// Executes if all conditions false
} - Example:
1
2
3
4
5
6
7
8int score = 85;
if (score >= 90) {
cout << "Excellent" << endl;
} else if (score >= 60) {
cout << "Pass" << endl; // This branch executes
} else {
cout << "Fail" << endl;
} - Note: Braces
{}can be omitted for single statements, but always using them is recommended to avoid logical errors.
2. Branching: switch
Suitable for equality checks against multiple constant values (more concise than if-else chains).
- Syntax:
1
2
3
4
5
6
7
8
9
10switch (expression) { // Expression must be integral, char, or enum
case constant1:
// code
break; // Essential: exits switch block
case constant2:
// code
break;
default:
// Optional: executes if no case matches
} - Example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14char grade = 'B';
switch (grade) {
case 'A':
cout << "90+";
break;
case 'B':
cout << "80-89"; // This branch executes
break;
case 'C':
cout << "60-79";
break;
default:
cout << "Fail";
} - Interview Focus: Role of
break(prevents fall-through), placement ofdefault(can be anywhere, executes if no match).
3. Loops: for/while/do-while
(1) for Loop (Most common, suitable for known iteration count)
- Syntax:
for (initialization; loop condition; increment/decrement) { loop body } - Example: Iterating 1 to 5:
1
2
3for (int i = 1; i <= 5; i++) {
cout << i << " "; // Output: 1 2 3 4 5
} - Flexibility: Initialization and increment can be omitted (e.g.,
for (; ;)is an infinite loop).
(2) while Loop (Suitable for unknown iteration count, checks condition before execution)
- Syntax:
while (loop condition) { loop body } - Example: Summing 1 to 100:
1
2
3
4
5
6int sum = 0, i = 1;
while (i <= 100) {
sum += i;
i++;
}
cout << sum; // Output: 5050
(3) do-while Loop (Executes at least once, checks condition after execution)
- Syntax:
do { loop body } while (loop condition);(Note semicolon) - Example: Password input until correct:
1
2
3
4
5
6string pwd;
do {
cout << "Enter password: ";
cin >> pwd;
} while (pwd != "123456");
cout << "Correct password!";
4. Loop Control: break/continue
break: Exits the innermost loop orswitchstatement immediately.continue: Skips the rest of the current loop iteration and proceeds to the next iteration.- Example:
1
2
3
4
5
6
7
8
9for (int i = 1; i <= 5; i++) {
if (i == 3) break; // Exits loop, i=4,5 not executed
cout << i << " "; // Output: 1 2
}
for (int i = 1; i <= 5; i++) {
if (i == 3) continue; // Skips i=3, goes to i=4
cout << i << " "; // Output: 1 2 4 5
}
5. Input/Output: cin/cout + iomanip
(1) Basic I/O
cout: Outputs to the console; requires<iostream>header.cin: Reads input from the console; supports chaining for multiple variables.- Example:
1
2
3
4
5
6
7
8
9
10
11
using namespace std; // Avoids writing std::cout (explained later)
int main() {
int a;
string name;
cout << "Enter name and age: ";
cin >> name >> a; // Chained input, separated by space/enter
cout << "Hello, " << name << ", age " << a << endl; // endl: newline + flush
return 0;
}
(2) Formatting: <iomanip> Header
Controls output format (e.g., decimal places, alignment, base conversion):
| Function | Manipulator/Function | Example | Result |
|---|---|---|---|
| Decimal precision | fixed + setprecision(n) |
cout << fixed << setprecision(2) << 3.1415; |
3.14 |
| Base conversion | hex (hexadecimal), oct (octal), dec (decimal) |
cout << hex << 255; |
ff |
| Alignment | setw(n) (width) + left (left-align)/right (right-align) |
cout << setw(5) << left << "Tom"; |
Tom (5 chars wide, left-aligned) |
- Example:
1
2
3
cout << fixed << setprecision(3) << 1.2345 << endl; // 1.235 (rounded)
cout << hex << uppercase << 255 << endl; // FF (uppercase hex)
6. Namespaces: namespace
- Purpose: Resolves naming conflicts (e.g., same function/variable names in different libraries); a core C++ feature.
- Core Usage:
- Define a namespace:
1
2
3
4
5namespace MySpace {
int add(int a, int b) {
return a + b;
}
} - Use a namespace:
- Direct specification:
MySpace::add(1,2);(safest). using namespace NamespaceName;: Global import (simplifies code, e.g.,using namespace std;).- Partial import:
using MySpace::add;(imports only specified members).
- Direct specification:
- Define a namespace:
- Interview Focus:
stdis the namespace for the C++ Standard Library. Avoidusing namespace std;in header files (can cause naming conflicts).
IV. Functions
1. Function Declaration and Definition
- Three Components: Return type, function name, parameter list.
- Declaration: Informs the compiler about a function’s existence (no implementation); typically in header (
.h) files. - Definition: Provides the function’s actual implementation (must have a body); typically in source (
.cpp) files. - Syntax:
1
2
3
4
5
6
7// Declaration (in header)
int add(int a, int b); // Ends with semicolon, no body
// Definition (in source)
int add(int a, int b) { // No semicolon, has body
return a + b; // Return value matches return type
} - Note: Declaration and definition must match exactly in return type, name, and parameter list (parameter names can differ).
2. Function Parameter Passing: By Value/By Reference/By Pointer
(1) Pass by Value (Default)
- Behavior: Passes a copy of the argument; modifications inside the function do not affect the original variable.
- Example:
1
2
3
4
5
6
7
8void swap(int x, int y) {
int temp = x;
x = y;
y = temp; // Only modifies copies, originals unchanged
}
int a=1, b=2;
swap(a, b);
cout << a << "," << b; // Output: 1,2 (originals not swapped)
(2) Pass by Reference (&)
- Behavior: Passes an alias (reference) to the original variable (syntactic sugar for pointers); modifications affect the original.
- Syntax: Append
&to the parameter type. - Example:
1
2
3
4
5
6
7
8void swap(int& x, int& y) { // x is alias for a, y for b
int temp = x;
x = y;
y = temp; // Modifies the original variables
}
int a=1, b=2;
swap(a, b);
cout << a << "," << b; // Output: 2,1 (originals swapped) - Advantage: Safer than pointers (no dangling pointers), cleaner syntax; recommended in C++.
(3) Pass by Pointer (*)
- Behavior: Passes the memory address of the variable; function modifies the original via dereferencing (
*). - Syntax: Parameter type is a pointer (
Type*). - Example:
1
2
3
4
5
6
7
8void swap(int* x, int* y) { // x holds address of a, y of b
int temp = *x;
*x = *y;
*y = temp; // Dereferences to modify originals
}
int a=1, b=2;
swap(&a, &b); // Pass addresses (& is address-of operator)
cout << a << "," << b; // Output: 2,1 (originals swapped) - Interview Focus: Core differences between references and pointers (detailed later).
3. Return Values
- Functions return a value via
return(type must match the declared return type). - If no value is returned, use
voidas the return type (returncan be omitted). - Example:
1
2
3
4
5
6
7int max(int a, int b) {
return a > b ? a : b; // Returns the larger value
}
void printHello() {
cout << "Hello";
// No return, function ends after execution
} - Note:
returnimmediately terminates the function; code after it is not executed.
4. Function Overloading (Overload)
- Core Concept: Multiple functions can share the same name within the same scope if their parameter lists differ (number, type, or order of parameters).
- Compiler Matching: The function is chosen based on the arguments’ types and count.
- Example:
1
2
3
4
5
6
7int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; } // Different types: overload
int add(int a, int b, int c) { return a + b + c; } // Different count: overload
cout << add(1,2) << endl; // Calls int add(int,int) → 3
cout << add(1.5, 2.5) << endl; // Calls double add(double,double) → 4.0
cout << add(1,2,3) << endl; // Calls int add(int,int,int) → 6 - Common Mistake: Different return types alone do not constitute overloading (compiler cannot distinguish calls by return type).
5. Default Arguments
- Purpose: Assigns a default value to a function parameter; can be omitted during the call.
- Syntax: Assign the default value in the parameter declaration.
- Example:
1
2
3
4
5void printInfo(string name, int age = 18) { // Default age = 18
cout << "Name: " << name << ", Age: " << age << endl;
}
printInfo("Tom"); // Omits age, uses default 18 → Name: Tom, Age: 18
printInfo("Jerry", 20); // Explicit argument overrides default → Name: Jerry, Age: 20 - Rule: Default arguments must be specified consecutively from right to left (e.g.,
void func(int a=1, int b)is invalid).
6. Lambda Expressions (C++11+)
- Core Concept: Anonymous functions (no name) that can be embedded directly in code; suitable for short logic.
- Syntax:
[capture-list](parameters) -> return-type { body }(return-type can often be omitted, deduced by compiler). - Example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using namespace std;
int main() {
// Lambda with no capture, no parameters, returns int
auto add = []() -> int { return 1 + 2; };
cout << add() << endl; // Output: 3
// Lambda capturing external variables ([=] by value, [&] by reference), with parameters
int a = 1, b = 2;
auto swap = [&]() { // [&] captures a and b by reference, can modify originals
int temp = a;
a = b;
b = temp;
};
swap();
cout << a << "," << b; // Output: 2,1
return 0;
} - Primary Use: Used with STL algorithms (e.g.,
sort,for_each) for concise code (detailed in later STL sections).
V. Arrays and Strings
1. One-dimensional Arrays
(1) Definition and Initialization
- Syntax:
Type ArrayName[ArraySize];(Size must be a constant expression). - Initialization Methods:
1
2
3
4
5
6
7
8
9
10
11// Method 1: Full initialization
int arr1[3] = {1, 2, 3}; // Elements: [1,2,3]
// Method 2: Partial initialization (uninitialized elements default to 0)
int arr2[5] = {1, 2}; // Elements: [1,2,0,0,0]
// Method 3: Omit size (compiler deduces)
int arr3[] = {1, 2, 3, 4}; // Size: 4
// Method 4: C++11 list initialization (omit =)
int arr4[] {1, 2, 3};
(2) Array Access and Traversal
- Access via index (0-based):
arr[i](i from 0 to size-1). - Traversal:
1
2
3
4
5
6
7
8
9
10
11
12int arr[] = {1, 2, 3, 4, 5};
int len = sizeof(arr) / sizeof(arr[0]); // Calculate length (total bytes / bytes per element)
// Method 1: for loop
for (int i = 0; i < len; i++) {
cout << arr[i] << " "; // Output: 1 2 3 4 5
}
// Method 2: C++11 range-based for (cleaner)
for (int num : arr) {
cout << num << " "; // Output: 1 2 3 4 5
} - Common Pitfall: Array index out of bounds (e.g., accessing
arr[len]). Compiler may not warn, but runtime crash (illegal memory access) is likely.
2. Strings: C-style Strings vs. std::string
(1) C-style Strings (C compatibility)
- Nature: Character array terminated by a null character
'\0'(ASCII 0). - Definition:
1
2
3char str1[] = "Hello"; // Automatically adds '\0', length 6 (H e l l o \0)
char str2[] = {'H', 'i', '\0'}; // Must manually add '\0' for valid string
const char* str3 = "World"; // String literal (stored in read-only memory, cannot be modified) - Common Operations (require
<cstring>header):1
2
3
4
5
6
7
char str1[] = "Hello", str2[] = "World";
cout << strlen(str1); // Length (excluding '\0') → 5
strcpy(str1, str2); // Copy str2 to str1 (overwrites; ensure str1 is large enough)
strcat(str1, str2); // Concatenate str2 to end of str1
int cmp = strcmp(str1, str2); // Compare (0 if equal, positive if str1>str2, negative otherwise) - Drawbacks: Unsafe (no bounds checking, prone to buffer overflows), cumbersome.
(2) std::string (C++ standard string, recommended)
- Nature: String class from the
stdnamespace, encapsulating string operations; safe and convenient. - Prerequisite: Include
<string>header andusing namespace std;(or usestd::string). - Common Operations:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
string str = "Hello";
// Access
cout << str[0]; // Index access → 'H'
cout << str.at(1); // at() access (throws exception if out-of-bounds, safer) → 'e'
// Length
cout << str.size(); // 5
cout << str.length(); // 5 (equivalent to size())
// Concatenation
str += " World"; // Direct concatenation → "Hello World"
str.append("!"); // Append → "Hello World!"
// Comparison
if (str == "Hello World!") {
cout << "Equal" << endl; // Direct comparison with ==
}
// Search
int pos = str.find("World"); // Find substring, returns starting index → 6
if (pos != string::npos) { // string::npos indicates not found
cout << "Substring found" << endl;
}
// Substring extraction
string sub = str.substr(0, 5); // From index 0, 5 characters → "Hello" - Advantages: Automatic memory management, supports operators (
+,==,[]), safer bounds checking; the preferred choice for C++.
VI. Introduction to Pointers
1. Core Concepts: Definition/Dereferencing/Address-of
- Pointer Essence: A variable that stores the memory address of another variable (an address is a number identifying a memory cell, typically 4/8 bytes).
- Key Operators:
&: Address-of operator → obtains the memory address of a variable.*: Dereference operator → accesses the value at the stored address.
- Definition and Usage Example:
1
2
3
4
5
6
7
8
9int a = 10;
int* p = &a; // Define pointer p of type int*, storing address of a (&a)
cout << &a; // Outputs a's address (e.g., 0x7ffee4b7e7ac)
cout << p; // Outputs address stored in p (same as &a)
cout << *p; // Dereferences p, accesses the value at that address → 10 (equivalent to a)
*p = 20; // Modifies a via pointer
cout << a; // Outputs 20 (a changed) - Syntax Note:
int* p,int *p,int * pare equivalent;int* pis recommended for clarity (emphasizes p is a pointer).
2. Pointers and Arrays
- Key Relationship: An array name is essentially a constant pointer to the first element (cannot be reassigned).
- Equivalence:
arr[i] == *(arr + i)(array indexing is pointer arithmetic). - Example:
1
2
3
4
5
6
7
8
9int arr[] = {1, 2, 3, 4, 5};
int* p = arr; // Equivalent to int* p = &arr[0]; (p points to first element)
cout << *p; // Accesses first element → 1
cout << *(p + 1); // Pointer arithmetic, accesses arr[1] → 2
cout << p[2]; // Pointers also support subscript notation → 3 (equivalent to *(p+2))
p++; // Increment pointer, now points to arr[1] (moves by sizeof(int) bytes)
cout << *p; // Outputs 2 - Interview Focus: Difference between array name and pointer (array name is a constant pointer, cannot be incremented; pointer is a variable, can be reassigned).
3. Pointers and Functions
- Pointer as function parameter: Passes address to allow modification of original variable (pass by pointer, covered earlier).
- Function pointer: A pointer that stores the address of a function.
- Function Pointer Example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14// Define a function
int add(int a, int b) {
return a + b;
}
int main() {
// Define function pointer: ReturnType (*PointerName)(ParameterList)
int (*funcPtr)(int, int) = add; // funcPtr points to add
// Call function via pointer
int result = funcPtr(1, 2); // Equivalent to add(1,2)
cout << result; // Output: 3
return 0;
} - Use Case: Implementing callbacks (e.g., custom comparison in sorting algorithms), foundational for polymorphism in C++.
4. Dangling Pointers and nullptr
(1) Dangling Pointers (Dangerous!)
- Definition: Pointers that are uninitialized, point to freed memory, or point to illegal addresses.
- Risk: Dereferencing a dangling pointer can crash the program (illegal memory access), difficult to debug.
- Common Scenarios:
1
2
3
4
5
6int* p; // Uninitialized, p holds garbage value (dangling pointer)
*p = 10; // Dangerous! Accesses random memory
int* q = new int(5);
delete q; // After deletion, q becomes dangling (points to freed memory)
*q = 20; // Dangerous!
(2) nullptr (C++11+)
- Purpose: Represents a null pointer (points to no valid address), replacing C’s
NULL(which is typically0, can cause ambiguity). - Best Practice: Initialize pointers to
nullptrif they don’t point to a valid object initially. - Example:
1
2
3
4
5int* p = nullptr; // Initialize as null pointer
if (p == nullptr) { // Safe check for null
cout << "p is a null pointer" << endl;
}
// *p = 10; // Compiles, but runtime crash (cannot dereference null pointer) - Interview Focus: Difference between
nullptrandNULL(nullptrhas pointer type,NULLis integral constant0, avoiding overload ambiguity).
5. Core Differences Between Pointers and References (High-Frequency Interview Topic)
| Aspect | Pointer (*) |
Reference (&) |
|---|---|---|
| Nature | Variable storing a memory address | Alias for an existing variable (syntactic sugar for pointer) |
| Initialization | Can be null (nullptr), can be reassigned |
Must be initialized upon declaration (binds to a variable), cannot be rebound |
| Null Value | Supports nullptr (null pointer) |
Cannot be null (must bind to a valid object) |
| Increment/Decrement | Can be incremented/decremented (changes the address it points to) | Increment/decrement modifies the bound variable’s value, not the reference itself |
| Multi-level | Supports multi-level pointers (int** p) |
No multi-level references (int&& r is an rvalue reference, not multi-level) |
| Safety | Risk of dangling pointers; requires manual null checks | Safer (no null references), no need for null checks |
| Syntax | Dereference (*p), address-of (&p for pointer’s address) |
Used directly (r is equivalent to the original variable) |
| Typical Use | Dynamic memory allocation, function pointers, multi-level indirection | Function parameters (avoid copy), return values, aliasing variables |
- Key Summary: Prefer references for safety and simplicity; use pointers when you need “null” semantics or the ability to reassign what they point to.
说些什么吧!