C++ 是一种通用编程语言,由 Bjarne Stroustrup 于 1979 年在贝尔实验室开发。它是 C 语言的扩展,增加了面向对象编程(OOP)、泛型编程等特性。
让我们从一个经典的 "Hello World" 程序开始:
#include <iostream>
int main() {
std::cout << "Hello World" << std::endl;
return 0;
}
#include <iostream>:包含输入输出流头文件,使我们可以使用 cin 和 coutint main():主函数,程序的入口点std::cout:标准输出流对象,用于向屏幕输出内容<<:插入运算符,将右侧的内容发送到左侧的流std::endl:换行符,输出后换行并刷新缓冲区return 0;:返回 0 表示程序正常结束std 是标准命名空间,cout 和 endl 都定义在这个命名空间中。使用 using namespace std; 可以省略 std:: 前缀。
注释用于解释代码,不会被编译器执行。良好的注释习惯是编程的基本素养。
// 这是单行注释,从 // 开始到行末都是注释
int a = 10; // 也可以放在代码后面
/*
这是多行注释
可以跨越多行
用于较长的说明
*/
C++ 提供了两种主要的输入输出方式:
#include <iostream>
using namespace std;
int main() {
int x, y;
cin >> x >> y; // 读入 x 和 y
cout << "x = " << x << endl;
cout << "y = " << y << endl;
cout << "x + y = " << x + y << endl;
return 0;
}
#include <cstdio>
int main() {
int x, y;
scanf("%d%d", &x, &y); // 读入 x 和 y
printf("x = %d\n", x);
printf("y = %d\n", y);
printf("x + y = %d\n", x + y);
return 0;
}
| 格式符 | 说明 | 示例 |
|---|---|---|
%d | 有符号整数 | printf("%d", 42); |
%lld | 长整型 (long long) | printf("%lld", n); |
%f | 浮点数 | printf("%f", 3.14); |
%lf | 双精度浮点数 | printf("%lf", 3.14); |
%c | 字符 | printf("%c", 'A'); |
%s | 字符串 | printf("%s", "hello"); |
%.2f | 保留2位小数 | printf("%.2f", 3.14159); |
scanf 和 printf 通常比 cin 和 cout 更快,适合处理大量数据。
#include 是预处理指令,用于包含头文件:
| 头文件 | 功能 |
|---|---|
<iostream> | 输入输出流 (cin, cout) |
<cstdio> | C 标准输入输出 (scanf, printf) |
<cmath> | 数学函数 (sqrt, pow, sin 等) |
<string> | 字符串类 string |
<vector> | 动态数组 vector |
<algorithm> | 算法库 (sort, max, min 等) |
<cstring> | C 字符串操作 (strlen, strcpy 等) |
#define 用于定义宏,本质是文本替换:
#include <iostream>
using namespace std;
#define PI 3.14159265
#define MAX_SIZE 1000
#define SQUARE(x) ((x) * (x))
int main() {
cout << "PI = " << PI << endl;
cout << "MAX_SIZE = " << MAX_SIZE << endl;
cout << "5的平方 = " << SQUARE(5) << endl;
return 0;
}
SQUARE(1+2) 会展开为 ((1+2) * (1+2)),如果没有括号保护,结果可能出错。
变量是程序中用于存储数据的容器。每个变量都有:
| 类型 | 字节数 | 范围 | 说明 |
|---|---|---|---|
int | 4 | -2,147,483,648 ~ 2,147,483,647 | 最常用的整型 |
long long | 8 | -9.2×10¹⁸ ~ 9.2×10¹⁸ | 大整数 |
short | 2 | -32,768 ~ 32,767 | 短整型 |
unsigned int | 4 | 0 ~ 4,294,967,295 | 无符号整型 |
unsigned long long | 8 | 0 ~ 1.8×10¹⁹ | 无符号长整型 |
| 类型 | 字节数 | 有效数字 | 说明 |
|---|---|---|---|
float | 4 | 约 7 位 | 单精度浮点数 |
double | 8 | 约 15 位 | 双精度浮点数(推荐) |
| 类型 | 字节数 | 范围/值 | 说明 |
|---|---|---|---|
char | 1 | -128 ~ 127 或 0 ~ 255 | 字符型 |
bool | 1 | true / false | 布尔型 |
int 和 long long 是最常用的整型。当数值可能超过 2×10⁹ 时,应使用 long long。
// 声明变量
int a; // 声明一个整型变量 a
double x, y; // 声明两个双精度浮点变量
// 初始化变量
int b = 10; // 声明并初始化
int c(20); // 构造函数初始化
int d{30}; // C++11 列表初始化(推荐)
// 多变量声明和初始化
int e = 1, f = 2, g = 3;
// 使用 auto 自动推导类型(C++11)
auto num = 100; // num 是 int 类型
auto pi = 3.14; // pi 是 double 类型
sum 和 Sum 是不同的变量)// 好的命名
int studentCount; // 小驼峰命名法
int student_count; // 下划线命名法
const int MAX_SIZE = 100; // 常量用大写
// 不好的命名
int a, b, c; // 无意义的名字
int x1, x2, x3; // 难以理解
int 1stPlace; // 错误:不能以数字开头
int my-var; // 错误:不能包含连字符
int a = 10;
double b = a; // int 自动转换为 double,b = 10.0
double x = 3.7;
int y = x; // double 自动转换为 int,y = 3(截断)
double x = 3.7;
// C 风格转换
int y = (int)x; // y = 3
// C++ 风格转换
int z = static_cast<int>(x); // z = 3
// 四舍五入
int w = (int)(x + 0.5); // w = 4
| 运算符 | 功能 | 示例 | 结果 |
|---|---|---|---|
+ | 加法 | 5 + 3 | 8 |
- | 减法 | 5 - 3 | 2 |
* | 乘法 | 5 * 3 | 15 |
/ | 除法 | 7 / 2 | 3(整数除法) |
% | 取模(求余数) | 7 % 2 | 1 |
7.0 / 2 结果为 3.5。
int i = 5;
// 前置自增:先加1,再使用
int a = ++i; // i = 6, a = 6
// 后置自增:先使用,再加1
int b = i++; // b = 6, i = 7
// 前置自减:先减1,再使用
int c = --i; // i = 6, c = 6
// 后置自减:先使用,再减1
int d = i--; // d = 6, i = 5
i++ 和 ++i 效果相同。但 ++i 效率略高(不需要保存旧值),在 C++ 中推荐使用前置自增。
| 运算符 | 示例 | 等价于 |
|---|---|---|
+= | a += b | a = a + b |
-= | a -= b | a = a - b |
*= | a *= b | a = a * b |
/= | a /= b | a = a / b |
%= | a %= b | a = a % b |
| 运算符 | 功能 | 示例 |
|---|---|---|
== | 等于 | a == b |
!= | 不等于 | a != b |
> | 大于 | a > b |
< | 小于 | a < b |
>= | 大于等于 | a >= b |
<= | 小于等于 | a <= b |
== 写成 =。if (a = 5) 是赋值语句,结果总是为真!正确的写法是 if (a == 5)。
| 运算符 | 功能 | 说明 |
|---|---|---|
&& | 逻辑与 | 两个条件都为真时结果为真 |
|| | 逻辑或 | 至少一个条件为真时结果为真 |
! | 逻辑非 | 取反,真变假,假变真 |
int age = 20;
bool hasID = true;
// 逻辑与:两个条件都要满足
if (age >= 18 && hasID) {
cout << "可以进入" << endl;
}
// 逻辑或:满足一个条件即可
if (age < 12 || age > 60) {
cout << "可以享受优惠" << endl;
}
// 逻辑非:取反
bool isRaining = false;
if (!isRaining) {
cout << "天气不错" << endl;
}
&&,如果左边为假,右边不会计算;对于 ||,如果左边为真,右边不会计算。
| 运算符 | 功能 | 示例 |
|---|---|---|
& | 按位与 | 5 & 3 = 1 |
| | 按位或 | 5 | 3 = 7 |
^ | 按位异或 | 5 ^ 3 = 6 |
~ | 按位取反 | ~5 |
<< | 左移 | 5 << 1 = 10 |
>> | 右移 | 5 >> 1 = 2 |
// 左移相当于乘以 2
int a = 5;
a = a << 1; // a = 10 (5 * 2)
a = a << 2; // a = 40 (10 * 4)
// 右移相当于除以 2
int b = 20;
b = b >> 1; // b = 10 (20 / 2)
b = b >> 2; // b = 2 (10 / 4)
// 判断奇偶
if (n & 1) {
cout << "n 是奇数" << endl;
} else {
cout << "n 是偶数" << endl;
}
条件运算符是 if-else 的简写形式:
// 语法:条件 ? 表达式1 : 表达式2
// 如果条件为真,返回表达式1的值;否则返回表达式2的值
int a = 10, b = 20;
int max = (a > b) ? a : b; // max = 20
// 实际应用:求绝对值
int x = -5;
int abs_x = (x >= 0) ? x : -x; // abs_x = 5
逗号运算符可将多个表达式分隔开来,整个表达式的值是最后的表达式的值。
int a = (1 + 2, 3 + 4, 5 + 6); // a = 11
// 常用于 for 循环
for (int i = 0, j = 10; i < j; i++, j--) {
// ...
}
数组是一种数据结构,用于存储相同类型的多个元素。这些元素在内存中连续存放,可以通过下标访问。
// 声明数组
int arr[10]; // 声明长度为10的数组,元素值未初始化
// 声明并初始化
int nums[5] = {1, 2, 3, 4, 5}; // 完全初始化
int values[5] = {1, 2}; // 部分初始化,其余为0
int zeros[5] = {}; // 全部初始化为0
int data[] = {1, 2, 3, 4, 5}; // 自动推断长度为5
// 使用常量定义大小
const int N = 100;
int a[N]; // 正确
int arr[5] = {10, 20, 30, 40, 50};
// 访问元素(下标从0开始)
cout << arr[0] << endl; // 输出 10
cout << arr[4] << endl; // 输出 50
// 修改元素
arr[2] = 100; // arr 变为 {10, 20, 100, 40, 50}
// 遍历数组
for (int i = 0; i < 5; i++) {
cout << arr[i] << " ";
}
二维数组可以看作"数组的数组",常用于表示矩阵、表格等。
// 声明二维数组
int matrix[3][4]; // 3行4列
// 声明并初始化
int arr[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
// 部分初始化
int b[2][3] = {{1}, {4, 5}}; // b[0] = {1,0,0}, b[1] = {4,5,0}
// 全部初始化为0
int c[3][4] = {};
int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
// 访问元素
cout << arr[0][1] << endl; // 输出 2
cout << arr[1][2] << endl; // 输出 6
// 遍历二维数组
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
cout << arr[i][j] << " ";
}
cout << endl;
}
// 数组大小计算
int arr[10];
cout << sizeof(arr) << endl; // 40 (10 * 4字节)
cout << sizeof(arr[0]) << endl; // 4 (一个int的大小)
cout << sizeof(arr) / sizeof(arr[0]) << endl; // 10 (元素个数)
C 风格字符串是以空字符 '\0' 结尾的字符数组:
#include <cstring>
char str1[] = "Hello"; // 自动添加 '\0',长度为6
char str2[10] = "World"; // 剩余位置填充 '\0'
char str3[] = {'H', 'i', '\0'}; // 显式添加结束符
// 常用函数
cout << strlen(str1) << endl; // 5(不含 '\0')
strcpy(str2, str1); // 复制字符串
strcat(str1, " World"); // 连接字符串
strcmp(str1, str2); // 比较字符串(相等返回0)
C++ 的 string 类更加安全方便,推荐使用:
#include <iostream>
#include <string>
using namespace std;
int main() {
// 创建字符串
string s1 = "Hello";
string s2("World");
string s3(5, 'a'); // "aaaaa"
// 字符串连接
string s4 = s1 + " " + s2; // "Hello World"
s1 += "!"; // s1 = "Hello!"
// 访问字符
cout << s1[0] << endl; // 'H'
cout << s1.at(0) << endl; // 'H'(带边界检查)
// 字符串长度
cout << s1.length() << endl; // 6
cout << s1.size() << endl; // 6
cout << s1.empty() << endl; // false(是否为空)
// 子串
string s = "Hello World";
cout << s.substr(0, 5) << endl; // "Hello"
cout << s.substr(6) << endl; // "World"
// 查找
cout << s.find("World") << endl; // 6(找到返回位置)
cout << s.find("abc") << endl; // string::npos(未找到)
// 输入
string name;
cin >> name; // 读入一个单词(遇空格停止)
getline(cin, name); // 读入一行(包括空格)
return 0;
}
getline(cin, s) 可以读入包含空格的整行字符串。
// 基本 if 语句
if (条件) {
// 条件为真时执行
}
// if-else 语句
if (score >= 60) {
cout << "及格" << endl;
} else {
cout << "不及格" << endl;
}
// if-else if-else 语句
if (score >= 90) {
cout << "优秀" << endl;
} else if (score >= 80) {
cout << "良好" << endl;
} else if (score >= 60) {
cout << "及格" << endl;
} else {
cout << "不及格" << endl;
}
switch 语句用于根据一个整型表达式的值选择执行不同的分支:
int day = 3;
switch (day) {
case 1:
cout << "星期一" << endl;
break;
case 2:
cout << "星期二" << endl;
break;
case 3:
cout << "星期三" << endl;
break;
case 6:
case 7:
cout << "周末" << endl;
break;
default:
cout << "无效的日期" << endl;
}
break 语句!如果没有 break,程序会继续执行下一个 case 的语句(称为"穿透")。
for 循环适用于已知循环次数的情况:
// 语法
for (初始化; 条件; 更新) {
循环体;
}
// 示例:输出1到10
for (int i = 1; i <= 10; i++) {
cout << i << " ";
}
// 示例:计算1到100的和
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
cout << sum << endl; // 5050
// 范围for循环(C++11)
int arr[] = {1, 2, 3, 4, 5};
for (int x : arr) {
cout << x << " ";
}
while 循环适用于不确定循环次数的情况:
// 语法
while (条件) {
循环体;
}
// 示例:计算1到100的和
int sum = 0, i = 1;
while (i <= 100) {
sum += i;
i++;
}
cout << sum << endl;
// 示例:验证 3x+1 猜想
while (x > 1) {
if (x % 2 == 1) {
x = 3 * x + 1;
} else {
x = x / 2;
}
}
do-while 循环至少执行一次循环体:
// 语法
do {
循环体;
} while (条件); // 注意分号
// 示例:菜单选择
int choice;
do {
cout << "1. 开始游戏" << endl;
cout << "2. 设置" << endl;
cout << "3. 退出" << endl;
cout << "请选择: ";
cin >> choice;
} while (choice != 3);
// break: 退出整个循环
for (int i = 1; i <= 10; i++) {
if (i == 5) break; // 当i等于5时退出循环
cout << i << " ";
}
// 输出: 1 2 3 4
// continue: 跳过本次循环,继续下一次
for (int i = 1; i <= 5; i++) {
if (i == 3) continue; // 跳过i等于3的情况
cout << i << " ";
}
// 输出: 1 2 4 5
函数是一段完成特定任务的代码块,可以被多次调用。使用函数可以:
// 函数声明(原型)
返回类型 函数名(参数列表);
// 函数定义
返回类型 函数名(参数列表) {
函数体;
return 返回值;
}
// 示例
int add(int a, int b); // 声明
int add(int a, int b) { // 定义
return a + b;
}
void printHello() { // 无返回值函数
cout << "Hello!" << endl;
}
int main() {
int result = add(3, 5); // 调用函数
cout << result << endl; // 输出 8
printHello(); // 输出 Hello!
return 0;
}
// 值传递:函数内修改不影响原变量
void swap1(int a, int b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 1, y = 2;
swap1(x, y);
cout << x << " " << y << endl; // 1 2(未交换)
return 0;
}
// 引用传递:函数内修改会影响原变量
void swap2(int &a, int &b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 1, y = 2;
swap2(x, y);
cout << x << " " << y << endl; // 2 1(已交换)
return 0;
}
// 指针传递:传递变量的地址
void swap3(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 1, y = 2;
swap3(&x, &y);
cout << x << " " << y << endl; // 2 1(已交换)
return 0;
}
// 默认参数必须从右向左连续设置
int power(int base, int exp = 2) {
int result = 1;
for (int i = 0; i < exp; i++) {
result *= base;
}
return result;
}
int main() {
cout << power(3) << endl; // 9 (3^2)
cout << power(2, 10) << endl; // 1024 (2^10)
return 0;
}
递归是函数调用自身的过程:
// 阶乘
long long factorial(int n) {
if (n <= 1) return 1; // 递归终止条件
return n * factorial(n - 1); // 递归调用
}
// 斐波那契数列
long long fib(int n) {
if (n <= 2) return 1;
return fib(n - 1) + fib(n - 2);
}
// 求和 1+2+...+n
int sum(int n) {
if (n == 1) return 1;
return n + sum(n - 1);
}
int main() {
cout << factorial(5) << endl; // 120
cout << fib(10) << endl; // 55
cout << sum(100) << endl; // 5050
return 0;
}
结构体(struct)是用户自定义的数据类型,可以将多个不同类型的数据组合在一起。
// 定义结构体
struct Student {
string name;
int age;
double score;
}; // 注意分号
// 创建结构体变量
int main() {
// 方式1:先声明后赋值
Student stu1;
stu1.name = "小明";
stu1.age = 15;
stu1.score = 95.5;
// 方式2:声明时初始化
Student stu2 = {"小红", 16, 98.0};
// 方式3:C++11统一初始化
Student stu3{"小刚", 14, 88.5};
// 访问成员
cout << stu1.name << " " << stu1.age << " " << stu1.score << endl;
return 0;
}
#include <iostream>
#include <string>
using namespace std;
struct Student {
string name;
int score;
};
int main() {
Student class1[3] = {
{"小明", 90},
{"小红", 85},
{"小刚", 95}
};
// 遍历结构体数组
for (int i = 0; i < 3; i++) {
cout << class1[i].name << ": " << class1[i].score << endl;
}
return 0;
}
struct Date {
int year;
int month;
int day;
};
struct Person {
string name;
Date birthday; // 嵌套结构体
};
int main() {
Person p;
p.name = "张三";
p.birthday.year = 2000;
p.birthday.month = 5;
p.birthday.day = 15;
cout << p.name << "的生日是: "
<< p.birthday.year << "-"
<< p.birthday.month << "-"
<< p.birthday.day << endl;
return 0;
}
#include <iostream>
#include <algorithm>
using namespace std;
struct Student {
string name;
int score;
};
// 自定义比较函数
bool cmp(Student a, Student b) {
return a.score > b.score; // 按分数降序
}
int main() {
Student stu[3] = {
{"小明", 90},
{"小红", 85},
{"小刚", 95}
};
// 排序
sort(stu, stu + 3, cmp);
// 输出排序结果
for (int i = 0; i < 3; i++) {
cout << stu[i].name << ": " << stu[i].score << endl;
}
return 0;
}
指针是一种特殊的变量,它存储的是另一个变量的内存地址,而不是值本身。
int main() {
int a = 123; // a: 123
int* pa = &a; // pa 指向 a 的地址
*pa = 321; // a: 321(通过指针修改)
}
int main() {
int a[3] = {1, 2, 3};
int* p = a; // p 指向 a[0]
*p = 4; // a: [4, 2, 3]
p = p + 1; // p 指向 a[1]
*p = 5; // a: [4, 5, 3]
p++; // p 指向 a[2]
*p = 6; // a: [4, 5, 6]
}
a[i] 等价于 *(a + i)。
struct ThreeInt {
int a, b, c;
};
int main() {
ThreeInt x{1, 2, 3};
ThreeInt* px = &x;
(*px).a = 4; // x: {4, 2, 3}
px->b = 5; // x: {4, 5, 3}(推荐写法)
}
int* p = nullptr; // C++11 推荐使用 nullptr
if (p == nullptr) {
cout << "p 是空指针" << endl;
}
// 动态分配单个对象
int* p = new int(1234);
/* ... */
delete p;
// 动态分配数组
int* arr = new int[100];
/* ... */
delete[] arr;
new 申请的内存必须使用 delete 释放,否则会造成内存泄漏。
引用是变量的别名,对引用的操作就是对原变量的操作。
#include <iostream>
using namespace std;
int main() {
int a = 10;
int& r = a; // r 是 a 的引用
r = 20; // a = 20
cout << a << endl; // 输出 20
return 0;
}
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 1, y = 2;
swap(x, y);
cout << x << " " << y << endl; // 2 1
return 0;
}
int a = 10;
const int& r = a; // const 引用
// r = 20; // 错误:不能通过 const 引用修改值
a = 20; // 正确:可以直接修改原变量
const int a = 0; // a 的类型为 const int
// a = 1; // 错误,不能修改常量
int a = 0;
const int b = 0;
int* p1 = &a;
*p1 = 1; // 正确
const int* p2 = &a;
// *p2 = 2; // 错误,不能通过常指针修改
// int* p3 = &b; // 错误,不能用普通指针指向 const 变量
const int* p4 = &b; // 正确
constexpr 声明的变量或函数可以在编译时求值:
constexpr int a = 10; // 直接定义常量
constexpr int FivePlus(int x) { return 5 + x; }
void test(const int x) {
// std::array<x> c1; // 错误,x在编译期不可知
std::array<FivePlus(6)> c2; // 可行,FivePlus编译期可以推断
}
扫码添加微信客服 (加好友时请备注:小码豆)