第2章 开始学习C++
环境搭建
编译器选择
C++是一种编译型语言,需要使用编译器将源代码转换为可执行文件。以下是一些常用的C++编译器:
1. GCC (GNU Compiler Collection)
- 适用平台:Windows、Linux、macOS
- 特点:开源、免费、支持最新的C++标准
- 安装方法:
- Linux:通过包管理器安装(如
apt install g++) - Windows:安装MinGW或MSYS2
- macOS:安装Xcode命令行工具或Homebrew
2. Clang
- 适用平台:Windows、Linux、macOS
- 特点:开源、免费、错误信息友好、编译速度快
- 安装方法:
- Linux:通过包管理器安装(如
apt install clang) - Windows:安装LLVM
- macOS:默认包含在Xcode命令行工具中
3. MSVC (Microsoft Visual C++)
- 适用平台:Windows
- 特点:与Windows平台集成良好、支持最新的C++标准
- 安装方法:安装Visual Studio或Visual Studio Build Tools
4. 其他编译器
- Intel C++ Compiler:针对Intel处理器优化
- Embarcadero C++ Builder:集成开发环境
- Oracle Solaris Studio:针对Solaris平台
集成开发环境(IDE)
使用IDE可以提高开发效率,以下是一些常用的C++ IDE:
1. Visual Studio
- 适用平台:Windows
- 特点:功能强大、集成调试器、代码编辑器、项目管理
- 版本:Community(免费)、Professional、Enterprise
2. Visual Studio Code
- 适用平台:Windows、Linux、macOS
- 特点:轻量级、可扩展、支持多种语言
- 插件:C/C++、C++ Intellisense、Code Runner等
3. CLion
- 适用平台:Windows、Linux、macOS
- 特点:专为C++设计、智能代码补全、重构工具
- 价格:付费,学生可免费使用
4. Eclipse CDT
- 适用平台:Windows、Linux、macOS
- 特点:开源、可扩展、支持多种语言
5. Code::Blocks
- 适用平台:Windows、Linux、macOS
- 特点:开源、轻量级、跨平台
第一个C++程序
让我们创建一个简单的C++程序,输出”Hello, C++!”。
1. 使用文本编辑器
在任意文本编辑器中创建一个名为hello.cpp的文件,输入以下代码:
1 2 3 4 5 6
| #include <iostream>
int main() { std::cout << "Hello, C++!" << std::endl; return 0; }
|
2. 编译和运行
使用GCC编译
1 2 3
| g++ hello.cpp -o hello ./hello hello.exe
|
使用Clang编译
1 2 3
| clang++ hello.cpp -o hello ./hello hello.exe
|
使用MSVC编译
3. 程序解析
1 2 3 4 5 6
| #include <iostream>
int main() { std::cout << "Hello, C++!" << std::endl; return 0; }
|
#include <iostream>:预处理器指令,包含标准输入/输出流库int main():主函数,每个C++程序都必须有一个主函数std::cout:标准输出流对象,用于输出数据<<:插入运算符,将右侧的数据插入到左侧的流中std::endl:换行符,同时刷新输出缓冲区return 0:主函数返回值,0表示成功
4. 现代C++特性示例
4.1 使用auto关键字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #include <iostream> #include <vector>
int main() { auto number = 42; auto pi = 3.14159; auto message = "Hello, Modern C++!"; std::vector<int> numbers = {1, 2, 3, 4, 5}; for (auto num : numbers) { std::cout << num << " "; } std::cout << std::endl; return 0; }
|
4.2 使用lambda表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include <iostream> #include <vector> #include <algorithm>
int main() { std::vector<int> numbers = {5, 2, 8, 1, 9}; std::sort(numbers.begin(), numbers.end(), [](int a, int b) { return a < b; }); for_each(numbers.begin(), numbers.end(), [](int num) { std::cout << num << " "; }); std::cout << std::endl; return 0; }
|
4.3 使用智能指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include <iostream> #include <memory>
class MyClass { public: MyClass() { std::cout << "MyClass constructed" << std::endl; } ~MyClass() { std::cout << "MyClass destructed" << std::endl; } void doSomething() { std::cout << "Doing something" << std::endl; } };
int main() { std::unique_ptr<MyClass> ptr1 = std::make_unique<MyClass>(); ptr1->doSomething(); std::shared_ptr<MyClass> ptr2 = std::make_shared<MyClass>(); std::shared_ptr<MyClass> ptr3 = ptr2; ptr2->doSomething(); return 0; }
|
4.4 使用标准库容器和算法
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 29 30 31 32
| #include <iostream> #include <vector> #include <algorithm> #include <numeric>
int main() { std::vector<int> numbers = {1, 2, 3, 4, 5}; int sum = std::accumulate(numbers.begin(), numbers.end(), 0); std::cout << "Sum: " << sum << std::endl; auto it = std::find(numbers.begin(), numbers.end(), 3); if (it != numbers.end()) { std::cout << "Found: " << *it << std::endl; } std::vector<int> squared(numbers.size()); std::transform(numbers.begin(), numbers.end(), squared.begin(), [](int x) { return x * x; }); std::cout << "Squared: "; for (auto num : squared) { std::cout << num << " "; } std::cout << std::endl; return 0; }
|
4.5 使用结构化绑定(C++17+)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include <iostream> #include <tuple> #include <string>
int main() { auto [name, age, score] = std::make_tuple("Alice", 25, 95.5); std::cout << "Name: " << name << ", Age: " << age << ", Score: " << score << std::endl; int arr[] = {1, 2, 3}; auto [a, b, c] = arr; std::cout << "a: " << a << ", b: " << b << ", c: " << c << std::endl; return 0; }
|
4.6 使用if constexpr(C++17+)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #include <iostream> #include <type_traits>
template <typename T> void printTypeInfo(T value) { if constexpr (std::is_integral_v<T>) { std::cout << "Integral type: " << value << std::endl; } else if constexpr (std::is_floating_point_v<T>) { std::cout << "Floating point type: " << value << std::endl; } else if constexpr (std::is_same_v<T, std::string>) { std::cout << "String type: " << value << std::endl; } else { std::cout << "Other type" << std::endl; } }
int main() { printTypeInfo(42); printTypeInfo(3.14); printTypeInfo(std::string("Hello")); return 0; }
|
4.7 使用范围库(C++20+)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include <iostream> #include <vector> #include <ranges>
int main() { std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; auto result = numbers | std::views::filter([](int n) { return n % 2 == 0; }) | std::views::transform([](int n) { return n * n; }); std::cout << "Even squares: "; for (auto num : result) { std::cout << num << " "; } std::cout << std::endl; return 0; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #include <iostream> #include <format>
int main() { std::string name = "Alice"; int age = 25; double score = 95.5; std::string message = std::format("Name: {}, Age: {}, Score: {:.2f}", name, age, score); std::cout << message << std::endl; return 0; }
|
C++程序的基本结构
1. 预处理指令
预处理指令以#开头,在编译前由预处理器处理:
1 2 3 4 5
| #include <iostream> #define PI 3.14159 #ifdef DEBUG #endif
|
2. 全局声明
在函数外部声明的变量、函数、类等:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #include <iostream>
int globalVar = 100;
void function();
class MyClass { };
int main() { return 0; }
void function() { }
|
3. 主函数
每个C++程序都必须有一个主函数,是程序的入口点:
1 2 3 4 5 6 7 8 9 10
| int main() { return 0; }
int main(int argc, char* argv[]) { return 0; }
|
4. 函数定义
函数是C++程序的基本组成单位:
1 2 3 4 5 6 7 8 9
| 返回类型 函数名(参数列表) { return 返回值; }
int add(int a, int b) { return a + b; }
|
5. 注释
C++支持两种注释方式:
C++的基本语法
1. 变量和常量
变量声明和初始化
1 2 3 4 5 6 7 8
| int age; age = 25;
int score = 95;
int value{100}; int number = {50};
|
常量
1 2 3 4 5
| const int MAX_AGE = 120;
constexpr int MIN_AGE = 0;
#define PI 3.14159
|
2. 数据类型
基本数据类型
| 类型 | 大小(字节) | 范围 |
|---|
| bool | 1 | true/false |
| char | 1 | -128 到 127 |
| unsigned char | 1 | 0 到 255 |
| short | 2 | -32768 到 32767 |
| unsigned short | 2 | 0 到 65535 |
| int | 4 | -2147483648 到 2147483647 |
| unsigned int | 4 | 0 到 4294967295 |
| long | 4 或 8 | 取决于平台 |
| unsigned long | 4 或 8 | 取决于平台 |
| long long | 8 | -9223372036854775808 到 9223372036854775807 |
| unsigned long long | 8 | 0 到 18446744073709551615 |
| float | 4 | 约±3.4e38 |
| double | 8 | 约±1.7e308 |
| long double | 8 或 16 | 取决于平台 |
类型修饰符
signed:有符号类型(默认)unsigned:无符号类型short:短整型long:长整型long long:更长的整型(C++11+)
类型转换
1 2 3 4 5 6 7 8
| int i = 100; double d = i;
double pi = 3.14159; int intPi = static_cast<int>(pi); int oldStylePi = (int)pi;
|
3. 运算符
算术运算符
| 运算符 | 描述 | 示例 |
|---|
| + | 加法 | a + b |
| - | 减法 | a - b |
| * | 乘法 | a * b |
| / | 除法 | a / b |
| % | 取模(余数) | a % b |
| ++ | 自增 | a++ 或 ++a |
| – | 自减 | a– 或 –a |
关系运算符
| 运算符 | 描述 | 示例 |
|---|
| == | 等于 | a == b |
| != | 不等于 | a != b |
| > | 大于 | a > b |
| < | 小于 | a < b |
| >= | 大于等于 | a >= b |
| <= | 小于等于 | a <= b |
逻辑运算符
| 运算符 | 描述 | 示例 |
|---|
| && | 逻辑与 | a && b |
| || | 逻辑或 | a || b |
| ! | 逻辑非 | !a |
赋值运算符
| 运算符 | 描述 | 示例 |
|---|
| = | 简单赋值 | a = b |
| += | 加后赋值 | a += b |
| -= | 减后赋值 | a -= b |
| *= | 乘后赋值 | a *= b |
| /= | 除后赋值 | a /= b |
| %= | 取模后赋值 | a %= b |
其他运算符
| 运算符 | 描述 | 示例 |
|---|
| sizeof | 计算大小 | sizeof(int) |
| & | 取地址 | &a |
| * | 解引用 | *p |
| ? : | 条件运算符 | a > b ? a : b |
| . | 成员访问 | obj.member |
| -> | 指针成员访问 | ptr->member |
4. 控制语句
条件语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| if (condition) { } else if (anotherCondition) { } else { }
switch (expression) { case value1: break; case value2: break; default: break; }
|
循环语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| for (initialization; condition; update) { }
while (condition) { }
do { } while (condition);
for (auto element : collection) { }
|
跳转语句
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
| for (int i = 0; i < 10; i++) { if (i == 5) { break; } }
for (int i = 0; i < 10; i++) { if (i % 2 == 0) { continue; } }
int add(int a, int b) { return a + b; }
if (error) { goto errorHandler; }
errorHandler:
|
输入和输出
标准输入输出
C++使用iostream库进行输入输出操作:
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
| #include <iostream>
int main() { std::cout << "Hello, " << "world!" << std::endl; int age; std::cout << "Enter your age: "; std::cin >> age; std::cout << "Your age is: " << age << std::endl; std::string name; std::cout << "Enter your name: "; std::cin >> name; std::cout << "Your name is: " << name << std::endl; std::string line; std::cout << "Enter a line: "; std::cin.ignore(); std::getline(std::cin, line); std::cout << "You entered: " << line << std::endl; return 0; }
|
格式化输出
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 29
| #include <iostream> #include <iomanip>
int main() { std::cout << std::setw(10) << "Hello" << std::endl; std::cout << std::setfill('*') << std::setw(10) << "Hello" << std::endl; double pi = 3.1415926535; std::cout << std::setprecision(5) << pi << std::endl; std::cout << std::scientific << pi << std::endl; int num = 255; std::cout << std::hex << num << std::endl; std::cout << std::oct << num << std::endl; std::cout << std::dec << std::fixed; return 0; }
|
常见错误和调试
常见错误
1. 语法错误
- 缺少分号:语句结束时忘记加分号
- 括号不匹配:大括号、小括号、中括号不匹配
- 变量未声明:使用未声明的变量
- 类型不匹配:将一种类型的值赋给另一种不兼容的类型
- 函数参数不匹配:调用函数时参数数量或类型不正确
2. 运行时错误
- 除以零:尝试除以零
- 数组越界:访问数组范围之外的元素
- 空指针解引用:使用空指针
- 内存泄漏:分配内存后未释放
- 栈溢出:递归深度过大或局部变量过大
3. 逻辑错误
- 算法错误:算法逻辑不正确
- 条件判断错误:条件表达式逻辑错误
- 循环错误:循环条件或循环体逻辑错误
- 变量初始化错误:变量未正确初始化
调试技巧
1. 使用输出语句
1
| std::cout << "Variable value: " << variable << std::endl;
|
2. 使用调试器
- 设置断点:在代码的特定位置设置断点,程序执行到断点时暂停
- 单步执行:逐行执行代码,观察变量变化
- 查看变量:在调试过程中查看变量的值
- 查看调用栈:了解函数调用关系
3. 使用断言
1 2 3 4 5 6
| #include <cassert>
int divide(int a, int b) { assert(b != 0 && "Division by zero"); return a / b; }
|
4. 代码审查
- 仔细检查代码逻辑
- 检查边界条件
- 检查变量初始化
- 检查内存管理
编程规范
1. 命名规范
- 变量和函数:使用小写字母和下划线(snake_case)
- 类和结构体:使用大写字母开头的驼峰命名法(CamelCase)
- 常量:使用全大写字母和下划线(UPPER_CASE)
- 命名空间:使用小写字母
2. 代码格式
- 缩进:使用4个空格或1个制表符进行缩进
- 换行:每行代码长度不宜过长(通常不超过80-100个字符)
- 空格:在运算符两侧、逗号后添加空格
- 空行:在函数之间、逻辑块之间添加空行
3. 注释规范
- 函数注释:描述函数的功能、参数、返回值
- 复杂代码注释:解释复杂的算法或逻辑
- 关键变量注释:解释关键变量的用途
- 修改注释:记录代码修改的原因和时间
4. 最佳实践
- 代码重用:将重复的代码提取为函数
- 模块化:将代码组织为逻辑模块
- 错误处理:适当处理错误情况
- 资源管理:使用RAII(资源获取即初始化)原则管理资源
- 性能优化:避免不必要的计算和内存操作
- 安全性:避免缓冲区溢出、空指针解引用等安全问题
小结
本章介绍了C++编程的基础知识,包括环境搭建、第一个C++程序、基本语法、输入输出、常见错误和调试技巧等内容。通过本章的学习,你应该能够:
- 搭建C++开发环境,选择适合自己的编译器和IDE
- 编写简单的C++程序,理解程序的基本结构
- 掌握C++的基本语法,包括变量、常量、数据类型、运算符、控制语句等
- 使用标准输入输出流进行数据的输入和输出
- 识别和解决常见的编译错误和运行时错误
- 遵循基本的编程规范,编写清晰、可维护的代码
在接下来的章节中,我们将深入学习C++的更多特性,包括数据类型、控制语句、函数、数组、指针、字符串、类和对象等内容。通过系统学习这些内容,你将能够掌握C++的核心概念和编程技巧,为进一步学习高级特性打下坚实基础。
C++是一种强大而灵活的编程语言,学习它需要耐心和实践。通过不断地编写代码、解决问题,你将逐渐掌握C++的精髓,成为一名优秀的C++程序员。