---
title: "变量与类型"
description: "从环境准备到 STL，系统学习 C++ 编程的基础知识。"
---

> Documentation Index
> Fetch the complete documentation index at: https://cppguide.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# 变量与类型

![](https://img.dailyup.xyz/originals/8208463126936-13382443-b082-4ce7-87a3-a1cf46def4d8.png)

## 变量基础

我们在上一章中讲解算术运算时有这样一个例子：

```cpp
#include <iostream>
using namespace std;

int main() {
  cout << 5 + 2 << endl; // 求和
  cout << 5 - 2 << endl; // 求差
  cout << 5 * 2 << endl; // 求积
  cout << 5 / 2 << endl; // 求商
  cout << 5 % 2 << endl; // 求余
  
  return 0;
}
```

可以发现这里都是关于 5 与 2 的运算，如果要改成 8 与 3 的运算呢？就得一个一个把所有的 5 换成 8，2 换成 3，太麻烦了。

如果能够有一种方法，只需要改一次，其它所有地方都自动改了，就方便太多了。

实际上，变量就可以用来解决这个问题，对上面的代码做一些改动，如下所示：

```cpp
int a = 5; // 定义了一个整数变量 a，值为 5
int b = 2; // 定义了一个整数变量 b，值为 2

cout << a + b << endl;
cout << a - b << endl;
cout << a * b << endl;
cout << a / b << endl;
cout << a % b << endl;
```

计算结果不变，但整个程序其实更「好」一些了，如果要将程序改为 8 和 3 的运算，只需要更改一下 a 和 b 就行了。

```cpp
int a = 8;
int b = 3;
```

剩下的都不用换了，这就是使用变量带来的好处。

### 变量定义

**变量（Variable）** 是用于存储数据的一个“容器”，它有一个名字，称为变量名，程序可以通过这个名字访问存储的数据。变量的值可以随着程序的运行而变化，因此被称为“变量”。

![](https://img.dailyup.xyz/optimized/8208463129416-772930c3-6a3c-488c-9690-0027af11759c.png)

上图定义了一个变量，变量的类型为 `int`，表示整数（integer），变量名为 `height`，它的值为 175 。实际应用中，定义这个变量可能是为了表示身高，值为 175 代表 175cm。

需要注意的是，与我们在数学中所学的等式不一样，这里的等号 `=` 并不是判断左右两边的值是否相等，而是赋值操作符号，表示将等号右边的值 `175` 赋值给等号左边的变量 `height` ，经过赋值后，当使用变量 `height` 时，它的值就是 175 了。

> 后面会讲到，在 C++ 中，判断两个数或两个变量是否相等，我们是用两个等号 `==` 来表示的，例如 `height == 175` 表示判断变量 `height` 的值是否等于 175

理解了赋值操作，下面的代码就容易明白是什么意思了。

```cpp
int height = 175;
height = height + 5; 
```

从数学上来看，上面的第 2 行代码是不成立的，而在编程中，第 2 行代码的含义表示：将等号右边的表达式 `height + 5` 结果计算出来，表达式结果是 180，然后把 180 赋值给等号左边的变量 `height`。赋值后，变量 `height` 的值就是 180 了。

### 变量命名

给变量命名，需要遵循一定的原则，

- 变量名只能由**字母**、**数字** 和 **下划线 _** 组成
- 变量名不能以数字开头
- 不能使用语言相关的 **保留关键字**

比如，下面的几组变量名，看看是否合法？

- `3a`，错误命名，变量名不能以数字开头
- `a3`，正确命名
- `max-v`，错误命名，变量名只能由 **字母**、**数字** 和 **下划线 _** 组成
- `max_v`，正确命名
- `_max`，正确命名
- `name&size`，错误命名，变量名中不能包含不允许的特殊字符
- `cout`，错误命名，保留关键字


除此之外，给变量命名时，尽可能有意义，容易识别，也更有利于查错。下面的一些变量名是一些常用的，我们以后会经常用到。

- `i` 或 `j`，通常用于下标编号
- `cnt`，用于计数，`count` 的简写
- `ans`，用于答案，`answer` 的简写
- `rlt`，用于结果，`result` 的简写
- `mx`，最大值，`max` 的简写
- `mn`，最小值，`min` 的简写

### 保留关键字

**保留关键字（Reserved Keywords）** 是 C++ 语言中已经定义好的词，它们有特定的含义和用途，不能用作其他目的（例如变量名、函数名等）。

下面是一些常见的保留关键字。

- 用于表示数据类型的：`int`、 `long`、`float`、`double`、`char`
- 用于条件分支的：`if`、`else`
- 用于循环的：`while`、`for`、`break`、`continue`
- 其它：`return`、`class`、`default`、`const` 等

保留关键字不用刻意去记，没必要，上面列出的这些，大家陆陆续续后面都会学到，自然就知道了。

## 顺序执行

从前面的程序大家应该有发现，**我们编写的程序是按从上到下的顺序依次执行的。这种方式称之为顺序结构（Sqeuence）**。下面是顺序结构的示意流程图。

![](https://img.dailyup.xyz/optimized/8208463126610-b2d37b61-f24b-4c0e-af53-f2c353b84471.png)

就像我们按照说明书去拼乐高，一定是按照说明书中的步骤，按步骤1、步骤2、步骤3 ... 这样的顺序依次去拼搭完成的。顺序结构也是我们在程序中接触到的一种最简单的流程结构。

如果有下面的代码，大家判断一下程序执行的结果应该是什么呢？

```cpp
#include <iostream>
using namespace std;

int main() {
  int a = 5;
  cout << a << endl;
  int b = 3;
  cout << b << endl;
  
  b = a + 2;
  a = b * 5;
  cout << a << endl;
  cout << b << endl;
  
  a = b + a;
  cout << a << endl;
  
  return 0;
}
```

这段代码执行后，最终 `a` 和 `b` 的值分别是多少呢？大家可以自己先判断一下，再动手去写一写，看看运行的结果是什么，是否与自己的判断一致。

## 变量类型

在 C++ 中，每个变量都有指定的类型，而变量的类型决定了变量存储所占用内存空间的大小，而变量的大小也决定了变量所能表示的数据范围。

下表列出了一些常见的变量基础类型及其表示范围，作为参考。

![](https://img.dailyup.xyz/optimized/8208463124712-b7565ad9-055d-4a97-9c87-3e6e94dbfb4c.png)

> 实际上变量的类型比上表中列出的要复杂很多，更多的变量类型及表示范围介绍见附录中的参考资源链接。

正是由于不同变量都有不同的大小及取值范围，我们在解决实际问题时，特别需要注意根据需求来选取不同的变量类型。

比如说，如果题目的输入描述写到：输入一个正整数 $n(1 \le n \le 10^{12})$，那我们在定义变量的时候，就不能选取 `int` 类型，因为 $n$ 的取值范围已经超过 `int` 所能表示的数据范围了，可以选取 `long long` 类型。

## 变量的大小

每种变量类型都有对应的大小，当我们在创建一个变量时，会在内存中申请并开取对应大小的空间。

我们可以通过 `sizeof()` 来查看不同变量类型所占空间的大小。

```cpp
#include <iostream>
using namespace std;

int main() {    
    cout << "char: " << sizeof(char) << " byte" << endl;
    cout << "int: " << sizeof(int) << " bytes" << endl;
    cout << "float: " << sizeof(float) << " bytes" << endl;
    cout << "double: " << sizeof(double) << " bytes" << endl;
    cout << "long long: " << sizeof(long long) << " bytes" << endl;
    cout << "long double: " << sizeof(long double) << " bytes" << endl;
    
    return 0;
}
```

程序运行结果：

```
char: 1 byte
int: 4 bytes
float: 4 bytes
double: 8 bytes
long long: 8 bytes
long double: 16 bytes
```

> 字节（byte）是计算机中的一种计量单位，常于表示存储容量的大小，我们在后面有专门的章节会讲到不同的计量单位以及它们之间的转换关系。

## 变量类型转换

有时候需要对变量的类型进行转换，转换有隐式与显示（强制）转换两种方式。

### 隐式转换

变量的隐式转换是自动进行的，由 C++ 编译器根据类型的兼容性进行推断和自动执行的。**通常来说，转换的目标类型精度比源类型更高一些**。

例如，当把一个整数值（int）赋值给一个浮点数（float）变量时，会发生隐式转换：

```cpp
int a = 10;
float b = a; // 隐式将整数类型转换为浮点数类型
```

再看一个精度丢失的隐式转换例子：

```cpp
int a = 5;
int b = 2;
cout << a / b << endl; // 结果为 2，丢失了精度
```

当两整数类型的数相除时，结果自动保留为整数，按理来说，5 除以 2 应该等于 2.5，但由于结果保留为整数，计算结果的小数部分自动丢掉了，一定要小心这样容易带来的问题。

### 显式转换

显式转换又称为强制转换，就是由开发人员明确指定转换操作符，强制改变变量的数据类型。

例如，下面的代码显式的将变量 `a` 转换为浮点数类型来进行计算。

```cpp
int a = 5;
int b = 2;
cout << float(a) / b << endl; // 正确输出结果 2.5
```

在编写代码时，为了确保运算结果的正确性，我们需要选择适当的类型转换方式。无论是隐式转换还是显式转换，都需要注意类型转换可能带来的精度损失和数据溢出问题，在显式转换时应该谨慎使用。

## 常量

如果一个程序中的某个数据永远不需要改动，最好将其定义为常量，常量的定义方式非常简单，在变量定义的数据类型前加上关键字 `const` 即可。

例如，在计算圆的面积时，数字中的 $\pi$ 应该是一个常量，可以像下面这样定义：

```cpp
#include <iostream>
using namespace std;

const float PI = 3.14; // 定义常量 PI

int main() {
  float r;
  cin >> r;

	cout << PI * r * r << endl;  
	return 0;
}
```

> 通常来说，常量我们会用全大写字母来表示，这是一个好的习惯（并非必须），当在阅读程序时，很容易区分出程序中哪些是常量，哪些不是。

## 练习

【待补充】
- 大巴车载人的例子
- 时分秒转换的例子
- 买东西打折的例子
- 拆分数字应用

## 小结

变量是程序设计中一个非常重要的基础概念，**它在程序中起到了存储和传递数据的作用**，使得我们能够进行计算、逻辑判断和操作。合理的使用变量，可以提高代码的可读性、可维护性和重用性。

Source: https://cppguide.xyz/basic/variable/index.mdx
