C/C++基础语法
文章目录
- C/C++基础语法
- 头文件
- 经典问题
- 链表
- 链表基础操作
- 秒数转换
- 闰年
- 斐波那契数列
- 打印n阶菱形
- 曼哈顿距离
- 菱形图案的定义
- 大数计算
- 输入输出
- 格式化输入输出
- `getline()`函数解决`cin`只读入一个单词的问题
- fgets读入整行
- 输出字符数组(两种方式puts和printf)
- 运算符
- 赋值运算符
- Switch
- 循环
- 处理未知数量输入的几种常见方法
- for-each
- 字符
- 字符数组的常用操作
- 字符串String
- 基本概念
- 其他数据类型转变为字符串`to_string()`
- 字符串连接
- 字符串判空
- 字符串长度
- 字符串输入输出
- string的比较:
- 为string对象赋值:
- 两个string对象相加:
- 字面值和string对象相加:
- 遍历数组
- 数组
- 初始化memset
- 函数原型
- 参数
- 返回值
- 使用示例
- 注意事项
- 数组复制memcpy
- 函数原型
- 参数
- 返回值
- 使用示例
- 注意事项
- 函数
- 多维数组形参的写法
- 类与结构体
- 类与结构体的定义与使用
- 构造函数
- 指针和引用
- STL
参考资料:
- AcWing
- https://www.w3schools.com/cpp/
- https://cui-jiacai.gitbook.io/c+±stl-tutorial/
- https://www.youtube.com/watch?v=RRVYpIET_RU
- https://takeuforward.org/c/c-stl-tutorial-most-frequent-used-stl-containers/
头文件
#include <cmath>
经典问题
链表
#include <iostream>using namespace std;struct Node
{int val;Node *next;Node(int _val) : val(_val), next(NULL) {} // 空指针
};int main()
{Node node = Node(1); // 定义了一个node类型的变量Node *p = &node;//定义完之后用指针指向
}
C++中可以直接生成一个结构体,然后把这个结构体放到指针p中
Node *p = new Node(1); // 我定义了一个Node类型的变量,他的返回值是这个变量的地址
#include <iostream>using namespace std;struct Node
{int val;Node *next;Node(int _val) : val(_val), next(NULL) {} // 空指针
};int main()
{Node *p = new Node(1); // 我定义了一个Node类型的变量,他的返回值是这个变量的地址auto q = new Node(2);p->next=q;
}
头节点:第一个节点的地址,而不是他的值
链表基础操作
遍历,头插,删除
运行结果:
秒数转换
输入一个整数,表示时间,单位是秒。输出一个字符串,用”时:分:秒”的形式表示这个时间。
#include <iostream>
#include <cstdio>using namespace std;int main()
{int t;cin >> t;int hours = t / 3600;int minutes = t % 3600 / 60;int seconds = t % 60;printf("%d:%d:%d\n", hours, minutes, seconds);return 0;
}
int hours = t / 3600;
计算总秒数 t 包含多少完整的小时。因为1小时 = 3600秒,所以使用整数除法 t / 3600 可以得到完整小时数。整数除法的结果是去掉小数部分,仅保留整数部分。int minutes = t % 3600 / 60;
首先,t % 3600 计算出除去完整小时后剩余的秒数。然后,将这个剩余的秒数除以60(因为1分钟 = 60秒)得到完整分钟数。这里也使用了整数除法,因此结果是剩余秒数中包含的完整分钟数。int seconds = t % 60;
使用取模运算 t % 60 计算出除去完整分钟后剩余的秒数。因为1分钟是60秒,所以这个操作会得到小于60的秒数,即最后剩余的秒数部分。
闰年
判断闰年。闰年有两种情况:
(1) 能被100整除时,必须能被400整除;
(2) 不能被100整除时,被4整除即可。
- 输入一个年份,如果是闰年输出yes,否则输出no。
#include <iostream>
#include <cstdio>using namespace std;int main()
{int year;cin >> year;if (year % 100 == 0){if (year % 400 == 0) cout << "yes" << endl;else cout << "no" << endl;}else{if (year % 4 == 0) cout << "yes" << endl;else cout << "no" << endl;}return 0;
}
- 用一条if语句,判断闰年。
#include <iostream>
#include <cstdio>using namespace std;int main()
{int year;cin >> year;if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)cout << "yes" << endl;elsecout << "no" << endl;return 0;
}
斐波那契数列
求斐波那契数列的第n项。f(1) = 1, f(2) = 1, f(3) = 2, f(n) = f(n-1) + f(n-2)。
#include <iostream>using namespace std;int main()
{int n;cin >> n;int a = 1, b = 1, i = 1;while (i < n){int c = a + b;a = b;b = c;i ++ ;}cout << a << endl;return 0;
}
打印n阶菱形
输入一个n,打印n阶菱形。n是奇数。
#include <iostream>using namespace std;int main()
{int n;cin >> n;int cx = n / 2, cy = n / 2;for (int i = 0; i < n; i ++ ){for (int j = 0; j < n; j ++ )if (abs(i - cx) + abs(j - cy) <= n / 2)cout << '*';else cout << ' ';cout << endl;}return 0;
}
曼哈顿距离
理解 abs(i - cx) + abs(j - cy) <= n / 2
这个条件的关键在于理解曼哈顿距离(Manhattan Distance)的概念,以及如何通过这个距离来定义一个菱形(或者说是正方形对角线方向的正方形)图案。
曼哈顿距离是在格点坐标系中,两点在标准的直角坐标系中的绝对轴距总和(只能横行走和纵向走,走到中心点要几步)。对于任意两点 (x1, y1)
和 (x2, y2)
,它们的曼哈顿距离是 |x1 - x2| + |y1 - y2|
。
在这个程序中,(i, j)
表示当前遍历到的网格点的坐标,(cx, cy)
是图案中心点的坐标。abs(i - cx) + abs(j - cy)
计算的就是当前点 (i, j)
到中心点 (cx, cy)
的曼哈顿距离。
菱形图案的定义
这个条件 abs(i - cx) + abs(j - cy) <= n / 2
用于判断当前点是否在菱形图案内部(包括边界)。这里的 n / 2
实际上定义了菱形的“半径”,即从中心点到边界的最大曼哈顿距离。
- 当
abs(i - cx) + abs(j - cy)
的值小于或等于n / 2
时,这意味着当前点(i, j)
距离中心点的曼哈顿距离在菱形的半径范围内,因此,它位于菱形内部或边界上,程序应该在这个位置打印一个星号*
。 - 当这个距离大于
n / 2
时,当前点(i, j)
在菱形外部,程序在这个位置打印一个空格
-
大数计算
计算 2 的 N 次方。N≤10000
#include <iostream>
#include <algorithm>using namespace std;int main()
{int a[10000], size = 1, n;a[0] = 1;cin >> n;while (n -- ){int t = 0;for (int i = 0; i < size; i ++ ){t += a[i] * 2;a[i] = t % 10;t /= 10;}if (t) a[size ++ ] = t;}for (int i = size - 1; i >= 0; i -- ) cout << a[i];cout << endl;return 0;
}
这段代码是一个计算2
的N
次方的程序,特别适用于处理大数运算,即当N
很大时,直接使用常规数据类型(如int
、long
)无法存储结果的情况。这里N
可以达到10000
。程序通过模拟手工乘法的方式来计算结果,将每一位数字存储在一个数组a
中,数组的每个元素代表结果数的一位,a[0]
是结果的最低位,a[size-1]
是结果的最高位。
下面是代码的详细解释:
-
初始化:
int a[10000]
:定义一个数组a
,用于存储计算过程中的每位数字。size = 1
:初始化结果数字的大小为1,因为2
的0
次方等于1
,所以起始时数组只有一位数字1
。a[0] = 1
:将结果的最低位初始化为1
。
-
读取输入:
cin >> n
:从标准输入读取N
的值。
-
计算
2
的N
次方:while (n -- )
:循环N
次,每次循环相当于将当前结果乘以2
。- 在每次循环中,使用变量
t
来存储进位,初始时进位为0
。 for (int i = 0; i < size; i ++ )
:遍历数组的每一位,模拟乘法运算。t += a[i] * 2
:当前位乘以2
加上前一位的进位(如果有)。a[i] = t % 10
:更新当前位的值为新计算结果的个位数。t /= 10
:计算新的进位值。- 如果最后一位运算完后还有进位(
t
不为0
),则将这个进位作为新的最高位添加到数组的末尾,并增加size
。
-
输出结果:
- 由于数组中存储的是倒序的结果(即最低位在数组的开始位置),因此输出时需要从
size - 1
开始倒序遍历数组。 for (int i = size - 1; i >= 0; i -- ) cout << a[i];
:倒序输出数组的每一位,即输出计算得到的2
的N
次方的结果。cout << endl;
:在结果后输出换行符。
- 由于数组中存储的是倒序的结果(即最低位在数组的开始位置),因此输出时需要从
输入输出
格式化输入输出
#include <iostream>
#include <cstdio>using namespace std;int main()
{float b = 3.12345678;double c = 3.12345678;printf("%.4f\n", b);printf("%.3lf\n", c);printf("%5d\n", a);printf("%8.4f\n", b);printf("%7.3lf\n", c);printf("%-5d!\n", a);printf("%-8.4f!\n", b); // 如果整个数字(包括小数点和小数部分)不足8个字符,则在右侧用空格填充,实现左对齐。printf("%-7.3lf!\n", c);printf("%05d\n", a);printf("%08.4f\n", b);printf("%07.3lf\n", c);return 0;
}
- float, double等输出保留若干位小数时用:
%.4f
,%.3lf
%8.3f
, 表示这个浮点数的最小宽度为8,保留3位小数,当宽度不足时在前面补空格。%-8.3f
,表示最小宽度为8,保留3位小数,当宽度不足时在后面补上空格%08.3f
, 表示最小宽度为8,保留3位小数,当宽度不足时在前面补上0
getline()
函数解决cin
只读入一个单词的问题
cin
将空格(空格、制表符等)视为终止字符,这意味着它只能存储单个单词(即使您键入许多单词)
在处理字符串时,我们经常使用 getline() 函数来读取一行文本。它以 cin 作为第一个参数,字符串变量作为第二个参数:
string fullName;
cout << "Type your full name: ";
getline (cin, fullName);
cout << "Your name is: " << fullName;
或
char s[100];cin.getline(s, 100); // 100是这一行最多读多少个字符cout << s << endl;return 0;
fgets读入整行
如果题目没有超时,用getline比较好;如果输入量比较大用fgets比较好
char s[100];fgets(s, 100, stdin);//100是最多读入多少个字符cout << s << endl;
输出字符数组(两种方式puts和printf)
char s[100];cin.getline(s, 100); // 100是这一行最多读多少个字符puts(s);printf("%s\n",s);//这两种输出方式等价return 0;
运算符
赋值运算符
这些赋值运算符是C++(以及C和其他语言)中的复合赋值运算符,它们将算术或位运算和赋值操作结合在一起。每个运算符的作用如下:
&=
(按位与赋值运算符)
- 语法:
x &= 3
- 等效于:
x = x & 3
- 作用: 将
x
与3
进行按位与操作,然后将结果赋值给x
。按位与操作对应位都为1时结果为1,否则为0。
|=
(按位或赋值运算符)
- 语法:
x |= 3
- 等效于:
x = x | 3
- 作用: 将
x
与3
进行按位或操作,然后将结果赋值给x
。按位或操作对应位有一个为1时结果为1,都为0时结果为0。
^=
(按位异或赋值运算符)
- 语法:
x ^= 3
- 等效于:
x = x ^ 3
- 作用: 将
x
与3
进行按位异或操作,然后将结果赋值给x
。按位异或操作对应位不同为1,相同为0。
>>=
(右移赋值运算符)
- 语法:
x >>= 3
- 等效于:
x = x >> 3
- 作用: 将
x
的二进制表示向右移动3
位,然后将结果赋值给x
。右移操作会将高位丢弃,对于无符号数,低位补0;对于有符号数,低位补充依赖于具体实现(通常是补符号位,即算术右移)。
<<=
(左移赋值运算符)
- 语法:
x <<= 3
- 等效于:
x = x << 3
- 作用: 将
x
的二进制表示向左移动3
位,然后将结果赋值给x
。左移操作会在低位补0,高位丢弃,相当于将x
乘以2
的移动位数次方(这里是2^3
或8
)。
二进制位移操作解释
Switch
int day = 4;
switch (day) {case 1:cout << "Monday";break;case 2:cout << "Tuesday";break;case 3:cout << "Wednesday";break;case 4:cout << "Thursday";break;case 5:cout << "Friday";break;case 6:cout << "Saturday";break;case 7:cout << "Sunday";break;
}
// Outputs "Thursday" (day 4)
循环
处理未知数量输入的几种常见方法
-
while(cin >> x)
在C++中,cin >> x
尝试从标准输入(通常是键盘输入或重定向的文件输入)读取一个值到变量x
中。如果读取成功,表达式的值为true
;如果遇到输入结束(如文件结束或遇到不匹配类型的输入),表达式的值为false
。因此,while(cin >> x)
循环会持续读取输入直到遇到输入结束。 -
while(scanf("%d", &x) != -1)
和while(~scanf("%d", &x))
在C语言中,scanf("%d", &x)
尝试从标准输入读取一个整数到变量x
中。scanf
函数返回成功读取的项目数量。如果读取成功,返回1
;如果遇到输入结束(EOF),返回-1
。
while(scanf("%d", &x) != -1)
循环会持续读取输入,直到scanf
返回-1
,即遇到输入结束。while(~scanf("%d", &x))
利用了位运算符~
(按位取反)。在大多数系统上,EOF
(即-1
)按位取反后的结果是0
,而0
是逻辑假。因此,这个循环同样会持续读取输入,直到遇到输入结束。这是一种更为简洁的写法。
while(cin >> x && x)
和while(cin >> x, x)
这两种形式都用于处理当读入的最后一个值为0
且这个0
不需要处理的情况。
while(cin >> x && x)
循环会持续读取并处理非零的输入。如果x
为0
或遇到输入结束,循环停止。while(cin >> x, x)
使用了逗号运算符,该运算符执行其两边的表达式,并返回右侧表达式的结果。这里先尝试从输入读取一个值到x
,然后通过逗号运算符返回x
的值作为while
循环的条件。这个用法较为少见,且可能引起混淆,其效果与while(cin >> x && x)
相同。
以上这些方法提供了在未知数量输入的情况下从标准输入读取数据的有效手段,以及如何根据特定条件(如输入的值为 0
)结束输入的方式。
for-each
“for-each 循环”(在 C++ 版本 11 (2011) 中引入,专门用于循环数组(或其他数据集合)中的元素
int myNumbers[5] = {10, 20, 30, 40, 50};
for (int i : myNumbers) {cout << i << "\n";
}
字符
常用 ASCIl 值:‘A’-Z’是65~90, ‘a’-z’是97-182,‘0’-'9’是 48-57。
宇符可以参与运算,运算时会将其当做整数
字符数组的常用操作
下面几个函数需要引入头文件:
#include <string.h>//或者
#include <cstring>
strlen(str)
,求字符串的长度(\0
不计入其中)时间复杂度是 O ( n ) O(n) O(n)strcmp(a, b)
,比较两个字符串的大小,a < b返回-1,a == b返回0,a > b返回1。这里的比较方式是字典序!strcpy(a, b)
,将字符串b复制给从a开始的字符数组。
字符串String
基本概念
可变长的字符序列,比字符数组更加好用。需要引入头文件:
#include <string>
- 定义和初始化:
#include <iostream>
#include <string>using namespace std;int main()
{string s1; // 默认初始化,s1是一个空字符串string s2 = s1; // s2是s1的副本,注意s2只是与s1的值相同,并不指向同一段地址string s3 = "hiya"; // s3是该字符串字面值的副本string s4(10, 'c'); // s4的内容是 "cccccccccc"return 0;
}
其他数据类型转变为字符串to_string()
int c = 10;string num = to_string(c);cout << num << endl;
字符串连接
使用+
号或者append()
string firstName = "John";
string lastName = "Doe";
string fullName = firstName + " " + lastName;
fullName = firstName.append(lastName);
cout << fullName;
字符串判空
string s1, s2 = "abc";cout << s1.empty() << endl;//输出1cout << s2.empty() << endl;//输出0
字符串长度
使用length()
或size()
,和strlen()不同,size()的时间复杂度是O(1)的
string txt = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
cout << "The length of the txt string is: " << txt.length();
cout << "The length of the txt string is: " << txt.size();
注意size是无符号整数,因此
s.size() <= -1
一定成立
字符串输入输出
string不可以用scanf读
#include <iostream>
#include <cstring>using namespace std;int main()
{string s;cin >> s; // string不可以用scanf读printf("%s\n", s.c_str()); // 返回字符串所存的字符数组的首地址puts(s.c_str());return 0;
}
读入一行
string s1;getline(cin, s1);cout << s1 << endl;
string的比较:
支持 >, <, >=, <=, ==, !=
等所有比较操作,按字典序进行比较。
为string对象赋值:
string s1(10, 'c'), s2; // s1的内容是 cccccccccc;s2是一个空字符串
s1 = s2; // 赋值:用s2的副本替换s1的副本// 此时s1和s2都是空字符串
两个string对象相加:
psptring s1 = "hello, "", s2 = "world\n";
string s3 = s1 + s2; // s3的内容是 hello, world\n
s1 += s2; // s1 = s1 + s2
字面值和string对象相加:
做加法运算时,字面值和字符都会被转化成string对象,因此直接相加就是将这些字面值串联起来:
string s1 = "hello", s2 = "world"; // 在s1和s2中都没有标点符号
string s3 = s1 + ", " + s2 + '\n';
当把string对象和字符字面值及字符串字面值混在一条语句中使用时,必须确保每个加法运算符的两侧的运算对象至少有一个是string:
string s4 = s1 + ", "; // 正确:把一个string对象和有一个字面值相加
string s5 = "hello" + ", "; // 错误:两个运算对象都不是stringstring s6 = s1 + ", " + "world"; // 正确,每个加法运算都有一个运算符是string
string s7 = "hello" + ", " + s2; // 错误:不能把字面值直接相加,运算是从左到右进行的
遍历数组
可以将string对象当成字符数组来处理:
#include <iostream>
#include <string>using namespace std;int main()
{string s = "hello world";for (int i = 0; i < s.size(); i ++ )cout << s[i] << endl;return 0;
}
或者使用基于范围的for语句:
#include <iostream>
#include <string>using namespace std;int main()
{string s = "hello world";for (char c: s) cout << c << endl;for (char& c: s) c = 'a';//想在改变c的同时改变s[i],在前面加上引用符号&使c等价于s[i]cout << s << endl;return 0;
}
数组
初始化memset
memset
函数是C和C++标准库中的一个函数,用于将一块内存中的每个字节都设置为一个给定的值。它通常用于初始化数组或者内存块。memset
函数的原型定义在 <cstring>
(在C++中)或 <string.h>
(在C中)头文件中。
#include <iostream>
#include <cstring>
using namespace std;
int main()
{int a[10];// memset(a, 0, 40);memset(a, 0, sizeof a); // sizeof a 返回a所占用的字节数量return 0;
}
将数组中的每一个字节设置为这个值。
因此,memset一般设置为0或者-1(补码,每一位都是1)
函数原型
在C和C++中,memset
函数的原型如下:
void *memset(void *s, int c, size_t n);
参数
void *s
:指向要填充的内存块的指针。int c
:是一个值,表示要设置的值。尽管这个参数的类型是int
,但实际上只有最低的8位(一个字节)会被用于设置内存块中的值。size_t n
:内存块的大小,即要设置的字节数。
返回值
memset
函数返回一个指向内存块 s
的指针。
使用示例
假设有一个字符数组 arr
,我们想将其所有元素初始化为0:
char arr[100];
memset(arr, 0, sizeof(arr));
这段代码将 arr
数组的所有100个字节都设置为0。
注意事项
memset
适用于简单的数据类型(如字符数组、整数数组等)的初始化,因为它是按字节操作的。对于需要按位初始化的复杂数据类型(如带有构造函数的C++对象),使用memset
可能不会得到预期的效果。- 当使用
memset
设置非零值时,需要注意c
参数只使用了最低的8位,这意味着如果你想用memset
来初始化比一个字节更大的数据类型(如int
、float
等),除非你是将其初始化为0或某个字节值的重复(比如0x01010101
),否则结果可能不是你所期望的。 - 由于
memset
是按字节设置值,对于初始化高级数据结构或需要调用构造函数的对象数组,应使用更适合的方法,如循环或标准库中的std::fill
或std::fill_n
函数。
数组复制memcpy
memcpy
函数是C和C++标准库中用于复制内存块的函数。它从源内存地址开始复制n
个字节到目标内存地址。这个函数对于执行低级别的二进制数据复制非常有效,尤其是当你需要快速复制大量数据时。memcpy
函数的原型定义在<cstring>
(C++中)或<string.h>
(C中)头文件中。
函数原型
在C和C++中,memcpy
函数的原型如下:
void *memcpy(void *dest, const void *src, size_t n);
参数
void *dest
:指向用于存储复制内容的目标内存块的指针。const void *src
:指向要从中复制数据的源内存块的指针。size_t n
:要复制的字节数。
返回值
memcpy
函数返回一个指向目标内存块dest
的指针。
使用示例
假设你有两个数组,source
和destination
,你想将source
数组的内容复制到destination
数组中:
char source[] = "Hello, World!";
char destination[20];memcpy(destination, source, strlen(source) + 1);
这段代码将source
数组包括结尾的空字符(\0
)一共14个字节的内容复制到destination
数组中。
注意事项
memcpy
函数不处理源和目标内存块重叠的情况。如果内存块重叠,复制的结果是未定义的。对于重叠内存块的复制,应使用memmove
函数。- 使用
memcpy
时必须确保目标内存块足够大,可以容纳要复制的数据,否则可能会导致缓冲区溢出,这是常见的安全漏洞之一。 memcpy
是按字节复制数据,因此它可以用于任何类型的数据复制,包括基本数据类型、结构体、类等,但复制对象时要小心,因为简单的字节复制可能不会正确处理对象内部的深层复制需求,比如指针成员的正确复制。对于包含动态分配内存或复杂资源管理的对象,使用memcpy
可能不适合,应考虑更高级的复制机制。
函数
多维数组形参的写法
// 多维数组中,除了第一维之外,其余维度的大小必须指定
void print(int (*a)[10]) {/* … */}
void print(int a[][10]) {/* … */}
#include <iostream>using namespace std;void print(int a[][10])
{for (int i = 0; i < 10; i ++ ){for (int j = 0; j < 10; j ++ )cout << a[i][j] << ' ';cout << endl;}
}int main()
{int a[10][10];for (int i = 0; i < 10; i ++ )for (int j = 0; j < 10; j ++ )a[i][j] = j;print(a);return 0;
}
类与结构体
类与结构体的定义与使用
类中的变量和函数被统一称为类的成员变量。
private
后面的内容是私有成员变量,在类的外部不能访问;public
后面的内容是公有成员变量,在类的外部可以访问。
#include <iostream>using namespace std;const int N = 1000010;class Person
{private:int age, height;double money;string books[100];public:string name;void say(){cout << "I'm " << name << endl;}int set_age(int a){age = a;}int get_age(){return age;}void add_money(double x){money += x;}
} person_a, person_b, persons[100];int main()
{Person c;c.name = "yxc"; // 正确!访问公有变量c.age = 18; // 错误!访问私有变量c.set_age(18); // 正确!set_age()是共有成员变量c.add_money(100);c.say();cout << c.get_age() << endl;return 0;
}
结构体和类的作用是一样的。不同点在于类默认是private,结构体默认是public。
struct Person
{private:int age, height;double money;string books[100];public:string name;void say(){cout << "I'm " << name << endl;}int set_age(int a){age = a;}int get_age(){return age;}void add_money(double x){money += x;}
} person_a, person_b, persons[100];
构造函数
#include <iostream>using namespace std;struct Person
{int age, height;double money;// 特殊的赋值方式Person(int _age, int _height) : age(_age), height(_height){};Person(int _age, int _height, double _money) // 构造函数{age = _age;height = _height;money = _money;}
};int main()
{// 多种初始化方式Person p1(18, 180, 10000);Person p2 = {18, 180, 10000};return 0;
}
指针和引用
指针指向存放变量的值的地址。因此我们可以通过指针来修改变量的值。
#include <iostream>using namespace std;int main()
{int a = 10;int *p = &a;*p += 5;cout << a << endl;return 0;
}
数组名是一种特殊的指针。指针可以做运算:
#include <iostream>using namespace std;int main()
{int a[5] = {1, 2, 3, 4, 5};for (int i = 0; i < 5; i ++ )cout << *(a + i) << endl;return 0;
}
引用和指针类似,相当于给变量起了个别名。
#include <iostream>using namespace std;int main()
{int a = 10;int &p = a;p += 5;cout << a << endl;return 0;
}
STL
multi是可以有重复元素,没有multi的不能有重复元素