文章

01.C++基础语法

01.C++基础语法

C++ 入门

C++ IDE

  • CodeBlocks 轻量级
  • Clion
  • Visual Code:Mac 版停止开发了
  • Xcode
  • VSCode:[[Visual Studio Code配置C++环境]]
  • 在线:C++ Shell:cpp.sh

变量常量

变量

语法数据类型 变量名 = 初始值;

1
int a = 10;

常量

C++ 定义常量两种方式

  1. #define 宏常量: #define 常量名 常量值
    • 通常在文件上方定义,表示一个常量
  2. const 修饰的变量 const 数据类型 常量名 = 常量值
    • 通常在变量定义前加关键字 const,修饰该变量为常量,不可修改
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//1、宏常量
#define day 7

int main() {

	cout << "一周里总共有 " << day << " 天" << endl;
	//day = 8;  //报错,宏常量不可以修改

	//2、const修饰变量
	const int month = 12;
	cout << "一年里总共有 " << month << " 个月份" << endl;
	//month = 24; //报错,常量是不可以修改的
	
	
	system("pause");

	return 0;
}

运算符

见:[[C++运算符]]

C++ 关键字

见:[[C++关键字]]

C++ 语句

选择结构

if 语句

  • if
  • if else
  • if else else if

示例:

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
int main() {
	int score = 0;
	cout << "请输入考试分数:" << endl;
	cin >> score;
	
	if (score > 600)
	{
		cout << "我考上了一本大学" << endl;
	}
	else if (score > 500)
	{
		cout << "我考上了二本大学" << endl;
	}
	else if (score > 400)
	{
		cout << "我考上了三本大学" << endl;
	}
	else
	{
		cout << "我未考上本科" << endl;
	}
	
	system("pause");
	return 0;
}

三目运算符

作用: 通过三目运算符实现简单的判断

语法:表达式1 ? 表达式2 :表达式3,和 Java 一样

解释:

  • 如果表达式 1 的值为真,执行表达式 2,并返回表达式 2 的结果;
  • 如果表达式 1 的值为假,执行表达式 3,并返回表达式 3 的结果。

格式:

1
2
条件表达式 ? 表达式1 : 表达式2;
// 语义:如果“条件表达式”为true,则整个表达式的值就是表达式1,忽略表达式2;如果“条件表达式”为false,则整个表达式的值就是表达式2,等价于if/else语句。

switch 语句

1
2
3
4
5
6
7
switch(表达式)
{
	case 结果1:执行语句;break;
	case 结果2:执行语句;break;
	// ...
	default:执行语句;break;
}

循环语句

基本循环语句

  • for
  • while
1
2
3
4
5
6
7
8
9
10
11
12
13
int main() {

	int num = 0;
	while (num < 10)
	{
		cout << "num = " << num << endl;
		num++;
	}
	
	system("pause");

	return 0;
}
  • do while
1
2
3
4
5
6
7
8
9
10
11
12
13
int main() {

	int num = 0;
	while (num < 10)
	{
		cout << "num = " << num << endl;
		num++;
	}
	
	system("pause");

	return 0;
}

while 循环区别在于,do…while 先执行一次循环语句,再判断循环条件

范围 for 循环(C++ 11)range-based for loop

定义: 范围 for 循环,是 C++11 的一个语法糖。特点:

  • 它有两个参数,一个是自己创建的变量,另一个是一个容器
  • 范围 for 循环可以将一个容器 (第二个参数) 里的元素依次传第一个参数,并在该循环体中依次对每一个元素做操作。
  • 如果你不想影响容器中的参数,请pass by value,否则请pass by reference

语法:

1
2
3
for (declaration : expression) {
    // 循环体
}
  • declaration:用于循环遍历的局部变量的声明。
  • expression:一个序列表达式,比如一个数组、向量或其他任何带有 begin()end() 成员函数的容器。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// by value
#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    
    for (int num : numbers) { // 每次迭代,变量 num 将被初始化为 numbers 容器中的下一个元素的副本。
        std::cout << num << std::endl;
    }
    
    return 0;
}


// by reference
for (int &num : numbers) {
    num *= 2; // 将每个元素乘以2
}

跳转语句

break

作用: 用于跳出==选择结构==或者==循环结构==

break 使用的时机:

  • 出现在 switch 条件语句中,作用是终止 case 并跳出 switch
  • 出现在循环语句中,作用是跳出当前的循环语句
  • 出现在嵌套循环中,跳出最近的内层循环语句

示例 1:在 switch 语句中使用 break

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
int main() {
	//1、在switch 语句中使用break
	cout << "请选择您挑战副本的难度:" << endl;
	cout << "1、普通" << endl;
	cout << "2、中等" << endl;
	cout << "3、困难" << endl;

	int num = 0;

	cin >> num;

	switch (num)
	{
	case 1:
		cout << "您选择的是普通难度" << endl;
		break;
	case 2:
		cout << "您选择的是中等难度" << endl;
		break;
	case 3:
		cout << "您选择的是困难难度" << endl;
		break;
	}

	system("pause");

	return 0;
}

示例 2:在循环语句中用 break

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int main() {
	//2、在循环语句中用break
	for (int i = 0; i < 10; i++)
	{
		if (i == 5)
		{
			break; //跳出循环语句
		}
		cout << i << endl;
	}

	system("pause");

	return 0;
}

示例 3:在嵌套循环语句中使用 break,退出内层循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int main() {
	//在嵌套循环语句中使用break,退出内层循环
	for (int i = 0; i < 10; i++)
	{
		for (int j = 0; j < 10; j++)
		{
			if (j == 5)
			{
				break;
			}
			cout << "*" << " ";
		}
		cout << endl;
	}
	
	system("pause");

	return 0;
}

continue

作用: 在循环语句中,跳过本次循环中余下尚未执行的语句,继续执行下一次循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int main() {

	for (int i = 0; i < 100; i++)
	{
		if (i % 2 == 0)
		{
			continue;
		}
		cout << i << endl;
	}
	
	system("pause");

	return 0;
}

goto

作用: 可以无条件跳转语句

语法: goto 标记;

解释: 如果标记的名称存在,执行到 goto 语句时,会跳转到标记的位置

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int main() {

	cout << "1" << endl;

	goto FLAG;

	cout << "2" << endl;
	cout << "3" << endl;
	cout << "4" << endl;

	FLAG:

	cout << "5" << endl;
	
	system("pause");

	return 0;
}

注意:在程序中不建议使用 goto 语句,以免造成程序流程混乱

C++ 数据类型

C++ 规定在创建一个变量或者常量时,必须要指定出相应的数据类型,否则无法给变量分配内存。

  • 有符号,最高一位是符号位

shortintlonglong intfloatdoublebool

  • 无符号位,都是正数

这些类型前面加上 unsigned

整型 int

C++ 中能够表示整型的类型有以下几种方式(有符号的),区别在于所占内存空间不同

数据类型占用空间取值范围
short(短整型)2 字节(-2^15 ~ 2^15-1)
int(整型)4 字节(-2^31 ~ 2^31-1)
long(长整形)Windows 为 4 字节,Linux 为 4 字节 (32 位),8 字节 (64 位)(-2^31 ~ 2^31-1)
long long(长长整形)8 字节(-2^63 ~ 2^63-1)

布尔类型 bool

作用: 布尔数据类型代表真或假的值

bool 类型只有两个值:

  • true — 真(本质是 1)
  • false — 假(本质是 0)

bool 类型占 1 个字节大小

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
int main() {
	bool flag = true;
	cout << flag << endl; // 1

	flag = false;
	cout << flag << endl; // 0

	cout << "size of bool = " << sizeof(bool) << endl; //1
	
	system("pause");

	return 0;
}

浮点型 float/double

作用:用于表示小数

浮点型变量分为两种:

  1. 单精度 float
  2. 双精度 double

两者的区别在于表示的有效数字范围不同。

数据类型占用空间有效数字范围
float4 字节7 位有效数字
double8 字节15~16 位有效数字

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int main() {

	float f1 = 3.14f;
	double d1 = 3.14;

	cout << f1 << endl;
	cout << d1<< endl;

	cout << "float  sizeof = " << sizeof(f1) << endl;
	cout << "double sizeof = " << sizeof(d1) << endl;

	//科学计数法
	float f2 = 3e2; // 3 * 10 ^ 2 
	cout << "f2 = " << f2 << endl;

	float f3 = 3e-2;  // 3 * 0.1 ^ 2
	cout << "f3 = " << f3 << endl;

	system("pause");

	return 0;
}

字符型 char

作用: 字符型变量用于显示单个字符

语法: char ch = 'a';

  • C 和 C++ 中字符型变量只占用 1 个字节。
  • 字符型变量并不是把字符本身放到内存中存储,而是将对应的 ASCII编码 放入到存储单元

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int main() {
	
	char ch = 'a';
	cout << ch << endl;
	cout << sizeof(char) << endl;

	//ch = "abcde"; //错误,不可以用双引号
	//ch = 'abcde'; //错误,单引号内只能引用一个字符

	cout << (int)ch << endl;  //查看字符a对应的ASCII码
	ch = 97; //可以直接用ASCII给字符型变量赋值
	cout << ch << endl;

	system("pause");

	return 0;
}

ASCII 码

ASCII 码表格:

ASCII 值控制字符ASCII 值字符ASCII 值字符ASCII 值字符
0NUT32(space)64@96
1SOH33!65A97a
2STX3466B98b
3ETX35#67C99c
4EOT36$68D100d
5ENQ37%69E101e
6ACK38&70F102f
7BEL39,71G103g
8BS40(72H104h
9HT41)73I105i
10LF42*74J106j
11VT43+75K107k
12FF44,76L108l
13CR45-77M109m
14SO46.78N110n
15SI47/79O111o
16DLE48080P112p
17DCI49181Q113q
18DC250282R114r
19DC351383S115s
20DC452484T116t
21NAK53585U117u
22SYN54686V118v
23TB55787W119w
24CAN56888X120x
25EM57989Y121y
26SUB58:90Z122z
27ESC59;91[123{
28FS60<92/124 
29GS61=93]125}
30RS62>94^126`
31US63?95_127DEL

ASCII 码大致由以下两部分组成:

  • ASCII 非打印控制字符: ASCII 表上的数字 0-31 分配给了控制字符,用于控制像打印机等一些外围设备。
  • ASCII 打印字符:数字 32-126 分配给了能在键盘上找到的字符,当查看或打印文档时就会出现。

转义字符

作用: 用于表示一些不能显示出来的 ASCII 字符

现阶段我们常用的转义字符有: \n \\ \t

转义字符含义ASCII码值(十进制)
\a警报007
\b退格 (BS) ,将当前位置移到前一列008
\f换页 (FF),将当前位置移到下页开头012
\n换行 (LF) ,将当前位置移到下一行开头010
\r回车 (CR) ,将当前位置移到本行开头013
\t水平制表 (HT) (跳到下一个 TAB 位置)009
\v垂直制表 (VT)011
\代表一个反斜线字符 ““092
代表一个单引号(撇号)字符039
代表一个双引号字符034
?代表一个问号063
\0数字 0000
\ddd8 进制转义字符,d 范围 0~73 位 8 进制
\xhh16 进制转义字符,h 范围 09,af,A~F3 位 16 进制

示例:

1
2
3
4
5
6
7
int main() {
	cout << "\\" << endl;
	cout << "\tHello" << endl;
	cout << "\n" << endl;
	system("pause");
	return 0;
}

字符串

见: [[04.C++字符串]]

sizeof 关键字

作用: 利用 sizeof 关键字可以统计数据类型所占内存大小

语法: sizeof(数据类型 或 变量)

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main() {

	cout << "short 类型所占内存空间为: " << sizeof(short) << endl;

	cout << "int 类型所占内存空间为: " << sizeof(int) << endl;

	cout << "long 类型所占内存空间为: " << sizeof(long) << endl;

	cout << "long long 类型所占内存空间为: " << sizeof(long long) << endl;

	system("pause");

	return 0;
}

C++ 的 auto 关键字(C++ 11)

  • auto 关键字在 C++ 中是一个类型说明符,用于让编译器自动推断变量的类型。它最早在 C++11 标准中引入,旨在简化代码,使之更加易读,并使得代码维护过程中,更新类型声明变得更加容易。
  • 当你在声明变量时使用 auto 关键字,你不需要显式指定变量的类型,编译器会根据变量的初始化表达式来自动推断变量的类型。
  • 在使用 auto 关键字时,必须立即初始化变量,因为编译器需要初始化表达式来推断类型。

以下是几个 auto 关键字的用例:

1
2
3
4
5
6
auto x = 42; // x 被推断为 int
auto y = 3.14; // y 被推断为 double
auto z = x; // z 被推断为 int

std::vector<int> vec = {1, 2, 3, 4};
auto it = vec.begin(); // it 的类型是 std::vector<int>::iterator

auto 使用建议:如果不是下面两种应用场景,请尽量不要使用 auto,能不用,就不用。

  • 在使用 iterator 的时候
1
2
3
4
5
6
7
8
9
10
11
12
std::vector<std::string> strings;
strings.push_back("Apple");
strings.push_back("Orange");
for (std::vector<std::string>::iterator it = strings.begin(); // 不使用auto
    it != strings.end(); it++)
{
    std::cout << *it << std::endl;
}
for (auto it = strings.begin(); it != strings.end(); it++) // 使用auto后简化代码
{
    std::cout << *it << std::endl;
}
  • 当类型名过长的时候可以使用 auto: 如 lambda,长的指针类型
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
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>

class Device{};

class DeviceManager
{
private:
    std::unordered_map<std::string, std::vector<Device *>> m_Devices;
public:
    const std::unordered_map<std::string, std::vector<Device *>> &GetDevices() const
    {
        return m_Devices;
    }
};

int main()
{
    DeviceManager dm;
    const std::unordered_map<std::string, std::vector<Device *>> &devices = dm.GetDevices();//不使用auto
    const auto& devices = dm.GetDevices(); //使用auto

    std::cin.get();
}

除此之外类型名过长的时候也可以使用 usingtypedef 方法:

1
2
3
4
using DeviceMap = std::unordered_map<std::string, std::vector<Device*>>;
typedef std::unordered_map<std::string, std::vector<Device*>> DeviceMap;

const DeviceMap& devices = dm.GetDevices();

C++ 类型双关 type punning

  • 将同一块内存的东西通过不同 type 的指针给取出来

示例:把一个 int 型的内存,换成 double 去解释,当然这样做很糟糕,因为添加了四字节不属于原本自己的内存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
int main()
{
    int a = 50;
    double value = *(double*)&a;
    std::cout << value << std::endl;

    std::cin.get();
}
// 可以用引用,这样就可以避免拷贝成一个新的变量:(只是演示,这样做很糟糕)
#include <iostream>
int main()
{
    int a = 50;
    double& value = *(double*)&a;
    std::cout << value << std::endl;

    std::cin.get();
}

示例 2:把一个结构体转换成数组进行操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
struct Entity
{
    int x, y;
};

int main()
{
    Entity e = {5, 8};
    int *position = (int *)&e; // 1
    std::cout << position[0] << ", " << position[1] << std::endl;

    int y = *(int *)((char *)&e + 4); // 2
    std::cout << y << std::endl;
}

解释:

上面的 struct 有 2 int 的字段 x 和 y,

  1. (int *)&e:取 e 地址,强转换为 int* 指针,struct 中的字段按它们在定义中的顺序依次排列在内存中,因此 x 会首先被分配空间,紧接着是 y,所以 int* 指针代表的就是 struct Entity 在内存中的起始位置,由于是 2 个 int 值,所以指针 position[0]position[1] 分别访问的是 x 和 y。
  2. e 地址转换成 char* 指针,加 4 表示定位到到了 y 的位置,然后转换为 int* 指针,最后取指针操作,就能把 y 的值取出来了

C++ 函数

见:[[02.C++函数]]

本文由作者按照 CC BY 4.0 进行授权