b站黑马程序员C++课程学习笔记,图片存在github,可能需要翻墙才可见
一、C++简介
1.1 C++的产生及其特点
- 从C语言发展演变而来,解决了C语言中存在的一些问题,并增加了对面向对象程序设计方法的支持
- 与其他高级语言相比,C语言可以直接访问物理地址;与汇编相比它具有良好的可读性和可移植性
- C++于1980年由贝尔实验室的Bjarne Stroustrup创建
- 特点:
- 尽量兼容C语言
- 支持面向对象的方法
- 对象是程序的基本单元
- 对象的属性需要用某种类型的数据来表示
- 对象的功能和行为由成员函数来实现,函数的实现归根到底是算法的设计
1.2 Hello World
// #include头文件,既用于声明头文件以供多个文件使用,同时也用来声明函数原型,以便于在整个程序中使用
#include <iostream>
// 主函数,程序入口
int main(){
std::cout << "Hello World !" << std::endl;
std::cout << "Welcome to C++ ! " << std::endl;
return 0;
}
二、C++语法基础
2.1 标识符命名规则
- 以字母或者下划线开始
- 可以由大写字母、小写字母、下划线或数字0~9组成
- 区分大小写
- 不能是C++关键字或操作符
2.2 注释
- 单行注释:
//注释描述
- 多行注释:
/* 注释描述 */
2.3 变量
-
作用:给一段指定的内存空间命名,方便操作这段内存
-
语法:
数据类型 变量名 = 初始值;
#include<iostream> using namespace std; int main() { //变量的定义 //语法:数据类型 变量名 = 初始值 int a = 10; cout << "a = " << a << endl; system("pause"); return 0; }
2.4 常量
-
作用:记录程序中不可更改的数据
-
定义方式:
- #define 宏常量:
#define 常量名 常量值
- 没有数据类型,只是简单的字符串替换,不能进行安全检查
- const常量:
const 数据类型 常量名 = 常量值
- 常类型,创建时必须初始化
- 编译期概念,即编译时用到的地方都会替换成相应的值,可节省空间,避免不必要的内存分配
- 作用:
- 防止修改,起保护作用,增加程序的健壮性
- 可以节省空间,避免不必要的内存分配
//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; }
- #define 宏常量:
-
const对象默认为文件局部变量
- 默认情况下,const对象被设定为仅在文件内有效,如果要在不同的程序文件中使用同一个const对象,则必须要显示声明extern,并初始化
- 多个文件之间共享const对象,那么不管是声明还是定义都可添加上extern关键字,这样就只需要定义一次即可
- 非const变量默认为extern,因此不需要显示声明
// file_1.cpp // 定义并初始化了一个常量,该常量可以被其他文件访问 extern const int bufSize = fcn(); // file_2.h // 与file_1.cpp中定义的bufSize是同一个 extern const int bufSize; // file_1.cpp定义并初始化了bufSize,因此显然是一个定义,加上了extern则可以被其他文件访问 // file_2.h头文件中的声明也由extern做了限定,其作用是指明bufSize并非本文独有,它的定义将在别处出现
2.5 数据类型
- 作用:
- 存储所需要的尺寸
- 取值空间
- 对齐信息
- 可执行的操作
- 不同变量类型之间的唯一区别就是内存空间大小
- 1 byte = 8 bit
- 1 bit 可为0或1
- 有符号数signed,需要有一位表示符号+/- ;无符号数unsigned
2.5.1 整型 int
- sizeof关键字
- 作用:统计数据类型所占内存大小
- 语法:
sizeof( 数据类型 / 变量)
- 例如:
sizeof(float)
- 整型内存大小的一个结论:short < int <= long <= long long
2.5.2 浮点型(实型)
-
作用:表示小数
-
分成两种:float、double
- 默认情况下,输出一个小数,会显示出6位有效数字
2.5.3 字符型 char
-
作用:用于显示单个字符
-
语法:
char ch = 'a';
-
注意:
- 用单引号将字符括起
- 单引号内只能有一个字符
-
C/C++中字符型变量只占用一个字节
-
不是把字符本身放到内存中存储,而是将对应的ASCII编码放入存储单元
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字符
-
字符串型
-
C风格:
char 变量名[]="字符串值"
- 要加中括号
int main() { char str1[] = "hello world"; cout << str1 << endl; system("pause"); return 0; }
-
C++风格:
string 变量名="字符串值"
- 要包含头文件:
#include <string>
#include <string> int main() { string str = "hello world"; cout << str << endl; system("pause"); return 0; }
- 要包含头文件:
-
2.5.4 布尔型 bool
-
只有两个值
- true:本质是1,非0都是1
- false:本质是0
-
只占1个字节
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; }
2.6 标准库类型string
标准库 string 表示可变长的字符序列
使用string类型时必须要首先包含string头文件
#include <string>
-
定义和初始化
string s1; // 默认初始化,s1是一个空字符串 string s2(s1); // 直接初始化 string s2 = s1; // 拷贝初始化
- 如果使用等号=初始化一个变量,实际上就是执行的拷贝初始化
- 不使用等号=,则执行的直接初始化
string s3(n, 'c'); // 把s3初始化为由连续n个字符c组成的串 // 例如: string s3(5, 'c'); // s3的初始化内容是5个c组成的串:ccccc
-
string对象的操作
- 执行读取操作时,string对象会自动忽略开头的空白,从第一个真正的字符开始读起
- 输入:“ HelloWorld ”,输出:“HelloWorld”
#include <string> int main() { string s; std::cin >> s; std::cout << s << std::endl; return 0; }
- 多个输入或多个输出可以连写在一起
string s1, s2; cin >> s1 >> s2; // 第一个输入读到s1中, 第二个输入读到s2中 cout << s1 << s2 << endl;
-
getline
- 读取一整行
- 可保留字符串中的空白符
- getline函数的参数是一个输入流和一个string对象,函数从给定的输入流中读入内容,将读入内存的存放到string对象中
- getline遇到换行符就结束读取操作并返回结果
int main() { string line; // 每次循环都是读入一整行, while (getline(cin, line)) { cout << line << endl; } return 0; }
-
empty
- string的成员函数
- 根据string对象是否为空返回一个对应的布尔值
while ( getline(cin, line) ) { if ( !line.empty() ) { count << line << endl; } }
-
size
- string的成员函数
- 返回string对象的长度,即string对象中字符的个数
string line; while (getline(cin, line)) { if (line.size() > 80) cout << line << endl; }
- size函数返回的是一个string::size_type类型的值
2.7 标准库类型vector
-
vector表示对象的集合,其中所有对象的类型都相同,集合中的每个对象都有一个与之对应的索引,该索引可用于访问对象
-
vector容纳着其他对象,因此也常称为容器(container)
-
使用vector必须包含vector头文件
#include <vector> using std::vector;
-
vector是一个类模板
- 模板本身不是类或函数,可将其看作编译器生成类或函数编写的一份说明
- 当使用模板时,需要指出编译器应该把类或函数实例化成何种类型
- 实例化:编译器根据模板创建类或函数的过程
-
定义和初始化
vector<T> v1; // T是对象类型,v1是一个空的vector对象,执行默认初始化 vector<T> v2(v1); // v2中包含v1所有元素的副本 vector<T> v2 = v1; // 同上 vector<T> v3(n, val); // v3包含n个重复的元素, 每个元素值都是val // 值初始化 vector<T> v4(n) // 只提供容纳的元素数量,初值由元素类型决定,如int型则初值为0 // 列表初始化 vector<T> v4{a, b, c, ...}; // v4包含了初始值个数的元素,每个元素被赋予相应的初始值 vector<T> v5 = {a, b, c, ...}; // 同上
-
push_back
- vector的成员函数,用于添加元素
- 将一个值作为vector对象的尾元素push到vector对象的尾端
// 将0 ~ 99的整数存储到v2中 vector<int> v2; for (int i = 0; i != 100; ++i) { v2.push_back(i); }
// 从标准输入中读取单词,将其作为vector对象的元素存储 string word; vector<string> text; while ( cin >> word ) { text.push_back(word); }
- 如果循环体内包含有向vector对象添加元素的语句,则不能使用范围for循环
- 范围for循环语句体内不应改变其所遍历序列的大小
注意:
-
不能用下标形式给vector对象添加元素
-
可用于访问已存在的元素,下标从0开始
2.6 数据输入
-
从键盘获取输入数据
int main(){ //整型输入 int a = 0; cout << "请输入整型变量:" << endl; cin >> a; cout << a << endl; //浮点型输入 double d = 0; cout << "请输入浮点型变量:" << endl; cin >> d; cout << d << endl; //字符型输入 char ch = 0; cout << "请输入字符型变量:" << endl; cin >> ch; cout << ch << endl; //字符串型输入 string str; cout << "请输入字符串型变量:" << endl; cin >> str; cout << str << endl; //布尔类型输入 bool flag = true; cout << "请输入布尔型变量:" << endl; cin >> flag; cout << flag << endl; system("pause"); return EXIT_SUCCESS; }
2.7 类型别名
两种方式:
-
typedef
typedef double d; // d是类型double的同义词
-
别名声明:using
using d = double; // 把等号左侧的名字规定成右侧的类型的别名
2.7.1 auto
-
让编译器通过初始值来推算变量的类型
-
auto定义的变量必须要有初始值
auto a = val1 + val2; // a初始化为val1和val2相加的结果
-
auto可以在一条语句中声明多个变量,但必须注意一条声明语句只能有一个基本数据类型
auto i = 1, *p = &i; // i是整型变量,p是整型指针 auto a = 0, b = 3.14; // 错误!!!
2.7.2 decltype
-
选择并返回操作数的数据类型
decltype( fcn() ) sum = x; // sum的类型是函数fcn返回类型
-
编译器会分析表达式并得到它的类型,不会实际计算表达式的值
三、运算符
- 用于执行代码运算
3.1 算术运算符
- 处理四则运算
-
加减乘除
int main() { int a1 = 10; int b1 = 3; cout << a1 + b1 << endl; cout << a1 - b1 << endl; cout << a1 * b1 << endl; cout << a1 / b1 << endl; //两个整数相除结果依然是整数 int a2 = 10; int b2 = 20; cout << a2 / b2 << endl; int a3 = 10; int b3 = 0; //cout << a3 / b3 << endl; //报错,除数不可以为0 //两个小数可以相除 double d1 = 0.5; double d2 = 0.25; cout << d1 / d2 << endl; return 0; }
-
取模
int main() { int a1 = 10; int b1 = 3; cout << 10 % 3 << endl; int a2 = 10; int b2 = 20; cout << a2 % b2 << endl; int a3 = 10; int b3 = 0; //cout << a3 % b3 << endl; //取模运算时,除数也不能为0 //两个小数不可以取模 double d1 = 3.14; double d2 = 1.1; //cout << d1 % d2 << endl; return 0; }
-
递增递减
int main() { //后置递增 int a = 10; a++; //等价于a = a + 1 cout << a << endl; // 11 //前置递增 int b = 10; ++b; cout << b << endl; // 11 //区别 //前置递增先对变量进行++,再计算表达式 int a2 = 10; int b2 = ++a2 * 10; cout << b2 << endl; //后置递增先计算表达式,后对变量进行++ int a3 = 10; int b3 = a3++ * 10; cout << b3 << endl; return 0; }
3.2 赋值运算符
3.3 比较运算符
- 用于表达式的比较,并返回一个真值或假值
3.4 逻辑运算符
- 用于根据表达式的值返回真值或假值
四、基本控制结构
C/C++支持最基本的三种程序运行结构:顺序结构、选择结构、循环结构
- 顺序结构:程序按顺序执行,不发生跳转
- 选择结构:依据条件是否满足,有选择的执行相应功能
- 循环结构:依据条件是否满足,循环多次执行某段代码
4.1 选择结构
4.1.1 if语句
-
单行格式 if 语句
int main() { //选择结构-单行if语句 //输入一个分数,如果分数大于600分,视为考上一本大学,并在屏幕上打印 int score = 0; cout << "请输入一个分数:" << endl; cin >> score; cout << "您输入的分数为: " << score << endl; //if语句 //注意事项,在if判断语句后面,不要加分号 if (score > 600) { cout << "我考上了一本大学!!!" << endl; } return 0; }
-
多行格式 if 语句
int main() { int score = 0; cout << "请输入考试分数:" << endl; cin >> score; if (score > 600) { cout << "我考上了一本大学" << endl; } else { cout << "我未考上一本大学" << endl; } return 0; }
-
多条件的 if 语句
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; } return 0; } /**********************等价于*************************/ else { if (score > 500) { cout << "我考上了二本大学" << endl; } }
-
嵌套if语句
// 案例需求: // 提示用户输入一个高考考试分数,根据分数做如下判断 // 分数如果大于600分视为考上一本,大于500分考上二本,大于400考上三本,其余视为未考上本科 // 在一本分数中,如果大于700分,考入北大,大于650分,考入清华,大于600考入人大 int main() { int score = 0; cout << "请输入考试分数:" << endl; cin >> score; if (score > 600) { cout << "我考上了一本大学" << endl; if (score > 700) { cout << "我考上了北大" << endl; } else if (score > 650) { cout << "我考上了清华" << endl; } else { cout << "我考上了人大" << endl; } } else if (score > 500) { cout << "我考上了二本大学" << endl; } else if (score > 400) { cout << "我考上了三本大学" << endl; } else { cout << "我未考上本科" << endl; } return 0; }
4.1.2 三目运算符
-
语法:
表达式1 ? 表达式2 :表达式3
- 如果表达式1的值为真,执行表达式2,并返回表达式2的结果;
- 如果表达式1的值为假,执行表达式3,并返回表达式3的结果。
int main() { int a = 10, b = 20, c = 0; c = a > b ? a : b; cout << "c = " << c << endl; //C++中三目运算符返回的是变量,可以继续赋值 (a > b ? a : b) = 100; cout << "a = " << a << endl; cout << "b = " << b << endl; cout << "c = " << c << endl; return 0; }
4.1.3 switch语句
-
执行多条件分支语句
-
switch语句中表达式类型只能是整型或者字符型
-
case里如果没有break,那么程序会一直向下执行
switch(表达式) { case 结果1:执行语句; break; case 结果2:执行语句; break; ... default:执行语句;break; }
//请给电影评分 //10 ~ 9 经典 // 8 ~ 7 非常好 // 6 ~ 5 一般 // 5分以下 烂片 int main() { int score = 0; cout << "请给电影打分" << endl; cin >> score; switch (score) { case 10: // 没有break就会继续往下执行 case 9: cout << "经典" << endl; break; case 8: cout << "非常好" << endl; break; case 7: case 6: cout << "一般" << endl; break; default: cout << "烂片" << endl; break; } return 0; }
4.2 循环语句
4.2.1 while循环
-
满足循环条件,执行循环语句
int main() { int num = 0; while (num < 10) { cout << "num = " << num << endl; num++; } return 0; }
4.2.2 do…while循环
-
与while的区别在于do…while会先执行一次循环语句,再判断循环条件
int main() { int num = 0; do { cout << num << endl; num++; } while (num < 10); return 0; }
4.2.3 for循环
-
语法:
for(起始表达式; 条件表达式; 末尾循环体) { 循环语句; }
int main() { for (int i = 0; i < 10; i++) { cout << i << endl; } return 0; } /*****************等价于***********************/ int i = 0; bool condition = true; for(;condition;) { i++; if(!(i < 10)) condition = false; }
4.3 break语句
-
用于跳出选择结构或者循环结构
-
break使用的时机:
- 出现在switch条件语句中,作用是终止case并跳出switch
- 出现在循环语句中,作用是跳出当前的循环语句
- 出现在嵌套循环中,跳出最近的内层循环语句
int main() { //2、在循环语句中用break for (int i = 0; i < 10; i++) { if (i == 5) { break; //跳出循环语句 } cout << i << endl; } return 0; }
4.4 continue语句
-
在循环语句中,跳过本次循环中余下尚未执行的语句,继续执行下一次循环
int main() { for (int i = 0; i < 100; i++) { if (i % 2 == 0) { continue; } cout << i << endl; } return 0; }
五、指针
5.1 指针的基本概念
-
指针是一个整数,存储一个内存地址
- 电脑中的内存就像是一条大街,街边都是房子,每栋房子都有一个门牌号和地址,将每栋带地址的房子想象成一个字节的数据(1 byte)
- 现在有人网购,需要送货上门;有人需要寄快递,把东西送出去。那么需要一个方法来获取正确的门牌号地址,也要能够从房子里搬东西出去,即能够从内存中,对那些byte进行read和write
- 指针就是那个地址,告诉我们房子在什么地方 —— 指定的字节的在电脑内存的哪个位置
- 电脑中的内存就像是一条大街,街边都是房子,每栋房子都有一个门牌号和地址,将每栋带地址的房子想象成一个字节的数据(1 byte)
-
语法:
数据类型* 变量名;
- 数据类型types对指针本身而言完全没有意义,因为所有指针都是一个整数,存放一个内存地址
- 数据类型代表的是存放在这个内存中的数据的类型
int main() { //指针的定义:数据类型* 变量名 ; int a = 10; //定义整型变量a int* p = &a; //定义并初始化指针, 指向变量a的地址 cout << &a << endl; //打印数据a的地址 cout << p << endl; //打印指针变量p }
- 数据类型types对指针本身而言完全没有意义,因为所有指针都是一个整数,存放一个内存地址
5.2 指针的使用
-
在指针前面加一个星号
*
,即可访问指针指向内存中存储的数据,并对其进行操作- 星号
*
也称为解引用符
- 星号
-
这也称为Dereferencing(逆向引用,解引用)
//通过*操作指针变量指向的内存 cout << "*p = " << *p << endl;
5.3 指针与const
-
指向常量的指针(pointer to const,const在*左侧)
const int *p = &a; // 或者 int const *p = &a;
-
const修饰的是指针指向的对象类型,而不是指针本身
const double pi = 3.14; // pi是常量 const double *p = π // p可以指向一个双精度常量 double *p2 = π // 错误!!!p2是一个普通指针,不可以指向一个常量对象
-
指向常量的指针可以指向一个非常量对象
int a = 1; const int *p = &a; // 不可以通过指针p来修改a的值
-
常量指针指向可以修改(地址),但是指向的值不可以修改(地址保存的值)
-
-
常量指针(const pointer,const在*右侧)
int *const p = &a;
-
const修饰的是指针本身
-
常量指针必须要初始化,且该指针的值不能修改
-
常量指针所指向的值可以通过非常量指针进行修改
#include <iostream> using namespace std; int main() { int num = 0; int * const ptr = # //const指针必须初始化!且const指针的值不能修改 int * t = # // 通过非常量指针对常量指针指向的值进行修改 *t = 1; cout << *ptr << endl; }
-
-
顶层const
- 顶层const(top-level const)表示指针本身是个常量
- 底层const(low-level const)表示指针所指向的对象是个常量
六、引用
6.1 引用的基本概念和使用
-
本质上只是指针的一个拓展
- 没有reference能做而pointer不能做的事
-
与指针的区别:
- reference必须引用一个已存在的变量,引用本身并不是一个新的变量,不真正占用内存
-
定义引用:
数据类型& 引用名
int main() { int a = 10; int &b = a; // b是a的别名 cout << "a = " << a << endl; cout << "b = " << b << endl; // b是a的别名,修改b的值就是在修改a的值 b = 100; cout << "a = " << a << endl; cout << "b = " << b << endl; return 0; }
-
注意事项:
- 引用必须初始化
- 引用在初始化之后,不可以改变
int main() { int a = 10; int b = 20; /***引用必须初始化***/ // int &c; // 错误!!! int &c = a; /***引用一旦初始化后,就不可以更改***/ // c = b; // 错误!!! cout << "a = " << a << endl; cout << "b = " << b << endl; cout << "c = " << c << endl; return 0; }
6.2 const引用
-
将引用绑定到const对象上
-
引用的类型必须与其所引用的对象的类型一致
-
常量引用可以绑定到一个普通的类型对象上,只是不能通过该常量引用修改绑定对象的值
const int a = 10; const int &b = a; int c = 5; const int &d = c;
七、函数
7.1 函数的定义与声明
-
函数的组成:
返回类型 函数名字(参数列表) { 函数体 }
-
函数的声明(也称为函数接口):
- 与定义的区别:函数声明不需要函数体
- 函数接口三要素:
- 返回类型
- 函数名
- 形参类型
-
一般在头文件中进行声明,在源文件中定义
- 含有函数声明的头文件应该被包含到定义函数的源文件中
7.2 参数传递
- 每次调用函数都会重建它的形参,并用传入的实参对形参进行初始化
7.2.1 值传递
- 实参的值被拷贝给形参,形参和实参是两个相互独立的对象
- 实参被值传递,函数被传值调用
- 函数对形参做的所有操作都不会影响实参
7.2.2 引用传递
- 形参是引用类型,那么它将直接绑定到对应的实参上
- 实参被引用传递,函数被传引用调用
7.3 函数分文件编写
- 作用:让代码结构更加清晰
- 步骤:
- 创建后缀名为 .h 的头文件
- 在头文件中写函数的声明
- 创建后缀名为 .cpp 的源文件
- 引用上一步的.h头文件
- 在源文件中写函数的定义
- 在主函数中调用函数,引用该函数的头文件
- 创建后缀名为 .h 的头文件
示例:
swap.h 头文件
# include <iostream>
//实现两个数字交换的函数声明
void swap(int a, int b);
swap.cpp 源文件
// 双引号""代表自定义的头文件
# include "swap.h"
void swap(int a, int b){
int temp = a;
a = b;
b = temp;
}
main.cpp 主程序文件
# include <iostream>
# include "swap.h"
int main(){
int a = 10;
int b = 20;
swap(a, b);
return 0;
}
八、数组
- 数组是一些元素的集合
- 每个数据元素都是相同的数据类型
- 由连续的内存位置组成
8.1 一维数组
-
定义方式
int main(){ // 方式1 // 数据类型 数组名[元素个数]; int score[10]; // 利用下标赋值 score[0] = 100; score[1] = 99; score[2] = 85; // 利用下标输出 cout << score[0] << endl; cout << score[1] << endl; cout << score[2] << endl; // 方式2 // 数据类型 数组名[元素个数] = {值1, 值2, 值3, ...}; // 如果{}内不足10个数据,剩余数据用0补全 int score2[10] = {100, 90, 80, 70, 60}; // 逐个输出 cout << score2[0] << endl; cout << score2[1] << endl; // 逐个输出太麻烦,可利用循环进行输出 for(int i = 0; i < 10; i++) { cout << score[i] << endl; } // 方式3 // 数据类型 数组名[] = {值1, 值2, 值3, ...}; int score3[] = {100, 90, 80, 70, 60}; }
-
数组名
- 可统计整个数组在内存中的长度
- 可获取数组在内存中的首地址
int main() { int arr[6] = { 11,22,33,44,55,66 }; cout << sizeof(arr) << endl; //整个数组占用内存大小; cout << sizeof(arr[0]) << endl; //第一个元素占用内存大小; cout << sizeof(arr) / sizeof(arr[0]) << endl; //数组中元素个数; cout << (int)arr << endl; //整个数组首地址,转十进制; cout << (int)&arr[0] << endl; //第一个元素的首地址,&是取址符,和整个数组相同; cout << (int)&arr[1] << endl; //第二个元素的首地址; //数组名是常量,不可赋值; arr = 100; // 错误!!!arr是地址,不可以修改 }
-
案例
#include <iostream> #include <string> #include <cmath> #include <ctime> using namespace std; int main() { //五只小猪称体重 int arrpig[5] = { 300, 350, 200, 250, 400 }; //设定一个最大值,访问数组中的每个值,如果比这个值大,就更新最大值; int max = 0; for (int i = 0; i < 5; i++) { //cout << arrpig[i] << endl; if (arrpig[i] > max) { max = arrpig[i]; //访问数组中的每个值,如果比max大,就更新最大值; } } cout << "最重的猪为" << max << "kg" << endl; //数组元素逆置,原数组为1,2,3,4,5,逆置后为5,4,3,2,1; int arrx[5] = { 1,2,3,4,5 }; cout << "逆置前的数组为:" ; for (int n = 0; n < 5; n++) { cout << arrx[n]; } printf("\n"); int start = 0; //第一个元素下标; int end = sizeof(arrx) / sizeof(arrx[0]) - 1; //最后一个元素下标,算法为元素个数减1; //只有当 start < end 时才互换; while (start < end) { int temp = arrx[start]; // 定义一个临时储存空间,把第一个元素先放进去; arrx[start] = arrx[end]; // 把最后一个元素放到第一个元素去; arrx[end] = temp; // 把temp里的值放到最后一个元素去,实现互换; start++; // 下标更新; end--; // 下标更新; } cout << "逆置后的数组为:" ; for (int n = 0; n < 5; n++) { cout << arrx[n]; } printf("\n"); system("pause"); return 0; }
-
冒泡排序
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个;
- 对每一对相邻元素做同样的工作,执行完毕后,找到第一个最大值;
- 重复以上步骤,每次比较次数-1,直到不需要比较。
- 排序总轮数 = 元素个数 - 1
- 每轮对比次数 = 元素个数 - 排序轮数 - 1
// 利用冒泡排序实现升序序列 #include <iostream> // 冒泡排序函数 参数1 数组的首地址 参数2 数组长度 void bubbleSort(int* arr, int len) { // 总共排序轮数为:数组长度-1 for (int i = 0; i < len - 1; i++) { // 每轮对比次数:数组长度-i-1 for (int j = 0; j < len - i - 1; j++) { // 前一个元素比后一个元素大则互换位置 if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } } // 打印数组 void printArray(int* arr, int len) { for (int i = 0; i < len; i++) { std::cout << arr[i] << std::endl; } } int main() { // 1、创建数组 int arr[10] = { 4, 3, 6, 9, 1, 2, 10, 8, 7, 5 }; int len = sizeof(arr) / sizeof(arr[0]); // 2、创建函数,实现冒泡排序 bubbleSort(arr, len); // 3、打印排序后的数组 printArray(arr, len); system("pause"); return 0; }
8.2 二维数组
-
在一维数组的基础上多加一个维度
int main(){ // 1,数据类型 数组名[行数][列数]; int arr[2][3]; arr[0][0] = 1; arr[0][1] = 2; arr[0][2] = 3; arr[1][0] = 4; arr[1][1] = 5; arr[1][2] = 6; // 逐个输出 cout << arr[0][0] << endl; cout << arr[0][1] << endl; ... cout << arr[1][2] << endl; // 利用嵌套循环逐个输出 // 外层循环打印行数,内层循环打印列数 for (int i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { cout << arr[i][j] << endl; } } // 2,数据类型 数组名[行数][列数] = {{数据1,数据2},{数据3,数据4}}; // 直观,代码可读性高,比较常用 int arr2[2][3] = { {1, 2, 3}, {4, 5, 6} }; for (int i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { cout << arr2[i][j] << " "; } cout << endl; } // 3,数据类型 数组名[行数][列数] = {数据1,数据2,数据3,数据4}; int arr3[2][3] = {11, 22, 33, 44, 55, 66}; for (int i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { cout << arr3[i][j] << " "; } cout << endl; } // 4,数据类型 数组名[][列数] = {数据1,数据2,数据3,数据4}; int arr4[][3] = { 1, 2, 3, 4, 5, 6 }; for (int i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { cout << arr4[i][j] << " "; } cout << endl; } // 数组名称用途 // 查看占用内存空间 cout << "二维数组占用内存空间:" << sizeof(arr4) << endl; cout << "二维数组第一行占用内存空间:" << sizeof(arr4[0]) << endl; // 第0行 cout << "二维数组第一个元素占用内存空间:" << sizeof(arr4[0][0]) << endl; cout << "二维数组的行数:" << sizeof(arr4) / sizeof(arr4[0]) << endl; cout << "二维数组的列数:" << sizeof(arr4[0]) / sizeof(arr4[0][0]) << endl; // 二维数组占用内存空间 cout << "二维数组的首地址:" << (int)arr4 << endl; cout << "二维数组第一行的首地址:" << (int)arr4[0] << endl; cout << "二维数组第二行的首地址:" << (int)arr4[1] << endl; cout << "二维数组第一个元素的首地址:" << (int)&arr4[0][0] << endl; // 访问具体元素的地址需要加地址符 cout << "二维数组第二个元素的首地址:" << (int)&arr4[0][1] << endl; }
-
案例:考试成绩统计
#include <iostream> #include <string> int main() { int scores[3][3] = { {100, 100, 100}, {90, 50, 100}, {60, 70, 80} }; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { cout << scores[i][j] << " "; } cout << endl; } string names[3] = { "张三", "李四", "王五" }; //字符串; // 每一行的三列进行相加得到总和 for (int i = 0; i < 3; i++) { int sum = 0; // 统计分数总和变量 for (int j = 0; j < 3; j++) { sum += scores[i][j]; //sum = sum + scores[i][j] } cout << names[i] << "的总分是:" << sum << endl; } system("pause"); return 0; }
九、结构体
9.1 结构体定义与使用
-
结构体属于用户自定义的数据类型,允许用户存储不同的数据
-
语法:
struct 结构体名{ 结构体成员列表 };
- 定义的时候不可以省略掉struct,一般定义在main函数前或头文件里
-
创建方式
- 定义结构体时的关键字是struct,不可以省略
- 创建结构体变量时,struct可以省略
- 结构体变量利用操作符“.”访问成员
#include <iostream> #include <string> using namespace std; // 1、创建学生数据类型:学生包括(姓名,年龄,分数) // 自定义数据类型,一些类型集合组成的一个类型 struct Student{ // 成员列表 string name; // 姓名 int age; // 年龄 int score; // 分数 }s3; // 2.3 定义结构体时顺便创建结构体变量s3(这种方式可读性差,不建议用) int main(){ // 2、通过学生类型创建具体学生 // 2.1 struct Student s1 struct Student s1; // 创建结构体变量的时候可以省略struct,但是定义的时候不可以省略 Student s4; // 给s1属性赋值,通过“.”访问结构体变量中的属性 s1.name = "张三"; s1.age = 18; s1.score = 100; cout << "姓名:" << s1.name << "年龄:" << s1.age << "分数:" << s1.score << endl; // 2.2 struct Student s2 = {...} // 创建结构体变量s2的时候赋初值 struct Student s2 = {"李四", 19, 80}; cout << "姓名:" << s2.name << "年龄:" << s2.age << "分数:" << s2.score << endl; // 2.3 定义结构体时顺便创建结构体变量 s3.name = "王五"; s3.age = 18; s3.score = 80; cout << "姓名:" << s3.name << "年龄:" << s3.age << "分数:" << s3.score << endl; }
9.2 结构体数组
-
作用:将自定义结构体放入到数组中方便维护
-
语法:
struct 结构体名 数组名[元素个数] = { {}, {}, ..., {} }
#include <iostream> #include <string> using namespace std; // 1、结构体定义 struct Student{ string name; // 姓名 int age; // 年龄 int score; // 分数 }; int main(){ // 2、创建结构体数组 // 可以初始化的时候赋初值,也可以创建后再赋值 struct Student stuArray[3] = { {"张三", 18, 120}, {"李四", 24, 80}, {"王五", 30, 95} }; // 3、给结构体数组中的元素赋值 stuArray[2].name = "赵六"; stuArray[2].age = 80; stuArray[2].score = 60; // 4、遍历结构体数组 for (int i = 0; i < 3; i++) { cout << "姓名:" << stuArray[i].name << "年龄:" << stuarray[i].age << "分数:" << stuarray[i].score << endl; } }
9.3 结构体指针
-
作用:通过指针访问结构体中的成员
-
利用操作符
->
可以通过结构体指针访问结构体属性// 1、定义结构体变量 struct Student{ string name; // 姓名 int age; // 年龄 int score; // 分数 }; int main(){ // 2、创建结构体变量 struct Student s = { "张三", 18, 100 }; // 3、通过指针指向结构体变量 struct Student * p = &s; // 4、通过指针访问结构体变量中的数据 // 通过结构体指针访问结构体中的属性,需要利用操作符“->”进行访问 cout << "姓名:" << p->name << "年龄:" << p->age << "分数:" << p->score << endl; }
9.4 结构体嵌套
-
结构体中的成员可以是另外一个结构体
#include <iostream> #include <string> using namesapce std; // 每个老师辅导一个学员,一个老师的结构体中记录一个学生结构体 // 1、定义学生结构体(在老师结构体定义中要使用,因此要在定义老师结构体前先义学生结构体) struct Student{ string name; // 学生姓名 int age; // 学生年龄 int score; // 学生分数 }; // 2、定义老师结构体 struct Teacher{ int id; // 教师编号 string name; // 教师姓名 int age; // 教师编号 struct Student stu; // 辅导的学生 }; int main(){ Teacher t; // 创建老师变量 t.id = 10000; t.name = "老王"; t.age = 50; t.stu.name = "小王"; t.stu.age = 20; t.stu.score = 60; cout << "老师姓名:" << t.name << "老师编号:" << t.id << "老师年龄:" << t.age << "学生姓名:" << t.stu.name << "学生年龄:" << t.stu.age << "学生分数:" << t.stu.score << endl; }
9.5 结构体做函数参数
-
作用:将结构体作为参数向函数中传递
-
传递方式:
- 值传递(不会修改主函数中的数据)
- 地址传递(可以修改主函数中的数据)
#include <iostream> #include <string> using namesapce std; // 1、定义学生结构体 struct Student{ string name; // 学生姓名 int age; // 学生年龄 int score; // 学生分数 } // 打印学生信息函数 // 1、值传递 void printStudent1(struct Student stu){ stu.age = 1000; // 主函数中的s.age不会被改变,只有形参发生变化 cout << "子函数1中 姓名:" << stu.name << "年龄:" << stu.age << "分数:" << stu.score << endl; } // 2、地址传递 // 形参用指针接受地址 void printStudent2(struct Student * p){ p->age = 1000; // 主函数中的s.age会被改变,形参和实参都发生变化 cout << "子函数2中 姓名:" << p->name << "年龄:" << p->age << "分数:" << p->score << endl; } int main(){ // 创建结构体变量 struct Student s; s.name = "张三"; s.age = 20; s.score = 85; cout << "main函数中打印 姓名:" << s.name << "年龄:" << s.age << "分数:" << s.score << endl; // 将结构体变量s传入到一个函数中,打印该结构体变量的信息 // 值传递 printStudent1(s); // 地址传递 printStudent2(&s); }
9.6 结构体中const使用场景
-
作用:防止误操作
// const使用场景 #include <iostream> #include <string> using namesapce std; // 定义结构体 struct Student{ string name; // 学生姓名 int age; // 学生年龄 int score; // 学生分数 } // 打印函数 // 值传递会把结构体完全拷贝一份,如果这个结构体变量包含很大的数据量,那么值传递会将所有数据复制一份,导致占用大量内存 void printStudent(struct Student stu){ cout << "姓名:" << stu->name << "年龄:" << stu->age << "分数:" << stu->score << endl; } // 地址传递则只是传递地址,只占4个字节,从而减少内存空间,而且不会复制新的副本出来 void printStudent(struct Student *stu){ cout << "姓名:" << stu->name << "年龄:" << stu->age << "分数:" << stu->score << endl; } // 但是,地址传递存在一个隐患:在子函数中修改形参会直接修改主函数中的实参 void printStudent(struct Student *stu){ stu->age = 1000; // 实参也被修改!!! cout << "姓名:" << stu->name << "年龄:" << stu->age << "分数:" << stu->score << endl; } // 解决办法:加入const void printStudent(const struct Student *stu){ // stu->age = 1000; // 修改操作会报错!!!防止误操作 cout << "姓名:" << stu->name << "年龄:" << stu->age << "分数:" << stu->score << endl; } int main(){ // 创建结构体变量 struct Student s = {"张三", 15, 70}; // 通过函数打印结构体变量信息 printStudent(s); }
十、内存分区模型
-
C++程序在执行时,将内存大方向划分为4个区域
- 代码区:存放函数体的二进制代码,由操作系统进行管理的
- 全局区:存放全局变量和静态变量以及常量
- 栈区:由编译器自动分配释放,存放函数的参数值,局部变量等
- 堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收
-
内存四区意义:
- 不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程
10.1 程序运行前
-
在程序编译后,生成了exe可执行程序,未执行该程序前分为两个区域
- 代码区
- 存放 CPU 执行的机器指令
- 代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可
- 代码区是只读的,使其只读的原因是防止程序意外地修改了它的指令
- 全局区
- 全局变量和静态变量存放在此
- 全局区还包含了常量区, 字符串常量和其他常量也存放在此
- 该区域的数据在程序结束后由操作系统释放
//全局变量 int g_a = 10; int g_b = 10; //全局常量 const int c_g_a = 10; const int c_g_b = 10; int main() { //局部变量 int a = 10; int b = 10; //打印地址 cout << "局部变量a地址为: " << (int)&a << endl; cout << "局部变量b地址为: " << (int)&b << endl; cout << "全局变量g_a地址为: " << (int)&g_a << endl; cout << "全局变量g_b地址为: " << (int)&g_b << endl; //静态变量 // 可以使变量在程序执行期间只初始化一次,并在程序的整个执行期间都保持其值 // 在函数内部声明的静态变量,它的生命周期是整个程序运行时间,但是它的可见范围仅限于声明它的函数 static int s_a = 10; static int s_b = 10; cout << "静态变量s_a地址为: " << (int)&s_a << endl; cout << "静态变量s_b地址为: " << (int)&s_b << endl; cout << "字符串常量地址为: " << (int)&"hello world" << endl; cout << "字符串常量地址为: " << (int)&"hello world1" << endl; cout << "全局常量c_g_a地址为: " << (int)&c_g_a << endl; cout << "全局常量c_g_b地址为: " << (int)&c_g_b << endl; const int c_l_a = 10; const int c_l_b = 10; cout << "局部常量c_l_a地址为: " << (int)&c_l_a << endl; cout << "局部常量c_l_b地址为: " << (int)&c_l_b << endl; return 0; }
- 代码区
10.2 程序运行后
-
栈区:
- 由编译器自动分配释放,存放函数的参数值,局部变量等
- 注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放
-
堆区:
- 由程序员分配释放,若程序员不释放,程序结束时由操作系统回收
- 在C++中主要利用new在堆区开辟内存
-
new
-
在堆区开辟数据
-
堆区开辟的数据,由程序员手动开辟,手动释放,释放利用操作符delete
-
语法:
new 数据类型
-
利用new创建的数据,会返回数据对应的类型的指针
int* func() { int* a = new int(10); return a; } int main() { int *p = func(); cout << *p << endl; cout << *p << endl; //利用delete释放堆区数据 delete p; //cout << *p << endl; //报错,释放的空间不可访问 return 0; }
-
开辟数组
//堆区开辟数组 int main() { int* arr = new int[10]; for (int i = 0; i < 10; i++) { arr[i] = i + 100; } for (int i = 0; i < 10; i++) { cout << arr[i] << endl; } //释放数组 delete 后加 [] delete[] arr; return 0; }
-
-
十一、通讯录管理系统
-
主函数
#include <iostream> #include "addressBooksSystem.h" using namespace std; int main() { // 创建通讯录结构体变量 Addressbooks abs; abs.m_Size = 0; // 用户选择输入变量 int select = 0; while (true) { // 调用菜单 showMenu(); cin >> select; switch (select) { case 1: // 1,添加联系人 addPerson(&abs); // 利用地址传递可以修饰实参 break; case 2: // 2,显示联系人 showPerson(&abs); break; case 3: // 3,删除联系人 deletePerson(&abs); break; case 4: // 4,查找联系人 findPerson(&abs); break; case 5: // 5,修改联系人 modifyPerson(&abs); break; case 6: // 6,清空联系人 cleanPerson(&abs); break; case 0: cout << "欢迎下次使用" << endl; system("pause"); return 0; break; default: break; } } system("pause"); return 0; }
-
头文件 addressBooksSystem.h
#pragma once #include <iostream> #include <string> using namespace std; #define MAX 1000 // 宏常量,通讯录的最大容量,方便数据管理 // 设计联系人结构体 struct Person { string m_Name; // 姓名 int m_Sex; // 性别,1-男,2-女 int m_Age; // 年龄 string m_Phone; // 电话 string m_Addr; // 住址 }; // 设计通讯录结构体 struct Addressbooks { struct Person PersonArray[MAX]; // 联系人数组,定义一个宏常量MAX方便数据管理 int m_Size; // 记录联系人个数 }; void showMenu(); // 菜单界面 void addPerson(struct Addressbooks* abs); // 添加联系人 void showPerson(struct Addressbooks* abs); // 显示所有联系人 int isExist(struct Addressbooks* abs, string name); // 检测联系人是否存在 void deletePerson(struct Addressbooks* abs); // 删除指定联系人 void findPerson(struct Addressbooks* abs); // 查找联系人 void modifyPerson(struct Addressbooks* abs); // 修改联系人信息 void cleanPerson(struct Addressbooks* abs); // 清空联系人
-
源文件 addressBooksSystem.cpp
#include "addressBooksSystem.h" // 菜单界面 void showMenu() { cout << "**************************" << endl; cout << "***** 1,添加联系人 *****" << endl; cout << "***** 2,显示联系人 *****" << endl; cout << "***** 3,删除联系人 *****" << endl; cout << "***** 4,查找联系人 *****" << endl; cout << "***** 5,修改联系人 *****" << endl; cout << "***** 6,清空联系人 *****" << endl; cout << "***** 0,退出通讯录 *****" << endl; cout << "**************************" << endl; } // 添加联系人 void addPerson(struct Addressbooks* abs) { // 判断通讯录是否已满,如果满了就不再添加 if (abs->m_Size == MAX) { cout << "通讯录已满,无法添加!!!" << endl; return; } else { // 添加具体联系人 // 姓名 string name; cout << "请输入姓名:" << endl; cin >> name; abs->PersonArray[abs->m_Size].m_Name = name; // 性别 cout << "请输入性别:" << endl; cout << "1 --- 男" << endl; cout << "2 --- 女" << endl; int sex = 0; while (true) { // 如果输入的是1或者2,可以退出循环,因为输入的是正确值 // 如果输入有误,则重新输入 cin >> sex; if (sex == 1 || sex == 2) { abs->PersonArray[abs->m_Size].m_Sex = sex; break; } cout << "输入有误,请重新输入" << endl; } // 年龄 cout << "请输入年龄:" << endl; int age = 0; cin >> age; abs->PersonArray[abs->m_Size].m_Age = age; // 电话 cout << "请输入电话:" << endl; string phone; cin >> phone; abs->PersonArray[abs->m_Size].m_Phone = phone; // 住址 cout << "请输入家庭住址:" << endl; string address; cin >> address; abs->PersonArray[abs->m_Size].m_Addr = address; // 更新通讯录人数 abs->m_Size++; cout << "添加成功" << endl; // 请按任意键继续 system("pause"); // 清屏 system("cls"); } } // 显示所有联系人 void showPerson(struct Addressbooks* abs) { // 判断通讯录中人数是否为0,如果为0,提示记录为空 // 如果不为0,显示记录的联系人信息 if (abs->m_Size == 0) { cout << "当前记录为空" << endl; } else { for (int i = 0; i < abs->m_Size; i++) { cout << "姓名:" << abs->PersonArray[i].m_Name << "\t"; cout << "性别:" << (abs->PersonArray[i].m_Sex == 1 ? "男" : "女") << "\t"; cout << "年龄:" << abs->PersonArray[i].m_Age << "\t"; cout << "电话:" << abs->PersonArray[i].m_Phone << "\t"; cout << "地址:" << abs->PersonArray[i].m_Addr << endl; } } system("pause"); system("cls"); } // 检测联系人是否存在,如果存在,返回联系人所在数组中的具体位置,不存在返回-1 // 参数1 通讯录 参数2 对比姓名 int isExist(struct Addressbooks* abs, string name) { for (int i = 0; i < abs->m_Size; i++) { // 找到用户输入的姓名了 if (abs->PersonArray[i].m_Name == name) //返回这个人在数组中的下标编号 return i; } // 如果遍历所有人都没找到用户输入的姓名,则不存在,返回-1 return -1; } // 删除指定联系人 void deletePerson(struct Addressbooks* abs) { cout << "请输入您要删除的联系人" << endl; string name; cin >> name; // ret == -1 未查到;ret != -1 查到了 int ret = isExist(abs, name); if (ret != -1) { // 查找到此人,要进行删除操作 for (int i = ret; i < abs->m_Size; i++) { abs->PersonArray[i] = abs->PersonArray[i + 1]; //数据前移,执行删除 } // 人数减一,更新通讯录人数 abs->m_Size--; cout << "删除成功" << endl; } else { cout << "查无此人" << endl; } system("pause"); system("cls"); } // 查找联系人 void findPerson(struct Addressbooks* abs) { cout << "请输入您要查找的联系人姓名:" << endl; string inputname; cin >> inputname; int ret = isExist(abs, inputname); // 找到了联系人 if (ret != -1) { cout << "姓名:" << abs->PersonArray[ret].m_Name << "\t"; cout << "性别:" << (abs->PersonArray[ret].m_Sex == 1 ? "男" : "女") << "\t"; cout << "年龄:" << abs->PersonArray[ret].m_Age << "\t"; cout << "电话:" << abs->PersonArray[ret].m_Phone << "\t"; cout << "地址:" << abs->PersonArray[ret].m_Addr << endl; } // 未找到联系人 else { cout << "查无此人" << endl; } system("pause"); system("cls"); } // 修改联系人信息 void modifyPerson(struct Addressbooks* abs) { cout << "请输入您要修改的联系人姓名:" << endl; string inputname; cin >> inputname; int ret = isExist(abs, inputname); // 找到了 if (ret != -1) { cout << "1:修改姓名" << endl; cout << "2:修改性别" << endl; cout << "3:修改年龄" << endl; cout << "4:修改电话" << endl; cout << "5:修改地址" << endl; cout << "0:保存退出" << endl; while (true) { int modifyselect = -1; cout << "请输入您的选择:" << endl; cin >> modifyselect; switch (modifyselect) { case 1: { string newName; cout << "请输入修改后的姓名:" << endl; cin >> newName; abs->PersonArray[ret].m_Name = newName; } break; case 2: { cout << "请输入修改后的性别:" << endl; cout << "1 --- 男" << endl; cout << "2 --- 女" << endl; int newSex = 0; while (true) { cin >> newSex; if (newSex == 1 || newSex == 2) { abs->PersonArray[ret].m_Sex = newSex; break; } else { cin.clear(); cin.ignore(); //输入字母或中文里防止死循环 cout << "输入有误,请重新输入:" << endl; } } } break; case 3: { cout << "请输入修改后的年龄:" << endl; int newAge = 0; while (true) //无限循环,直到输入正确再退出 { cin >> newAge; if (newAge > 0 && newAge < 120) { abs->PersonArray[ret].m_Age = newAge; break; } else { cin.clear(); cin.ignore(); cout << "输入有误,请重新输入:" << endl; } } } break; case 4: { cout << "请输入修改后的电话:" << endl; string newPhone; cin >> newPhone; abs->PersonArray[ret].m_Phone = newPhone; } break; case 5: { cout << "请输入修改后的地址:" << endl; string newAddress; cin >> newAddress; abs->PersonArray[ret].m_Addr = newAddress; } break; case 0: cout << "修改成功" << endl; system("pause"); system("cls"); return; break; default: break; } } } else { cout << "查无此人" << endl; } system("pause"); system("cls"); } // 清空联系人 void cleanPerson(struct Addressbooks* abs) { // 将当前记录联系人数量置为0,做逻辑清空操作 abs->m_Size = 0; cout << "通讯录已清空" << endl; system("pause"); system("cls"); }