2. 基本语法与数据类型:变量、常量、基本数据类型、类型转换、auto关键字
好,咱们正式开始接触C++的“血肉”。
上一章我们把环境搭好了,也跑通了第一个程序。但说实话,那个程序除了打印一句话,啥也干不了。真正的程序,是要处理数据的——数字、文字、开关状态,这些东西在C++里怎么表示?怎么存?怎么变?
这一章,我们就来把这些基础打牢。
2.1 变量:给数据起个名字
变量,说白了就是一块内存空间,我们给它起了个名字。你可以把它想象成一个带标签的盒子。盒子里能放什么东西,取决于盒子的类型。
#include <iostream>
int main() {
int age = 25; // 一个叫age的盒子,里面放整数25
double price = 19.99; // 一个叫price的盒子,里面放小数
char grade = 'A'; // 一个叫grade的盒子,里面放一个字符
return 0;
}
我个人习惯,变量名一定要见名知意。别用 a、b、c 这种名字。你想想看,三个月后回头看代码,看到 int a = 5;,你还能记得这个 a 是干嘛的吗?
- 变量名只能包含字母、数字、下划线
- 不能以数字开头
- 不能是C++关键字(比如
int、return) - 推荐用驼峰命名法:
studentAge、totalScore
2.2 常量:不变的值
有些数据,一旦确定就不该被修改。比如圆周率3.14159,或者程序里定义的最大人数。
C++里定义常量有两种方式:
// 方式一:const 关键字(推荐)
const double PI = 3.14159;
const int MAX_STUDENTS = 100;
// 方式二:#define 宏定义(C语言风格,不推荐)
#define MAX_SIZE 1024
我建议你优先用 const。为什么?因为 const 有类型检查,编译器能帮你发现错误。而 #define 只是简单的文本替换,出了问题很难排查。我曾经在一个项目里看到有人用 #define 定义了一个常量,结果因为宏展开的优先级问题,导致计算结果完全不对……嗯,从那以后我再也不用 #define 定义常量了。
2.3 基本数据类型
C++里最常用的四种基本类型,我列个表给你看:
| 类型 | 关键字 | 占用空间 | 取值范围 | 示例 |
|---|---|---|---|---|
| 整型 | int |
4字节 | -21亿 ~ 21亿 | int count = 10; |
| 浮点型 | float |
4字节 | 约 ±3.4e38 | float pi = 3.14f; |
| 双精度浮点 | double |
8字节 | 约 ±1.8e308 | double price = 99.99; |
| 字符型 | char |
1字节 | -128 ~ 127 | char ch = 'A'; |
| 布尔型 | bool |
1字节 | true / false | bool isOK = true; |
写 float 类型时,数值后面要加 f 后缀。比如 3.14f。不加的话,编译器默认当成 double,可能会产生精度警告。我刚开始学的时候就踩过这个坑。
2.4 类型转换
实际开发中,不同类型的数据经常需要混着用。比如整数和浮点数做运算,或者把字符转成整数。
C++里类型转换分两种:
2.4.1 隐式类型转换(自动转)
int a = 10;
double b = a; // int 自动转成 double,没问题
// 结果是 10.0
double x = 3.14;
int y = x; // double 转 int,小数部分被截断!
// 结果是 3,不是 3.14
看到了吗?隐式转换虽然方便,但可能会丢失精度。从 double 转 int,小数点后面的东西就没了。这个要特别小心。
2.4.2 显式类型转换(强制转)
如果你明确知道自己在做什么,可以用强制转换:
double pi = 3.14159;
int intPi = (int)pi; // C风格:直接在前面加括号写类型
int intPi2 = static_cast<int>(pi); // C++风格:推荐用这个
我个人强烈推荐用 static_cast。为什么?因为C风格的强制转换太“暴力”了,什么都能转,容易掩盖真正的错误。而 static_cast 至少会做基本的类型检查,更安全。
我曾经在项目里看到有人用 (int*) 把一个 float 的地址强行转成 int* 来读取数据。结果因为浮点数和整数的内存表示完全不同,读出来的数值完全不对。这种“骚操作”千万别学。
2.5 auto关键字:让编译器帮你推类型
C++11 引入了 auto 关键字。它的作用是让编译器根据初始值自动推导变量类型。
auto age = 25; // 编译器推导出 int
auto price = 19.99; // 推导出 double
auto grade = 'A'; // 推导出 char
auto isPass = true; // 推导出 bool
你可能会问:这有什么用?我直接写 int 不就行了?
嗯,在简单场景下确实区别不大。但当你遇到复杂的类型时——比如迭代器、lambda表达式——auto 能省下大量打字时间,而且让代码更清晰。
// 没有 auto 的时候
std::vector<int>::iterator it = vec.begin();
// 有了 auto 之后
auto it = vec.begin(); // 简洁多了
不过要注意,auto 必须在定义时初始化。你不能写 auto x; 然后后面再赋值——编译器不知道它是什么类型。
对于简单类型(int、double、char),我一般直接写类型名,因为一眼就能看出是什么。但对于复杂类型(迭代器、模板类型),我会用 auto,让代码更简洁。说白了,auto 是个好工具,但别滥用。
知识体系总览
这一章的内容比较多,我画了一张图帮你理清关系:
这一章的内容,说白了就是C++的“砖瓦”。变量和常量是存数据的容器,基本类型决定了容器能装什么,类型转换让你能在不同容器间倒腾数据,而 auto 则是帮你偷懒的利器。
把这些基础打牢了,后面学函数、类、指针的时候,你才不会觉得吃力。嗯,下一章我们就要开始玩“运算符”了——加减乘除、逻辑判断,让程序真正动起来。
公众号:蓝海资料掘金营,微信deep3321