Faker :: Lost
REALITY IS FAKE
0%

C++ Primer Plus 学习笔记 - 第2章 开始学习 C++

预计阅读 13 分钟

本章概览

Why This Matters: 第 2 章是从理论到实践的桥梁。理解程序的基本结构、如何与用户交互(I/O)、如何组织代码(函数),是编写任何 C++ 程序的前提。

前置知识: 学习本章前,建议先掌握第 1 章的 C++ 发展历史和编程范式基础。

核心目标

  • 理解 C++ 程序的基本构成(预处理器、main 函数、语句)
  • 掌握输入输出系统(cout/cin
  • 学会声明和使用函数
C++ 程序结构:
├── 预处理器指令 (#include)
│   └── 引入标准库头文件
│
├── main() 函数
│   ├── 程序执行入口
│   ├── 返回值类型必须是 int
│   └── 函数体 { ... }
│
├── 语句 (Statements)
│   ├── 变量声明与赋值
│   ├── 输入输出 (cin/cout)
│   └── 函数调用
│
└── 自定义函数
    ├── 函数原型 (Prototype)
    └── 函数定义 (Definition)

一、基础知识讲解 (Core Concepts)

1.1 第一个 C++ 程序

// 完整示例 - 可直接编译运行
#include <iostream>          // 预处理器指令:引入 I/O 库

int main()                   // 主函数:程序执行入口
{
    using namespace std;     // 使用标准名称空间
    cout << "Hello World!";  // 输出语句
    cout << endl;            // 换行
    return 0;                // 返回 0 表示程序正常结束
}

程序执行流程

  1. 预处理器将 iostream 的内容插入程序
  2. 编译器编译代码
  3. 操作系统调用 main() 函数
  4. 执行函数体内的语句
  5. return 0 结束程序

1.2 main() 函数

main() 是程序的唯一入口,操作系统通过调用它来启动程序。

int main()
{
    // 函数体
    return 0;  // 返回 0 表示成功
}

关键点

  • 返回值类型必须是 int
  • 如果不写 return 0;,编译器会自动补上(仅限 main 函数)
  • 返回值传递给操作系统(0 = 成功,非 0 = 错误)

1.3 预处理器指令 (#include)

#include 告诉预处理器将指定文件的内容插入到当前位置。

#include <iostream>   // 系统头文件,用尖括号
#include "myheader.h" // 自定义头文件,用双引号

常用标准库头文件

头文件 功能
<iostream> 输入输出流(cin/cout
<string> 字符串类
<vector> 动态数组
<cmath> 数学函数(sqrt/pow 等)

1.4 名称空间 (Namespace)

名称空间用于避免大型项目中的名称冲突。

// 方式 1:使用整个 std 名称空间(简单但不推荐用于大型项目)
using namespace std;
cout << "Hello";

// 方式 2:使用特定名称(推荐)
using std::cout;
using std::endl;
cout << "Hello" << endl;

// 方式 3:每次都加前缀(最安全)
std::cout << "Hello" << std::endl;

最佳实践:在小型学习项目中可以用 using namespace std;,但在大型项目中应避免,以防止名称冲突。

1.5 输出:cout

cout(console output)用于向屏幕输出内容。

#include <iostream>
using namespace std;

int main() {
    cout << "我有 ";
    cout << 25;
    cout << " 根胡萝卜。";
    cout << endl;  // 换行
    
    // 可以链式调用
    cout << "我有 " << 25 << " 根胡萝卜。" << endl;
    
    return 0;
}

输出

我有 25 根胡萝卜。

endl vs \n

  • endl:换行 + 刷新缓冲区
  • \n:仅换行(更高效)

1.6 输入:cin

cin(console input)用于从键盘读取输入。

#include <iostream>
using namespace std;

int main() {
    int carrots;
    cout << "你有多少根胡萝卜?";
    cin >> carrots;  // 读取用户输入
    cout << "你有 " << carrots << " 根胡萝卜。" << endl;
    return 0;
}

运行示例

你有多少根胡萝卜?25
你有 25 根胡萝卜。

1.7 变量声明与赋值

C++ 是强类型语言,使用变量前必须声明类型。

int carrots;        // 声明
carrots = 25;       // 赋值

int apples = 10;    // 声明 + 初始化(推荐)

1.8 函数的使用

使用标准库函数

#include <cmath>
#include <iostream>
using namespace std;

int main() {
    double x = sqrt(6.25);  // 调用 sqrt 函数
    cout << "6.25 的平方根是 " << x << endl;  // 2.5
    return 0;
}

自定义函数

函数包含三个部分:原型、调用、定义

#include <iostream>
using namespace std;

// 1. 函数原型(声明)
void Simon(int);

int main() {
    // 2. 函数调用
    Simon(3);
    return 0;
}

// 3. 函数定义
void Simon(int n) {
    cout << "Simon says touch your toes " << n << " times." << endl;
}

输出

Simon says touch your toes 3 times.

为什么需要函数原型?

  • 告诉编译器函数的参数类型和返回值类型
  • 允许在定义之前调用函数
  • 提高代码可读性

二、进阶应用 (Modern C++ Practice)

2.1 用 auto 简化类型声明 (C++11)

// 传统写法
double x = sqrt(6.25);

// 现代写法
auto x = sqrt(6.25);  // 编译器自动推导为 double

2.2 用范围 for 循环输出 (C++11)

#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> nums = {1, 2, 3, 4, 5};
    
    // 传统写法
    for (int i = 0; i < nums.size(); i++) {
        cout << nums[i] << " ";
    }
    
    // 现代写法(更简洁)
    for (auto num : nums) {
        cout << num << " ";
    }
    
    return 0;
}

2.3 用 nullptr 代替 NULL (C++11)

// 传统写法
int *p = NULL;

// 现代写法
int *p = nullptr;  // 类型安全的空指针

2.4 用 constexpr 定义编译期常量 (C++11)

// 传统 const
const int SIZE = 100;

// 现代 constexpr(保证编译期计算)
constexpr int SIZE = 100;
constexpr double PI = 3.14159;

三、工程陷阱与避坑指南 (Engineering Pitfalls)

3.1 忘记 using namespace stdstd::

现象:编译错误 'cout' was not declared in this scope原因coutcinstd 名称空间中,必须显式指定。

#include <iostream>

int main() {
    cout << "Hello";  // ❌ 编译错误!
    return 0;
}

解决方案

// 方案 1
using namespace std;
cout << "Hello";

// 方案 2
std::cout << "Hello";

3.2 忘记 #include <iostream>

现象:编译错误 'cout' was not declared原因coutcin 定义在 iostream 头文件中。

int main() {
    std::cout << "Hello";  // ❌ 编译错误!
    return 0;
}

解决方案

#include <iostream>  // ✅ 必须包含

3.3 cin 输入类型不匹配

现象:程序行为异常,输入被跳过。 原因cin 期望读取整数,但用户输入了字符串。

int age;
cout << "请输入年龄:";
cin >> age;  // 用户输入 "abc",cin 失败

解决方案:检查输入状态。

if (cin >> age) {
    cout << "年龄:" << age << endl;
} else {
    cout << "输入无效!" << endl;
    cin.clear();  // 清除错误标志
    cin.ignore(1000, '\n');  // 清空缓冲区
}

3.4 函数原型与定义不匹配

现象:链接错误或编译错误。 原因:函数原型的参数类型与定义不一致。

void foo(int);  // 原型

void foo(double x) {  // ❌ 定义参数类型不匹配
    // ...
}

解决方案:确保原型和定义完全一致。

void foo(int);  // 原型

void foo(int x) {  // ✅ 匹配
    // ...
}

四、面试高频考点 (Interview Focus)

Q1: main() 函数的返回值有什么作用?

main() 的返回值传递给操作系统,表示程序的退出状态:

  • return 0;:程序正常结束
  • return 非0;:程序异常结束(错误码)

在 Shell 脚本中可以通过 $?(Linux)或 %ERRORLEVEL%(Windows)获取这个返回值。

Q2: using namespace std; 有什么潜在问题?

:在大型项目中,using namespace std; 可能导致名称冲突。例如,如果你定义了一个名为 count 的变量,它可能与 std::count 冲突。

最佳实践

  • 小型学习项目:可以使用 using namespace std;
  • 大型项目:使用 std:: 前缀或 using std::cout; 等特定声明

Q3: endl\n 有什么区别?

  • endl:换行 + 刷新缓冲区(强制立即输出)
  • \n:仅换行(不刷新缓冲区,更高效)

在性能敏感的场景(如大量输出),优先使用 \n


五、总结与回顾 (Summary & Review)

核心记忆点

  1. 程序结构#includemain(){ 语句 }
  2. I/O 系统cout << 输出,cin >> 输入
  3. 名称空间using namespace std;std:: 前缀
  4. 变量:先声明类型,再赋值
  5. 函数:原型(声明)→ 调用 → 定义
  6. main() 返回值:0 = 成功,非 0 = 错误

C++ 程序基本框架

#include <iostream>
using namespace std;

int main() {
    // 变量声明
    int x = 10;
    
    // 输出
    cout << "x = " << x << endl;
    
    // 输入
    cin >> x;
    
    // 函数调用
    // ...
    
    return 0;
}

下一章预告:第 3 章将深入探讨 C++ 的数据类型系统——整型、浮点型、字符型、布尔型,以及类型转换的规则!

💬 评论区

感谢阅读!如有任何问题或建议,欢迎交流。