第一章:C++ 基础篇 —— 从零走通一个 C++ 程序

学习来源:LearnCpp — Chapter 1
整理目的:以更精炼、更适合复习和分享的方式,梳理 C++ 最基础但又最关键的一章。


0. 本章脉络(先看全景)

第一章其实回答了一个问题:

一段 C++ 代码,是怎么从“字符”变成“会跑起来的程序”的?

围绕这个问题,学完之后你应该能讲清楚这几件事:

  1. C++ 程序由什么组成(语句、函数、main
  2. 用什么方式给电脑“存数据”(对象、变量、数据类型)
  3. 怎么把值放进变量里(初始化 vs 赋值)
  4. 怎么和用户交互(std::cin / std::cout
  5. 什么是表达式、什么是运算符、什么是副作用
  6. 为什么“未初始化的变量”是灾难,什么是未定义行为
  7. 写代码时的命名与格式规范
  8. 用一个完整小程序把上面全部串起来

下面按这个顺序展开。


1. 程序结构:语句、函数与 main

C++ 程序 = 一堆按顺序执行的语句 + 把语句组织起来的函数

  • 语句(statement):C++ 中最小的独立“做事单位”,大多数以 ; 结尾。
  • 函数(function):一组按顺序执行的语句集合,用于完成某个具体任务。
  • main 函数:每个 C++ 程序必须有且仅有一个 main(),程序从这里开始执行、到这里结束。

一个最小的 C++ 程序:

#include <iostream>

int main()
{
std::cout << "Hello, C++!\n";
return 0;
}

关键要素拆解:

元素 含义
#include <iostream> 预处理指令,引入输入输出库
int main() 定义 main 函数,返回值类型是 int
{ ... } 函数体,中间的所有语句属于 main
std::cout << ... 向控制台输出
return 0; 告诉操作系统“程序正常结束”

一句话记忆:C++ 程序是 “从 main 开始,按语句顺序执行” 的。


2. 数据、值与字面量

程序做事的本质,是操作数据

  • 值(value):程序处理的一份单独的数据。
  • 字面量(literal)直接写在源码里的值,例如 53.14'A'"Hello"

三种最常见的字面量:

42        // 数字:不加引号
'A' // 字符:单引号,只能一个字符
"Hello" // 字符串:双引号,可含 0 到多个字符

⚠️ 易错点

  • 'A' 是字符(1 个字符),"A" 是字符串(含 1 个字符 + 结尾)。
  • 字符串必须用双引号,字符必须用单引号,写错会直接编译报错。

字面量的最大特点是只读、固定不变,因此单靠字面量没法保存中间结果,我们需要变量


3. 对象与变量

计算机的运行内存叫做 RAM,可以理解为一排编号的“小格子”。

C++ 中我们不直接操作内存地址,而是通过 对象(object) 来间接访问。

  • 对象:一块能存值的内存区域。
  • 变量(variable)有名字的对象

也就是说:

变量 = 有标识符的对象;对象是内存的抽象,变量是给对象起了个名字。

变量定义语法:

int age;      // 定义一个 int 类型的变量 age
double pi; // 定义一个 double 类型的变量 pi

每个变量都有三个基本属性:

  1. 标识符(名字):如 age
  2. 类型:如 intdouble
  3. :定义完可能是垃圾值,也可能被初始化过

C++ 中一个对象的类型必须在编译期就已知,且不能中途改变类型(这是它与 Python 等动态语言的巨大区别)。

最佳实践:一行一个变量定义,配注释说明用途。

int score {};    // 玩家当前分数
int hp {}; // 玩家当前血量

4. 赋值 vs 初始化

这是新手最容易混淆的一对概念。

赋值(assignment)

变量已经存在,再用 = 给它一个值:

int x;
x = 5; // 赋值:把 5 拷贝进 x
x = 7; // 覆盖旧值

初始化(initialization)

变量诞生时就给它一个值:

int a = 5;    // 拷贝初始化
int b(5); // 直接初始化
int c{ 5 }; // 直接列表初始化(推荐)
int d{}; // 值初始化(默认为 0)

五种初始化形式一览

int x;         // 默认初始化:可能是垃圾值 ❌
int a = 5; // 拷贝初始化
int b(5); // 直接初始化
int c{5}; // 直接列表初始化 ✅ 推荐
int d{}; // 值初始化(等价于 0)✅ 推荐

为什么强推 {}

它会禁止“窄化转换”,防止你把大值悄悄塞进小类型:

int w1 { 4.5 }; // ❌ 编译错误:小数塞不进 int
int w2 = 4.5; // ⚠️ 静悄悄丢掉 .5,w2 变成 4
int w3(4.5); // ⚠️ 同样丢掉 .5

一句话记忆看到 {},就是列表初始化,遇错早发现。

什么时候用 {0} vs {}

场景 建议
会立刻用这个初始值 int x{0};
马上就要被 cin 覆盖 int x{}; 更简洁

5. 输入输出:std::cinstd::cout

C++ 标准库通过 <iostream> 提供最基础的 IO:

#include <iostream>

int main()
{
int age{};
std::cout << "请输入年龄:";
std::cin >> age;
std::cout << "你输入的是:" << age << '\n';
return 0;
}

记忆口诀

  • std::cin / std::cout 永远在运算符左边
  • <<cout,表示数据往控制台流
  • >>cin,表示数据从键盘流进变量

换行:优先使用 '\n' 而不是 std::endl

写法 是否换行 是否刷新缓冲区 性能
'\n' 快 ✅
std::endl

日常输出优先 '\n',除非你明确需要立即 flush 缓冲区。

cin 是有缓冲的

比如:

int x, y;
std::cin >> x >> y; // 输入 "3 5",会依次读到 x=3, y=5
  • 输入的字符先进入输入缓冲区
  • >>跳过前导空白,然后读到不合法字符为止
  • 回车符 \n 也会留在缓冲区里,后面读字符/字符串时容易踩坑

6. 未初始化变量与未定义行为(UB)

C++ 不会自动把变量清零,未初始化的变量里是内存里残留的垃圾值

int x;                 // 未初始化
std::cout << x; // ❌ 未定义行为,可能输出任何东西

什么是未定义行为(Undefined Behavior,UB)

C++ 标准没有规定“这么写会发生什么”,因此任何结果都可能出现:

  • 每次运行结果不同
  • 每次都错但错得一样
  • 换个编译器就崩
  • 表面能跑,几个月后突然出 bug

⚠️ 重要认知

“我这么写了,程序还能跑” ≠ “这样写没问题”。
那多半只是 UB 恰好 给了你想要的结果。

铁律

永远初始化变量。{} 兜底就够了:

int score{};   // 就算什么都不填,也是 0,绝不留 UB

7. 表达式与运算符

表达式(expression)

一段能计算出一个值的代码组合,可以由字面量、变量、运算符、函数调用构成:

2 + 3          // → 5
x // → x 的当前值
2 * (x + 1) // → 计算结果
five() // → 函数返回值

表达式本身没有分号,加上分号才变成表达式语句

x = 5;         // 表达式语句

运算符(operator)与元数

元数 说明 例子
一元 1 个操作数 -x
二元 2 个操作数 a + b
三元 3 个操作数 a ? b : c
零元 0 个操作数 throw

运算符优先级:与数学一致

PEMDAS:括号 → 指数 → 乘除 → 加减。

副作用(side effect)

如果一个运算符除了返回值,还留下可观察的改变,那它就有副作用:

  • x = 5:副作用是“x 变成了 5”
  • std::cout << x:副作用是“屏幕上出现了 x 的值”

=<<返回左操作数,所以可以链式:

x = y = 5;                          // 等价于 x = (y = 5)
std::cout << "a" << "b" << "c"; // 从左到右依次输出

8. 关键字、命名与代码风格

关键字(Keywords)

C++ 保留了 92 个关键字(如 intreturnclassifelse)。标识符不能与关键字重名

命名规则(硬性)

  1. 只能由字母、数字、下划线组成
  2. 不能以数字开头
  3. 区分大小写ageAge 不是一个东西
  4. 不能是关键字

命名习惯(软性)

类型 建议
变量 / 函数 小写字母开头:agegetScore()
类 / 结构体 大写字母开头:StudentVector3
多单词 snake_casecamelCase,本教程用 camelCase
不要以下划线开头 _count 通常被系统保留

名字要“有含义”

❌ 不推荐 ✅ 推荐
int d; int daysElapsed;
int data; int studentCount;
int time; int elapsedSeconds;

经验法则用得越广、含义越具体,名字就该越长。


9. 代码格式规范(简版)

C++ 是空白无关语言,怎么排都能编译,但可读性差异巨大

  • 缩进:4 个空格
  • 大括号:本教程使用换行风格
int main()
{
// 语句
}
  • 每行不要超过 80 字符
  • 长语句换行时,把运算符放到下一行行首
  • 用空行分块,用对齐让代码整齐
  • 善用 IDE 的“格式化文档”快捷键

10. 实战:把学过的东西串起来

需求:让用户输入一个整数,输出它的 2 倍。

步骤化开发(这是最重要的思维方式)

新手最爱一次性把整个程序写完 → 出一堆错。正确姿势是:一次加一小块,编译一次,运行一次。

三种写法对比

// ❌ 写法一:覆盖原始输入
num = num * 2;
std::cout << "Double: " << num << '\n';

// ⚠️ 写法二:多一个临时变量
int doubled{ num * 2 };
std::cout << "Double: " << doubled << '\n';

// ✅ 写法三:在需要用的地方直接算
std::cout << "Double: " << num * 2 << '\n';

参考实现

#include <iostream>

int main()
{
std::cout << "Enter an integer: ";

int num{};
std::cin >> num;

std::cout << "Double that number is: " << num * 2 << '\n';
return 0;
}

运行示例:

Enter an integer: 4
Double that number is: 8

11. 本章重点回顾(面试 / 复试速记版)

# 关键问题 一句话答案
1 每个 C++ 程序必须有什么? main 函数
2 语句一般以什么结尾? ;
3 什么是变量? 有名字的对象,代表一块可存值的内存
4 变量类型什么时候确定? 编译期
5 赋值和初始化有什么区别? 初始化:诞生时给值;赋值:诞生之后再给值
6 推荐的初始化写法? 列表初始化 int x{5}; / int x{};
7 列表初始化的好处? 一致、清晰、禁止窄化转换
8 未初始化变量为什么危险? 会产生 未定义行为(UB)
9 换行推荐 \n 还是 endl 优先 \nendl 会 flush 缓冲区
10 cincout 对应的运算符? cin >>cout <<
11 什么是表达式? 能求值出一个值的代码组合
12 什么是副作用? 除返回值外可被观察到的变化,如赋值、输出

12. 学习心得

学完第一章我最大的三个感受:

  1. C++ 的“简单”其实并不简单。
    一个 int x{}; 背后就藏着编译期、类型系统、初始化规则、UB 等一整套机制。
  2. 一次只做一点点,是新手最重要的能力。
    我原本以为“写代码”是坐下来一次写完。实际上是:加一点 → 编译 → 运行 → 再加一点
  3. 看得懂 ≠ 会写。
    看懂 std::cin >> x 只需要 3 秒,自己写出来能编译通过,是完全不同的两件事。

    所以从今天起,每学一个知识点,我都会自己敲 2~3 个小例子

下一章我打算学习 函数、多文件工程、命名空间与前置声明,把“程序的组织方式”这条主线接上。


代码仓库cpp-learning-journey
学习网站learnCPP