一、C++基础入门

一、C++初识

1、注释

单行注释://

多行注释:/**/

2、变量

作用:给一段指定的内存空间起名,方操作这段内存

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

示例

#include <iostream>
using namespace std;

int main()
{
    // 数据类型  变量名 = 初始值;
    int a = 0;
	system("pause");
	return 0;
}

3、常量

作用:用于记录不可更改的数据

定义:c++两种定义常量的方式

1. #define宏常量:#define  常量名  常量值
 - 通常在文件上方定义,表示一个常量
2. const修饰的变量:const  数据类型  常量名  =  常量值
 - 通常在定义前加关键字const,修饰该变量为常量,且不可修改

示例

#include <iostream>
using namespace std;

// 常量的定义方式
// 1、#define  宏常量
#define Day 7

int main()
{
	cout << "一周总共有" << Day<< "天" <<endl;

	// 2、const修饰的变量
	const int month = 12;
	cout << "一年共有" << month << "个月" << endl;

	system("pause");
	return 0;
}

注意:当一个数据被定义成常量后就不可再更改

4、关键字

作用:关键字是c++中预先保留的字符

注意:在定义变量和常量名的时候不可以使用关键字

c++关键字

asm do if return typedef
auto double inline short typeid
bool dynamic_cast int signed typename
break else long sizeof union
case enum mutable static unsigned
catch explicit namespace static_cast using
char export new struct virtual
class extern operator switch void
const false private template volatile
const_cast float protected this wchar_t
continue for public throw while
default friend register true
delete goto reinterpret_cast try

5、标识符命名规则

作用:c++规定给标识符(变量、常量)命名 时,有一定的规范

  • 标识符不能是关键字
  • 标识符只能有字母、数字、下划线组成
  • 第一个字符必须为字母或者下划线
  • 标识符中字母区分大小写

注意:再命名时,最好做到见名知意,方便自己和他人阅读

二、常用关键字

1、cout——输出语句

作用:在黑窗口打印输出的数据

语法:cout << 字符串\变量名;

示例:

#include <iostream>
using namespace std;

int main()
{
    int a = 10;
	cout << "hello word";
    cout << a;
    system("pause");
	return 0;
}

2、endl——换行

作用:与\n作用一样

示例

#include <iostream>
using namespace std;

int main()
{
	cout << "hello word" << endl;
    system("pause");
	return 0;
}

3、sizeof——统计字节数

作用:可以统计出数据类型所占用的内存大小

语法sizeof(数据类型/变量)

示例

#include <iostream>
using namespace std;

int main()
{
	short num1 = 11;
	cout <<"short占用的内存空间为" << sizeof(short) << "个字节" << endl;  // 2
	cout <<"short占用的内存空间为" << sizeof(num1) << "个字节" << endl;  // 2

	int num2 = 22;
	cout << "int占用的内存空间为" << sizeof(int) << "个字节" << endl;  // 4
	cout << "int占用的内存空间为" << sizeof(num2) << "个字节" << endl;  // 4

	long num3 = 33;
	cout << "long占用的内存空间为" << sizeof(long) << "个字节" << endl;  // 4
	cout << "long占用的内存空间为" << sizeof(num3) << "个字节" << endl;  // 4

	long long num4 = 44;
	cout << "long long 占用的内存空间为" << sizeof(long long) << "个字节" << endl;  // 8
	cout << "long long 占用的内存空间为" << sizeof(num4) << "个字节" << endl;  // 8

	system("pause");
	return 0;
}

4、cin——输出语句

作用:获取用户输入的内容

语法:cin >> 变量名;

示例

#include <iostream>
#include <string>
using namespace std;

int main()
{

	string name;
	string gender;
	int age;
	cout << "输入你的姓名" << endl;
	cin >> name;
	cout << "输入你的性别" << endl;
	cin >> gender;
	cout << "输入你的年龄" << endl;
	cin >> age;
	cout << "我叫" << name<< ",性别:" << gender << ",今年" << age << "岁了。" << endl;

	system("pause");
	return 0;
}

5、typeid——显示数据类型名称

作用:字符的形式输出数据类型的名称

语法:typeid(变量名).name()

示例

#include<iostream>
#include<string>
using namespace std;

void test()
{
	int a = 10;
	string b = "aaa";
	char c = 'a';
	double d = 2.11;
	cout << typeid(a).name() << endl;
	cout << typeid(b).name() << endl;
	cout << typeid(c).name() << endl;
	cout << typeid(d).name() << endl;
}

int main()
{
	test();

	return 0;
}

三、基本数据类型

1、整型

作用:表示整数类型的数据

c++中能够表示整型的几种关键字

数据类型 占用空间 取值范围
short(短整型) 2字节 (-215~215-1)
int(整型) 4字节 (-231~231-1)
long(长整型) windows为4字节,Linux4字节(32位),8字节(64位) (-231~231-1)
long long(长长整型) 8字节 (-263~263-1)

根据字节长度不同选择合适的类型

注意:当存储数据的长度超过整型能容纳的字节时,会回到最下限

#include <iostream>
using namespace std;

int main()
{
	short num = 32768;
	cout <<"num=" << num << endl;

	system("pause");
	return 0;
}
// 打印的结果是-32768

2、浮点型(实型)

作用:用来表示小数

浮点型有两种数据类型

  1. 单精度:float
  2. 双精度:double
数据类型 占用空间 有效数字范围 数值范围
float 4字节 7位有效数字 -3.4e38~3.4e38
double 8字节 15~16位有效数字 -2.23e308~1.97e308

有效数字范围:单精度浮点数最多有7位十进制有效数字,如果某个数的有效数字超过7位,当把它定义为单精度变量时,超出的部分会自动四舍五入;双精度可以表示十进制的位数有15~16个有效数字,超出部分也会自动四舍五入

科学计数法:e表示10的多少次方,3.4e38表示3.4乘以10的38次方;3.4e-38表示3.4乘以0.1的38次方

示例

#include <iostream>
using namespace std;

int main()
{
	/* 
	定义一个小数变量的时候,系统会默认他是双精度的,当我们把这个变量定义成单精度时
	会多出来一步双精度转换单精度的过程
	所以在定义单精度变量时,可以在小数后面加一个f, 表示这是一个单精度小数
	运行程序时就可以少一个转换的过程
	*/
	float f1 = 3.14f;
	double d1 = 3.14;

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

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

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

	system("pause");
	return 0;
}

3、字符型

作用:字符型用来显示单个字符

语法:char 变量名 = '单个字符';

注意:

	- 创建字符型的时候要用单引号
	- 只能放一个字符,放多了会报错
	- 字符型变量不是把字符本身放到内存中,而是将对应的ASCII编码放到存储单元中
	- c和c++中字符型变量只占用1个字节

示例

#include <iostream>
using namespace std;

int main()
{
	char ch = 'a';
	cout << ch << endl;

	// 查看字符对应的ASCII编码
	cout << int(ch) << endl;

	system("pause");
	return 0;
}

4、转义字符

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

转义字符 含义 ASCII码(十进制)
\a 警报 007
\h 退格(BS),将当前位置移到前一列 008
\f 换页(LF),将当前位置移到下页开头 012
\n 换行(LF),将当前位置移到下一行开头 010
\r 回车(CR),将当前位置移到本行开头 013
\t 水平制表(HT),跳到下一个TAB位置 009
\v 垂直制表(VT) 011
\\ 一个反斜杠 092
\' 一个单引号 039
\" 一个双引号 034
? 一个问号 063
\0 数字0 000
\ddd 八进制转义字符,d范围0~7 3位八进制
\xhh 十六进制转义符,h范围09,af,A~F 3位十六进制

示例

#include <iostream>
using namespace std;

int main()
{
	// 换行 \n
	cout << "你好,世界\n";

	// 水平制表  \t
	cout << "aa\t你好世界" << endl;
	cout << "aaa\t你好世界" << endl;
	cout << "aaaa\t你好世界" << endl;
    /*
    aa      你好世界
	aaa     你好世界
	aaaa    你好世界
	*/

	system("pause");
	return 0;
}

5、字符串类型

作用:用来存储多个字符

字符串类型有两种写法

  1. c语言风格

    语法:char 变量名[] = "数据";

    注意:

     - 变量名后面要加中括号[]
     - 数据要用双引号括起来
    

    示例

    #include <iostream>
    using namespace std;
    
    int main()
    {
    	char str1[] = "你好世界";
    	cout << str1 << endl;
    
    	system("pause");
    	return 0;
    }
    
  2. c++风格

    语法:string 变量名 = "数据";

    注意:使用string关键字时要加头文件#include <string>

    示例

    #include <iostream>
    #include <string>
    using namespace std;
    
    int main()
    {
    	string str = "你好世界";
    	cout << str << endl;
    
    	system("pause");
    	return 0;
    }
    

6、布尔类型

作用:用来表示一个值的真或假

真 —— true —— 1

假 ——false —— 0

语法:bool 变量名 = 数据;

bool类型只占一个字节

示例

#include <iostream
using namespace std;

int main()
{
	bool a = true;
	cout << a << endl;  // 1

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

	system("pause");
	return 0;
}

四、运算符

1、算术运算符

作用:处理四则运算

运算符 意义
+
-
*
/
% 取模(取余)
++ 自增
-- 自减

注意:

  • 整数相除时只会保留整数部分,小数相除时可以保留小数部分
  • 做除法运算时除数不可以为0,也就是 ”/“ 后面的数不可以为0
  • 做取模运算时除数不可以为0,也就是 ”/“ 后面的数不可以为0
  • i ++ / i -- 和 ++ i / -- i是有区别的,i ++/ i -- 是先赋值后加减,++ i / -- i是先加减后赋值

示例

#include <iostream>
using namespace std;

int main()
{
	int a = 10;
	int b = 3;

	/*加减乘除*/
	cout << a + b << endl;  // 13
	cout << a - b << endl;  // 7
	cout << a * b << endl;  // 30

	// 整数相除时只会保留整数部分
	cout << a / b << endl;  // 3

	// 小数相除时保留小数
	cout << 2.22 / 3.14 << endl;  // 0.707006

	/*取模*/
	cout << a % b << endl;  // 1
	cout << b % a << endl;  // 3

	/*自增自减*/
	int i = 1;
	// i++,先赋值再自增1,所以i打印出来的结果为1,但是他的值经过自增后为2
	cout << i++ << endl;  // 1
	// ++i,先自增1再赋值,因为前面i已经加1了,所以i的值为2,然后进行自增,i的值为3,最后赋值给i,打印出来的结果就是3
    // i--和--i同上理
	cout << ++i << endl;  // 3
	 
	system("pause");
	return 0;
}

2、赋值运算符

作用:将表达式的值赋给变量

运算符 意义 示例 等同于
= 赋值
+= 加等于 a += 2 a = a + 2
-= 减等于 a -= 2 a = a - 2
*= 乘等于 a *= 2 a = a * 2
/= 除等于 a /= 2 a = a / 2
%= 模等于 a %= 2 a = a % 2
#include <iostream>
using namespace std;

int main()
{
	int a = 10;
	// a = a + 2
	a += 2;
	cout << a << endl;
	
	system("pause");
	return 0;
}

3、比较运算符

作用:用于表达式的比较,返回真或假

运算符 意义
== 相等于
!= 不等于
< 小于
> 大于
<= 小于等于
>= 大于等于

示例

#include <iostream>
using namespace std;

int main()
{
	int a = 10;
	int b = 20;
    // 把式子用括号括起来提升优先级,先进行比较运算再通过endl换行
	cout << (a == b) << endl;  // 0
	cout << (a > b) << endl;  // 0
	cout << (a <= b) << endl;  // 1
	cout << (a != b) << endl;  // 1
	
	system("pause");
	return 0;
}

4、逻辑运算符

作用:根据表达式的bool值返回真或假

运算符 意义 示例 结果
&& a&&b a和b的值都为真,则结果为真,否则为假
|| a||b a和b的值有一个为真,则结果为真,否则为假
! !a 对a的值取反,a的值是真则结果为假,a的值是假则结果为真

示例

#include <iostream>
using namespace std;

int main()
{
	int a = 1;
	int b = 0;
	// 与
	cout << (a && b) << endl;  // 0

	// 或
	cout << (a || b) << endl;  // 1

	// 非
	cout << !a << endl;  // 0
	
	system("pause");
	return 0;
}

五、流程控制结构

c/c++支持最基本的三种程序运行结构:顺序结构、选择结构、循环结构

  • 顺序结构:程序按照顺序执行,不发生跳转
  • 选择结构:依据条件是否满足,有选择的执行相应功能
  • 循环结构:依据条件是否满足,循环多次执行某段代码

1、选择结构

1.1、if语句

作用:执行满足条件的语句

  • 单行格式if语句
  • 多行格式if语句
  • 多条件的if语句

1、单行格式if语句

语法:if(条件){条件满足执行的代码}

示例

#include <iostream>
using namespace std;

int main()
{
	// 定义变量,用来接收等级
	int lv;
	cout << "输入当前等级" << endl;
	// 用户输入等级
	cin >> lv;
	// 判断用户输入的等级是否大于等于60
	if (lv >= 60) {
		// 判断结果为真执行该语句
		cout << "恭喜你成功转职" << endl;
	}
	
	system("pause");
	return 0;
}

2、多行格式的if语句

语法:if(条件){条件满足执行的语句}else{条件不满足执行的语句}

示例

#include <iostream>
using namespace std;

int main()
{
	// 定义变量,用来接收等级
	int lv;
	cout << "输入当前等级" << endl;
	// 用户输入等级
	cin >> lv;
	// 判断用户输入的等级是否大于等于60
	if (lv >= 60) {
		// 判断结果为真执行该语句
		cout << "恭喜你成功转职" << endl;
	}
	else {
		// 判断结果为假执行该语句
		cout << "等级不够,无法转职" << endl;
	}
	
	system("pause");
	return 0;
}

3、多条件的if语句

语法:if(条件1){满足条件1执行的语句}else if(条件2){满足条件2执行的语句}else if(条件3){满足条件3执行的语句}...else{上述条件都不满足执行的语句}

#include <iostream>
using namespace std;

int main()
{
	// 定义变量,用来接收魂力等级
	int lv;
	cout << "输入当前等级" << endl;
	// 用户输入等级
	cin >> lv;
	// 
	if (lv <= 0) {
		cout << "一介凡人" << endl;
	}
	else if (lv <= 10) {
		cout << "魂士" << endl;
	}
	else if (lv <= 20) {
		cout << "魂师" << endl;
	}
	else if (lv <= 30) {
		cout << "大魂师" << endl;
	}
	else {
		cout << "小小县城居然有30级以上的大佬" << endl;
	}
	
	system("pause");
	return 0;
}

4、if嵌套

#include <iostream>
using namespace std;

int main()
{
	// 定义变量
	int score;
	cout << "输入你的分数" << endl;
    // 获取用户输入
	cin >> score;
    // 条件1判断是否上本科
	if (score <= 400) {
		cout << "很遗憾没有上本科" << endl;
	}
    // 条件二判断是否上一本
	else if (score>500) {
        // if嵌套,判断是否考上了流弊的一本大学
		if (score > 650) {
			cout << "恭喜你上了清华" << endl;
		}
        // 考了普通的一本
		else {
			cout << "恭喜你上了一本" << endl;
		}
	}else{
        // 考上了本科
        cout << "恭喜你上了本科" << endl;
    }
	
	system("pause");
	return 0;
}

5、案例

有三只体重不相等的小猪,通过if判断和if嵌套,得出体重最重的那个小猪

#include <iostream>
using namespace std;

int main()
{
	int a;
	int b;
	int c;
	cout << "a猪的重量" << endl;
	cin >> a;
	cout << "b猪的重量" << endl;
	cin >> b;
	cout << "c猪的重量" << endl;
	cin >> c;
	if (a > b) {
		if (a > c) {
			cout << "a猪最重" << endl;
		}
		else {
			cout << "c猪最重" << endl;
		}
	}
	else if (b > c) {
		cout << "b猪最重" << endl;
	}
	else {
		cout << "c猪最重" << endl;
	}

	system("pause");
	return 0;
}

1.2、三目运算符

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

语法:表达式1 ? 表达式2 : 表达式3

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

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

示例1

#include <iostream>
using namespace std;

int main()
{
	// 当分数大于450时考上本科
	int mark;
	cout << "输入你的分数" << endl;
	cin >> mark;
	mark > 450 ? cout << "恭喜你考上了本科" << endl : cout << "很遗憾没有考上本科" << endl;

	system("pause");
	return 0;
}

再三目运算符中返回的时变量,可以继续赋值

示例2

#include <iostream>
using namespace std;

int main()
{
	/*
	判断a和b的大小,a大于b时返回a乘b的结果,a小于b时返回a加b的结果
	当最后的结果大于100时返回TRUE,反之返回FALSE
	*/
	int a;
	int b;
	cout << "依次输入a和b的值" << endl;
	cin >> a;
	cin >> b;
	(a > b ? a * b : a + b) > 100 ? cout << "TURE" << endl : cout << "FALSE" << endl;

	system("pause");
	return 0;
}

1.3、switch语句

作用:执行多条件语句

语法

switch(表达式){
        // 当表达式的结果满足条件1时,运行执行语句1的代码
        case 条件1:执行语句1;break;
        // 当表达式的结果满足条件2时,运行执行语句2的代码
        case 条件2:执行语句2;break;
        // 当表达式的结果满足条件3时,运行执行语句3的代码
        case 条件3:执行语句3;break;
        ...
        // 当所有条件都不满足结果时执行default后面的代码
        default:执行语句;break;
}

注意:case里如果没有break,那么程序就会一直向下执行

示例

#include <iostream>
using namespace std;

int main()
{
	// 根据不同的星期上不一样的课
	int work;
	cout << "今天星期几" << endl;
	cin >> work;
	switch (work) {
	case 1:
		cout << "Java" << endl;
		break;
	case 2:
		cout << "Linux" << endl;
		break;
	case 3:
		cout << "MySQL" << endl;
		break;
	case 4:
		cout << "C++" << endl;
		break;
	case 5:
		cout << "Python" << endl;
		break;
	default:
		cout << "休息" << endl;
	}
	

	system("pause");
	return 0;
}

2、循环结构

2.1、while循环

作用:满足循环条件,执行循环语句

语法:while(循环条件){循环语句}

当循环条件为真时,执行循环语句,直到循环条件为假,则循环结束

示例

#include <iostream>
using namespace std;

int main()
{
	// 循环打印1~9
	int i = 1;
	while (i < 10) {
		cout << i << endl;
		i++;
	}
	

	system("pause");
	return 0;
}

while循环案例:系统随机生成1~100的数字,让用户来猜,猜对了退出去,猜错了提示猜大了还是猜小了,当猜的次数大于等于五次时也退出循环,游戏失败

#include <iostream>
#include <ctime>
using namespace std;

int main()
{
	// 添加随机数种子,利用当前系统时间生成随机数,防止每次随机数都一样
	// 使用time关键字需要添加头文件  #include <ctime>
	srand((unsigned)time(NULL));


	// rand()%,可以生成0~99的随机数,想要生成1~99的随机数加1就可以了
	// 这只是一个伪随机数,每次生成的随机数是一样的,要加一个随机数种子就可以生成不一样的随机数
	int num = rand() % 100 + 1;
	int val;
	int i = 0;
	while (1) {
		i++;
		if (i > 5) {
			cout << "游戏失败,数字大小为:" << num << endl;
			break;
		}
		cout << "输入猜的数字" << endl;
		cin >> val;
		if (val == num) {
			cout << "恭喜你猜对了" << endl;
			// 退出循环
			break;
		}
		else if (val < num) {
			cout << "猜小了" << endl;
		}
		else if (val > num) {
			cout << "猜大了" << endl;
		}
	}
	

	system("pause");
	return 0;
}

2.2、do...while循环语句

作用:满足循环条件,执行循环语句

语法:do{循环语句} while(循环条件)

注意:与while循环的区别在于do...while会先执行一次循环语句,再判断循环条件是否满足

示例

#include <iostream>
using namespace std;

int main()
{
	int i = 0;
	do {
		cout << i << endl;
		i++;
	} while (i < 10);

	system("pause");
	return 0;
}

循环案例

水仙花数:水仙花数是指一个3位数,他的每个位上数字的3次幂之和等于它本身
例如:1^3 + 5^3 + 3^3=153

#include <iostream>
using namespace std;

int main()
{
	/*水仙花数:水仙花数是指一个3位数,他的每个位上数字的3次幂之和等于它本身
	例如:1^3 + 5^3 + 3^3=153*/
	// 定义i的起始值为100
	int i = 100;
	// 每循环一次i加1,直到i = 999为止
	while (i < 999) {
		i++;
		// 获取这个整数的百位数
		int i1 = i / 100;

		// 获取这个整数的十位数
		int i2 = i / 10 % 10;

		// 获取这个整数的个位数
		int i3 = i % 10;

		// 把这个整数的个位数、十位数、百位数分别乘以3立方再相加
		int ii = (i1 * i1 * i1) + (i2 * i2 * i2) + (i3 * i3 * i3);

		// 一个3位数上的每个位上的数字3次幂之和等于他的本身时,他就是水仙花数
		if (ii == i) {
			cout << i << endl;
		}
	}

	system("pause");
	return 0;
}
/*水仙花数有:153,370,371,407*/

2.3、for循环

作用:满足循环条件,执行循环语句

语法:for(起始表达式;条件表达式;末尾表达式){循环语句}

示例:

#include <iostream>
using namespace std;

int main()
{
	for (int i = 0; i < 10; i++) {
		cout << i << endl;
	}

	system("pause");
	return 0;
}

案例

敲桌子:从1开始数到100,如果数字个位、十位含有7,或者该数字是7的倍数我们就打印敲桌子,其与数字打印输出

#include <iostream>
using namespace std;

int main()
{
	/*敲桌子:从1开始数到100,如果数字个位、十位含有7,或者该数字是7的倍数
	我们就打印敲桌子,其与数字打印输出*/
	for (int i = 1; i <= 100; i++) {
		// 如果十位有7、个位有7、或者是7的倍数,打印敲桌子
		if ((i % 10 == 7) || (i / 10 == 7) || (i % 7 == 0)) {
			cout << "敲桌子" << endl;
		}
		else {
			cout << i << endl;
		}
	}

	system("pause");
	return 0;
}

for循环嵌套

案例

九九乘法表

#include <iostream>
using namespace std;

int main()
{
	// 九九乘法表
	for (int i = 1; i < 10; i++) {
		for (int j = 1; j <= i; j++) {
			cout << j << "*" << i << "=" << i * j<< "\t";
		}
		cout << endl;
	}

	system("pause");
	return 0;
}

3、跳转语句

3.1、break语句

作用:用于结束选择结构或者循环结构

break使用的时候

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

3.2、continue语句

作用:在循环语句中,跳过本次循环,重新开始新的一轮循环

示例

#include <iostream>
using namespace std;

int main()
{
	// 验证密码
	int i = 123;
	int password;
	while (1) {
		cout << "输入密码" << endl;
		cin >> password;
		if (password == i) {
			cout << "密码验证成功" << endl;
			// 秘密验证成功退出循环
			break;
		}
		else {
			cout << "密码错误" << endl;
			// 密码验证失败,重新开始循环
			continue;
		}
	}

	system("pause");
	return 0;
}

3.3、goto语句

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

语法:goto 标记

注意:

  • 我们约定俗成,标记使用全大写来命名
  • 在程序中尽量少的使用,因为会影响代码的可阅读性

示例

#include <iostream>
using namespace std;

int main()
{
	cout << "1" << endl;
	cout << "2" << endl;
	// 告诉程序我要开始跳转了
	goto TO;
	cout << "3" << endl;
	cout << "4" << endl;
	// 直接运行下面的代码,中间的代码跳过了
	TO:
	cout << "5" << endl;
	
	system("pause");
	return 0;
}
/*
最后的打印结果是
1
2
5
*/

六、数组

1、概述

就是一个集合,里面存放了相同类型的数据类型

特点1:数组中的每个数据元素都是相同的数据类型

特点2:数组是由联系的内存位置组成的

2、一维数组

2.1、一维数组定义与查看

定义一维数组的三种方式

  1. 数据类型 数组名[ 数组长度 ]
  2. 数据类型 数组名[数组长度] = {值1,值2,值3...}
  3. 数据类型 数组名[] = {值1,值2,值3...}

示例

#include <iostream>
using namespace std;

int main()
{
	//1、数据类型  数组名[ 数组长度 ]
	int arr1[3];
	// 为数组赋值
	arr1[0] = 1;
	arr1[1] = 2;
	arr1[2] = 3;
	
	// 2、`数据类型  数组名[数组长度] = {值1,值2,值3...}`
	// 在初始化数据的时候,定义的数组长度大于数组实际的数据时,会用0补全
	int arr2[3] = { 1,2,3};

	// 3、`数据类型  数组名[] = {值1,值2,值3...}`
	int arr3[] = { 1,2,3,4,5 };

	system("pause");
	return 0;
}

查看数组内的数据

#include <iostream>
using namespace std;

int main()
{
	// 查看数组内容
	int arr[] = { 1,2,3,4,5 };
	// 查看单个数据
	cout << arr[0] << endl;
	cout << arr[1] << endl;
	// 查看多个数据
	for (int i = 0; i < 5; i++) {
		cout << arr[i] << endl;
	}

	system("pause");
	return 0;
}

2.2、一维数组组名的用途

  1. 可以统计整个数组在内存中的长度
  2. 可以获取数组在内存中的首地址

注意:再查看单个元素的首地址时要加上 "&" 符号

示例

#include <iostream>
using namespace std;

int main()
{
	// 1、可以获取整个数组占用以及单个元素内存空间的大小
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };

	// 整个数组所占的内存空间
	cout << sizeof(arr) << endl;

	// 单个元素所占的内存空间
	cout << sizeof(arr[0]) << endl;

	// 数组的元素个数
	cout << sizeof(arr) / sizeof(arr[0]) << endl;


	// 2、可以通过数组名获取到数组首地址和单个元素的首地址
	// 整个数组的首地址
	cout << arr << endl;

	// 数组内某个元素的首地址
	// 在前面加上  "&"  符号就可以查看单个元素的首地址
	cout << &arr[0] << endl;
	cout << &arr[1] << endl;

	system("pause");
	return 0;
}

一维数组案例

  • 算出一个数组中的最大值
#include <iostream>
using namespace std;

int main()
{
	// 定义一个变量
	int max;
	// 定义一个整型一维数组
	int list[] = { 450,250,666,888,1314 };
	// 把数组中第一个值赋给变量
	max = list[0];
	// 循环数组中的每一个元素
	for (int i = 0; i < sizeof(list) / sizeof(list[0]); i++) {
		// 当max小于当前数组中的值时,把这个值赋给max
		if (max < list[i]) {
			max = list[i];
		}
	}
	cout << max << endl;

	system("pause");
	return 0;
}
  • 数组元素逆置
#include <iostream>
using namespace std;

int main()
{
	// 定义一个数组
	int srr[] = { 1,2,3,4,5 };
	// 定义起始索引
	int start = 0;
	// 定义结束索引,也就是元素个数减一
	int end = sizeof(srr) / sizeof(srr[0]) - 1;
	// 暂时存放数据
	int temp;

	// 当结束索引小于等于起始索引时停止循环
	while (start < end) {
		// 把数组的起始元素存赋值给另一个变量
		temp = srr[start];
		// 把数组中最后一个元素覆盖到数组中的第一个元素上
		srr[start] = srr[end];
		// 拿出存放在起始元素的变量,将他覆盖到末尾的元素上
		srr[end] = temp;
		// 更新元素的起始和结束索引,分别加一和减一
		start++;
		end--;
	}

	// 循环打印所有逆置后的数组元素
	for (int i = 0; i < sizeof(srr) / sizeof(srr[0]); i++) {
		cout << srr[i] << endl;
	}

	system("pause");
	return 0;
}

2.4、冒泡排序

作用:最常用的排序算法,对数组内元素进行排序

升序排列:

  1. 比较相邻的元素,如果第一个比第二个大,就交换他们两个
  2. 对每一对相邻的元素做同样的工作,执行完毕后,即找到第一个最大值
  3. 重复以上的步骤,每次对比次数减一,直到不需要比较

示例

#include <iostream>
using namespace std;

int main()
{
	// 冒泡排序,升序排列下面数组
	int arr[] = { 3,5,2,6,1,0,9,7,8,4 };
	cout << "排序前:";
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
		cout << arr[i] << " ";
	}
	// 暂时存放数据的地方
	int temp;
	// 当前元素个数
	int li = sizeof(arr) / sizeof(arr[0]);
	// 总共有li个元素个数,相邻的两个数两两对比所需的轮数为元素的个数减一
	for (int i = 0; i < li-1; i++) {
		// 每个相邻的两个数对比所需的轮数为元素的个数减一
		for (int j = 0; j < li-1; j++) {
			// 前面的数大于后面的那个数时调换位置
			if (arr[j] > arr[j + 1]) {
				temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
		// 每循环一次,数组就找到当前参与排序的最大值,放在末尾,所以元素个数减一
		li--;
	}
	cout << "排序后:";
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
		cout << arr[i] << " ";
	}

	system("pause");
	return 0;
}

3、二维数组

3.1、二维数组定义与查看

二维数组四种定义方式

  1. 数据类型 数组名[ 行数 ][ 列数 ]
  2. 数据类型 数组名[ 行数 ][ 列数 ] = { { 数据1,数据2 }, { 数据3,数据4 } }
  3. 数据类型 数组名[ 行数 ][ 列数 ] = { 数据1, 数据2,数据3,数据4 }
  4. 数据类型 数组名[ ][ 列数 ] = { 数据1, 数据2,数据3,数据4 }

建议使用第二种方式,更加直观,提高代码可读性

注意:在定义二维数组的时候行数可以省略不写,只写列数

示例

#include <iostream>
using namespace std;

int main()
{	
	// 1. `数据类型 数组名[ 行数 ][ 列数 ]`
	int arr1[2][3];
	arr1[0][0] = 1;
	arr1[0][1] = 2;
	arr1[0][2] = 3;
	arr1[1][0] = 4;
	arr1[1][1] = 5;
	arr1[1][2] = 6;

	// 2. `数据类型 数组名[行数][列数] = { { 数据1,数据2 }, { 数据3,数据4 } }`
	int arr2[2][3] = { {1,2,3},{4,5,6} };

	// 3. `数据类型 数组名[行数][列数] = { 数据1, 数据2,数据3,数据4 }`
	int arr3[2][3] = { 1,2,3,4,5,6 };
	
	// 4. `数据类型 数组名[][列数] = { 数据1, 数据2,数据3,数据4 }`
	int arr4[][3] = { 1,2,3,4,5,6 };

	system("pause");
	return 0;
}

查看二维数组数据

#include <iostream>
using namespace std;

int main()
{	
	int arr[2][3] = { {1,2,3},{4,5,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] << " ";
		}
		cout << endl;
	}

	system("pause");
	return 0;
}

3.2、二维数组名称作用

查看占用内存空间大小

#include <iostream>
using namespace std;

int main()
{
	int arr[2][3] = {
		{1,2,3},
		{4,5,6}
	};
	// 整个二维数组占内存空间的大小
	cout << sizeof(arr) << endl;
	// 第一行占内存空间的大小
	cout << sizeof(arr[0]) << endl;
	// 单个元素占内存空间的大小
	cout << sizeof(arr[0][0]) << endl;

	// 通过上面数据可以算出当前二维数组的行、列和元素的数量
	// 行数  二维数组占用空间除以一行占用的内存空间
	cout << sizeof(arr) / sizeof(arr[0]) << endl;
	// 列数  一行占用的内存空间除以单个元素占用的内存空间
	cout << sizeof(arr[0]) / sizeof(arr[0][0]) << endl;
	// 元素数量  二维数组占用空间除以单个元素占用的内存空间
	cout << sizeof(arr) / sizeof(arr[0][0]) << endl;

	system("pause");
	return 0;
}

查看首地址

注意:

  1. 查看单个元素首地址时要加 "&"
  2. 在前面加 (int) 可以转换成十进制
#include <iostream>
using namespace std;

int main()
{	
	int arr[2][3] = {
		{1,2,3},
		{4,5,6}
	};

	// 二维数组首地址
	cout << arr << endl;
	cout << (int)arr << endl;

	// 一行数据的首地址
	cout << arr[0] << endl;
	cout << (int)arr[0] << endl;

	// 单个元素的首地址
	cout << &arr[0][0] << endl;
	cout << (int)&arr[0][0] << endl;

	system("pause");
	return 0;
}

二维数组案例

姓名 数学 语文 英语 总分
张三 98 69 48
李四 75 55 54
王五 36 52 66

计算出上面三个学生的总分

#include <iostream>
#include <string>
using namespace std;

int main()
{	
	// 创建关于成绩的二维数组
	int scores[3][3] = {
		{98,69,48},
		{75,55,54},
		{36,52,66}
	};

	// 创建姓名的一维数组
	string names[] = { "张三", "李四","王五" };
	for (int i = 0; i < sizeof(scores) / sizeof(scores[0]); i++) {
		// 初始化总分
		int total = 0;
		for (int j = 0; j < sizeof(scores[0]) / sizeof(scores[0][0]); j++) {
			total += scores[i][j];
		}
		cout << names[i] << "的总分为" << total << endl;
	}

	system("pause");
	return 0;
}

七、函数基础

1、概述

作用:将一段经常使用的代码封装起来,减少重复代码

一个较大的程序,一般分为若干给程序块,每个模块实现特定的功能

2、函数的定义

函数的定义一般主要有5个步骤

  1. 返回值类型
  2. 函数名
  3. 参数列表
  4. 函数体语句
  5. return表达式

注意:当函数没有返回值时,声明的变量写void void func(){}

语法:

返回值类型 函数名 (参数列表)
{
    函数体语句
        
    return 表达式
}

示例

#include <iostream>
using namespace std;

int main()
{	

	system("pause");
	return 0;
}

int add(int num1, int num2)
{
	int sum = num1 + num2;
	return sum;
}

3、函数的调用

语法:函数名(参数)

注意:

  1. 传递给函数的参数不能多也不能少
  2. 函数一定是先定义再调用,用为程序时从上往下运行的,把定义函数写在调用函数后面,会导致程序认为你没有定义函数从而报错

示例

#include <iostream>
using namespace std;


// 定义加法函数
int add(int num1, int num2)
{
	int sum = num1 + num2;
	return sum;
}

int main()
{	
	int a;
	int b;

	cout << "分别输入两个整数用来相加" << endl;
	cin >> a;
	cin >> b;

    // 调用函数,函数需要两个参数,就传两个参数,一个不多一个不少
	int c = add(a, b);
	cout << a << "+" << b << "=" << c << endl;

	system("pause");
	return 0;
}

4、值传递

  • 所谓值传递,就是函数调用时实参将数值传入给形参
  • 值传递时,如果形参发生改变,并不会影响实参

示例

#include <iostream>
using namespace std;

// 给函数传入两个整型,然后将他们分别乘以十
void func(int num1, int num2)
{
	num1 = num1 * 10;
	num2 = num2 * 10;

	cout << num1 << "  " << num2 << endl;
}

int main()
{	
	int a = 10;
	int b = 20;
	func(a, b);
	cout << a << " " << b << endl;

	system("pause");
	return 0;
}

5、函数的常见样式

有四种常见样式

  1. 无参无返
  2. 有参无返
  3. 无参有返
  4. 有参有返

示例

#include <iostream>
using namespace std;

// 1. 无参无返
void func1() {
	cout << "无参无返" << endl;
}
 
// 2. 有参无返
void func2(int a) {
	cout << "有参无返" << endl;
}
 
// 3. 无参有返
int func3() {
	cout << "无参有返" << endl;
	return 888;
}

// 4. 有参有返
int func4(int a) {
	cout << "有参有返" << endl;
	return a;
}

int main()
{	
	
	system("pause");
	return 0;
}

6、函数的声明

作用:在函数定义之前,告诉程序函数的存在

一般来说,函数的定义要在调用之前,因为程序是一行一行从上往下运行的,只有先定义了,程序才能知道有这个函数,否则程序会找不到调用的函数

要想把定义写在调用后面,就可以在调用之前声明一下函数

语法:数据类型 函数名(形参);

注意:声明函数可以有多次,但是定义只能有一次

示例

#include <iostream>
using namespace std;

// 声明函数
int func(int a);

int main()
{	
	func(10);

	system("pause");
	return 0;
}


// 定义
int func(int a) {
	cout << a << endl;
	return a;
}

7、函数的分文件编写

作用:让代码结构更加清晰

函数的分文件编写一般有四个步骤

  1. 创建后缀名为.h的头文件
  2. 创建后缀名为.cpp的源文件
  3. 在头文件中写函数的声明
  4. 在源文件中写函数的定义

注意:#include后面用 <> 包起来的是c++自带的头文件,用 "" 包起来的是自定义的头文件

示例:

后缀为.h的头文件

// 01.h
#include <iostream>
using namespace std;

// 声明函数
int func(int a, int b);

后缀为.cpp的源文件1

// c++自带的头文件
#include <iostream>
// 引入自定义的头文件
#include "01.h"
using namespace std;

// 主函数
int main()
{	
	// 添加头文件后就可以直接调用函数
	int c = func(10, 5);
	cout << c << endl;

	system("pause");
	return 0;
}

后缀为.cpp的源文件2

// 引入自定义头文件,将源文件与头文件关联起来
#include "01.h"

// 编写功能代码,比较两个数的大小
int func(int a, int b) {
	if (a > b) {
		return a;
	}
	return b;
}

八、指针

1、指针的基本概念

作用:可以通过指针间接访问内存

  • 内存编号是从0开始记录的,一般使用十六进制数字表示
  • 可以利用指针变量保存地址

2、指针的定义和简单使用

语法:

  1. 定义指针:数据类型 * 指针变量名;
  2. 使用指针(解引用):*指针变量名

示例

#include <iostream>
using namespace std;

// 主函数
int main()
{	
	int a = 10;
	// 1、定义指针
	int* p;
	// 让指针记录变量a的地址
	p = &a;
	// 变量a和指针p指向同一个内存地址
	cout << "a的地址为:" << &a << endl;
	cout << "指针p为:" << p << endl;

	// 2、使用 指针:解引用
	// 可以通过解引用的方式找到指针指向的内存中的数据
	*p = 1000;  // 变量a指向的内存中的数据就变成了1000
	cout << a << endl;
	system("pause");
	return 0;
}

3、指针所占内存空间

不管什么是什么类型的指针在相同操作系统下都是占用一样的内存空间

在32位操作系统下:占用4个字节空间

在64位操作系统下:占用8个字节空间

#include <iostream>
using namespace std;

// 主函数
int main()
{	
	int a = 10;
	int* p = &a;

	cout << sizeof(int*) << endl;
	cout << sizeof(float*) << endl;
	cout << sizeof(char*) << endl;
	cout << sizeof(double*) << endl;

	system("pause");
	return 0;
}

4、空指针

空指针:指针变量指向内存中编号为0的空间

作用:初始化指针变量

注意:空指针指向的内存是不可以访问的(0~255之间的内存编号是系统占用的,因此不可以访问)

示例

#include <iostream>
using namespace std;

// 主函数
int main()
{	
	// 定义一个空指针
	int* p = NULL;

	// 访问空指针报错,0~255为系统占用,用户无权限访问
	cout << *p << endl;

	system("pause");
	

5、野指针

5.1、野指针定义

野指针:指针变量指向非法的内存空间

5.2、出现野指针常见情形

  1. 未初始化的指针
  2. 指针所指的对象已经消亡
  3. 指针释放后未置空
  4. realloc函数使用不当

5.3、避免野指针

野指针有时候比较隐蔽,编译器不能发现

  1. c++引入了引用机制,如果使用引用可以达到编程的目的,既可以不必使用指针。因为引用在定义的时候,必须初始化,所以可以避免野指针的出现
  2. 如果一定要使用指针,那么需要在定义指针变量的同时对他进行初始化的操作。定义时将其置位NULL或者指向一个有名变量
  3. 对指针进行free或者delete操作后,将其设置为NULL。对于使用free的情况,常常定义一个宏或者函数xfree来代替free置空指针

#define xfree(x) free(x); x = NULL;

6、const修饰指针

6.1、const修饰指针 -- 常量指针

语法:const 指针类型 * 指针变量名;

特点:指针的指向可以改,指针指向的值不可以改

示例

#include <iostream>
using namespace std;

int main()
{	
	int a = 10;
	int b = 10;
	// 常量指针
	const int* p = &a;
	*p = 20;  // 错误:指针指向的值不可以改
	p = &b;  //  指针的指向可以改

	system("pause");
	return 0;
}

6.2、const修饰常量 -- 指针常量

语法:指针类型 * const 指针变量名;

特点:指针的指向不可以改,指针指向的值可以改

示例

#include <iostream>
using namespace std;

int main()
{	
	int a = 10;
	int b = 10;
	// 指针常量
	int* const p = &a;
	*p = 20;  // 指针指向的值可以改
	p = &b;  //  错误:指针的指向不可以改

	system("pause");
	return 0;
}

6.3、const修饰指针和修饰常量

语法:const 指针类型 * const 指针变量名;

特点:指针的指向不可以改,指针指向的值也不可以改

示例

#include <iostream>
using namespace std;

int main()
{	
	int a = 10;
	int b = 10;
	// const修饰指针和常量
	const int* const p = &a;
	*p = 20;  //  错误:指针指向的值不可以改
	p = &b;  //  错误:指针的指向也不可以改

	system("pause");
	return 0;
}

7、指针和数组

作用:利用指针访问数组中的元素

注意:对指针进行自增时,会根据指针类型的不同来进行不同字节的偏移

示例

#include <iostream>
using namespace std;

int main()
{	
	float arr[10] = { 1,2,3,4,5,6,7,8,9,10 };

	float* p = arr;  // 数组名就是数组的首地址

	// 数组中的第一个元素首地址等于数组的首地址,所以可以直接解引用访问到第一个元素
	cout << "利用指针访问数组中的第一个元素:" << *p << endl;

	// 利用指针访问数值中的第二个元素
	// 因为指针p是int型的指针,所以p++时他的内存地址会向后偏移四个字节
	p++;
	cout << "元素中的第二个元素为:" << *p << endl;

	system("pause");
	return 0;
}

利用指针遍历数值中所有的元素

#include <iostream>
using namespace std;

int main()
{	
	float arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	float* p = arr;
	for (int i = 0; i < 10; i++) {
		cout << *p << endl;
		p++;
	}
	

	system("pause");
	return 0;
}

8、指针和函数

如果不想修改实参,就用值传递,如果想修改实参,就用地址传递

值传递时形参改变,实参不会跟着改变

#include <iostream>
using namespace std;

void func(int a, int b) {
	int temp = a;
	a = b;
	b = temp;
	cout << "函数内的a的值:" << a << endl;
	cout << "函数内的b的值:" << b << endl;
}

int main()
{	
	int a = 10;
	int b = 20;
	// 值传递
	func(a, b);

	cout << "实参a:" << a << endl;
	cout << "实参b:" << b << endl;

	system("pause");
	return 0;
}

地址传递时形参改变,实参会跟着改变

#include <iostream>
using namespace std;

void func(int *a, int *b) {
	int temp = *a;
	*a = *b;
	*b = temp;
}

int main()
{	
	int a = 10;
	int b = 20;
	// 地址传递前
	cout << "地址传递前的实参a:" << a << endl;
	cout << "地址传递前的实参b:" << b << endl;

	// 地址传递
	func(&a, &b);

	// 地址传递后
	cout << "地址传递后的实参a:" << a << endl;
	cout << "地址传递后的实参b:" << b << endl;

	system("pause");
	return 0;
}

9、指针、数组、函数的案例

案例描述:封装一个函数,利用冒泡排序,实现对整型数组的升序排序

例如:int arr[10] = {3,6,1,9,4,7,2,8,10,5}

#include <iostream>
using namespace std;
// 冒泡排序函数 形参1:整型数组  形参2:数组长度
void bubble_sort(int *arr, int len) {
	for (int i = 0; i < len - 1; i++) {
		for (int j = 0; j < len - 1; j++) {
			if (arr[j] > arr[j + 1]) {
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
		len--;
	}
}

// 打印数组函数
void print_arr(int* arr, int len) {
	cout << "升序排序后的数组:";
	for (int i = 0; i < len; i++) {
		cout << arr[i] << " ";
	}
	cout << endl;
}

int main()
{	
	// 1、创建数组
	int arr[10] = { 3,6,1,9,4,7,2,8,10,5 };

	// 2、利用函数进行冒泡排序
	// 数组长度
	int len = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, len);

	// 3、打印数组
	print_arr(arr, len);

	system("pause");
	return 0;
}

九、结构体

1、概述

结构体属于用户自定义的数据类型,允许用户存储不同的数据类型

2、结构体的定义和使用

语法:struct 结构体名 { 结构体成员列表 };

通过结构体创建变量的方式用三种

  1. struct 结构体名 变量名
  2. struct 结构体名 变量名 =
  3. 定义结构体时顺便创建变量

注意:

  1. 通过结构体创建变量时可以省略struct
  2. 我们一般使用第一种和第二种创建结构体变量

示例

#include <iostream>
#include <string>
using namespace std;

struct Student {
	// 成员列表
	string name;
	int age;
	int score;
} s3;  // 顺便创建的结构体变量,不过一般不用


int main()
{	
	// 创建结构体变量的方式一:
	struct Student s1;
	s1.name = "张三";
	s1.age = 13;
	s1.score = 89;
	cout << "姓名:" << s1.name << "年龄:" << s1.age << "成绩:" << s1.score << endl;

	// 创建结构体变量的方式二:
	struct Student s2 = { "李四", 23, 90 };
	cout << "姓名:" << s2.name << "年龄:" << s2.age << "成绩:" << s2.score << endl;

	// 创建结构体变量的方式三:在定义结构体时把变量名写在大括号后面
	s3.name = "王五";
	s3.age = 21;
	s3.score = 34;
	cout << "姓名:" << s3.name << "年龄:" << s3.age << "成绩:" << s3.score << endl;

	system("pause");
	return 0;
}

3、结构体数组

作用:将自定义的结构体放入到数组中方便维护

语法:struct 结构体名 数组名[元素个数] = { {}, {}, {}... };

注意:要记得先定义结构体

示例:

#include <iostream>
#include <string>
using namespace std;

struct Student {
	// 成员列表
	string name;
	int age;
	int score;
};


int main()
{	
	struct Student student_arr[3] = {
		{"张三", 18, 57},
		{"李四", 19, 98},
		{"王五", 21, 88}
	};
	// 循环展示结构体数组中的元素数据
	for (int i = 0; i < 3; i++) {
		cout << " 姓名:" << student_arr[i].name
			<< " 年龄:" << student_arr[i].age
			<< " 成绩:" << student_arr[i].score << endl;
	}

	// 给结构体数组中的元素赋值
	// 修改王五的姓名为刘麻子,年龄22,成绩99
	student_arr[2].name = "刘麻子";
	student_arr[2].age = 22;
	student_arr[2].score = 99;
	// 修改后
	cout << "修改后" << endl;
	for (int i = 0; i < 3; i++) {
		cout << " 姓名:" << student_arr[i].name
			<< " 年龄:" << student_arr[i].age
			<< " 成绩:" << student_arr[i].score << endl;
	}

	return 0;
}

4、结构体指针

4.1、通过指针指向结构体

语法:struct 结构体名 * 指针变量名 = &结构体变量名

示例

#include <iostream>
#include <string>
using namespace std;

// 定义结构体
struct Student {
	// 成员列表
	string name;
	int age;
	int score;
};


int main()
{	
    // 创建结构体变量
	struct Student stu = { "刘六", 18, 99 };

    // 指针指向结构体变量
	struct Student* p = &stu;
	return 0;
}

4.2、通过指针访问结构体变量中的数据

语法:指针变量名 -> 成员变量名;

示例

#include <iostream>
#include <string>
using namespace std;

struct Student {
	// 成员列表
	string name;
	int age;
	int score;
};


int main()
{	
	struct Student stu = { "刘六", 18, 99 };

	struct Student* p = &stu;

	// 指针通过  ->  符号可以访问成员
	p->name = "王五";
	cout << " 姓名:" << p->name
		 << " 年龄:" << p->age
		 << " 成绩:" << p->score << endl;

	return 0;
}

5、结构体嵌套结构体

结构体中的成员可以是另一个结构体

例如一个老师有自己的姓名、年龄、编号等等,也有自己辅导的学生,学生也有自己的姓名年龄等等,这样我们就可以用到结构体嵌套了

示例1:第一种为嵌套结构体变量赋值的方法

#include <iostream>
#include <string>
using namespace std;

// 学生结构体
struct student {
	// 成员列表
	string name;
	int age;
	int score;
};

// 老师结构体
struct teacher {
	int id;
	string name;
	int age;
	struct student stu1;
	struct student stu2;
};


int main()
{	
    // 第一种
	struct teacher t1;
	t1.id = 01;
	t1.name = "老王";
	t1.age = 56;

	t1.stu1.name = "小李";
	t1.stu1.age = 18;
	t1.stu1.score = 98;

	t1.stu2.name = "小刘";
	t1.stu2.age = 18;
	t1.stu2.score = 98;


	cout << " 老师编号:" << t1.id << " 老师姓名:" << t1.name
		<< " 老师年龄:" << t1.age << endl
		<< " 辅导的学生1号姓名:" << t1.stu1.name
		<< " 年龄" << t1.stu1.age << " 成绩" << t1.stu1.score << endl
		<< " 辅导的学生1号姓名:" << t1.stu1.name
		<< " 年龄" << t1.stu1.age << " 成绩" << t1.stu1.score << endl;
	return 0;
}

示例2:第二种为嵌套结构体变量赋值的方法

#include <iostream>
#include <string>
using namespace std;

// 学生结构体
struct student {
	// 成员列表
	string name;
	int age;
	int score;
};

// 老师结构体
struct teacher {
	int id;
	string name;
	int age;
	struct student stu1;
	struct student stu2;
};


int main()
{
	teacher t1 = { 01, "老王", 67,{"小王", 12,98}, {"小李", 23,99} };


	cout << " 老师编号:" << t1.id << " 老师姓名:" << t1.name
		<< " 老师年龄:" << t1.age << endl
		<< " 辅导的学生1号姓名:" << t1.stu1.name
		<< " 年龄" << t1.stu1.age << " 成绩" << t1.stu1.score << endl
		<< " 辅导的学生1号姓名:" << t1.stu1.name
		<< " 年龄" << t1.stu1.age << " 成绩" << t1.stu1.score << endl;
	return 0;
}

6、结构体做函数参数

传递的方式有两种

  1. 值传递

    语法:函数类型 函数名(结构体名 形参名){}

  2. 地址传递

    语法:函数类型 函数名(结构体名 * 指针形参名){}

值传递示例:形参改变,实参不会跟着改变

#include <iostream>
#include <string>
using namespace std;

// 学生结构体
struct student {
	// 成员列表
	string name;
	int age;
	int score;
};

// 值传递
void print_stu1(struct student stu) {
	stu.name = "张三";
	stu.age = 99;
	stu.score = 10;
	cout << "在值传递函数中修改过数据打印的结果:";
	cout << " 学生姓名:" << stu.name
		<< " 学生年龄:" << stu.age
		<< " 学生成绩:" << stu.score << endl;
}

int main()
{	
	student stu = {"李四", 18, 89};
	// 值传递
	print_stu1(stu);

	cout << "在main函数中数据打印的结果:";
	cout << " 学生姓名:" << stu.name
		<< " 学生年龄:" << stu.age
		<< " 学生成绩:" << stu.score << endl;
	
	return 0;
}

地址传递示例:形参改变实参会跟着改变

#include <iostream>
#include <string>
using namespace std;

// 学生结构体
struct student {
	// 成员列表
	string name;
	int age;
	int score;
};

// 地址传递
void print_stu2(struct student* stu) {
	stu->name = "张三";
	stu->age = 99;
	stu->score = 10;
	cout << "在地址传递函数中修改了数据打印的结果:";
	cout << " 学生姓名:" << stu->name
		<< " 学生年龄:" << stu->age
		<< " 学生成绩:" << stu->score << endl;
}

int main()
{	
	student stu = {"李四", 18, 89};
	// 地址传递
	print_stu2(&stu);

	cout << "在main函数中数据打印的结果:";
	cout << " 学生姓名:" << stu.name
		<< " 学生年龄:" << stu.age
		<< " 学生成绩:" << stu.score << endl;

	

	
	
	return 0;
}

7、结构体中const使用场景

作用:防止误操作

在函数中执行打印操作的时候,如果我们使用值传递的方式,程序会把要打印的数据复制一份,当要打印的数据过大时,会占用较大的内存,所以最好使用地址传递的方式,但是使用地址传递时修改了形参的数据,实参也会跟着改变,为了防止误操作导致数据被更改,因此在形参前加上const,使形参不可修改

语法:数据类型 函数名 (const struct 结构体名 结构体变量名)

示例

#include <iostream>
#include <string>
using namespace std;

// 学生结构体
struct student {
	// 成员列表
	string name;
	int age;
	int score;
};

// 地址传递
void print_stu2(const struct student* stu) {
	// stu->name = "李四";  // 会报错,不可修改
	cout << " 学生姓名:" << stu->name
		<< " 学生年龄:" << stu->age
		<< " 学生成绩:" << stu->score << endl;
}

int main()
{	
	struct student stu = { "张三", 18, 99 };

	return 0;
}

8、结构体案例

案例一:

学校正在做毕设项目,每名老师带领5个学生,总共有3名老师,需求如下

设计学生和老师结构体,其中在老师的结构体中,有老师姓名和一个存放5名学生的数组作为成员,学生的成员有姓名和考试分数,创建数组存放3名老师,通过函数给每个老师及所带的学生赋值,最终打印出老师数据和老师所带的学生数据

示例

#include <iostream>
#include <string>
#include <ctime>
using namespace std;

// 学生结构体
struct student {
	// 学生姓名
	string name;
	// 学生成绩
	int score;
};

// 老师结构体
struct teacher {
	// 老师姓名
	string name;
	// 学生数组
	struct student stu_arr[5];
};

// 为结构体赋值
// 参数1:老师结构体数组;参数2:老师结构体数组长度;参数3:学生结构体数组长度;参数4:老师的姓名数组;参数5:学生姓名的二维数组
void add(teacher teacher_arr[], int teacher_len, int student_len, string teacher_name[], string student_name[][5]) {
	// 第一层循环老师结构体数组
	for (int i = 0; i < teacher_len; i++) {
		// 给老师赋值,从老师姓名数组中按顺序循环给老师赋值姓名
		teacher_arr[i].name = teacher_name[i];
		// 第二层循环单个老师中的学生结构体数组
		for (int j = 0; j < student_len; j++) {
			// 给学生赋值姓名
			teacher_arr[i].stu_arr[j].name = student_name[i][j];
			// 40到100的随机数
			int number = rand() % 61 + 40;
			// 给学生赋值随机的成绩
			teacher_arr[i].stu_arr[j].score = number;
		}
	}
}

// 打印结构体中所有的信息
void print_teacher_stu(teacher teachers[], int teacher_len, int student_len) {
	// 循环打印老师信息
	for (int i = 0; i < teacher_len; i++) {
		cout << "老师姓名:" << teachers[i].name << endl;
		// 循环打印学生信息
		for (int j = 0; j < student_len; j++) {
			cout << "\t学生姓名:" << teachers[i].stu_arr[j].name
			     << "\t学生成绩:" << teachers[i].stu_arr[j].score << endl;
		}
	}
}

int main()
{	
	// 根据时间生成随机数种子
	srand((unsigned)time(NULL));
	// 创建老师姓名数组
	string teacher_name[] = { "老王","老刘","老张" };
	// 创建学生姓名的二维数组,一个老师带五个学生
	string student_name[][5] = {
		{ "小刘","小李","小王","小宋","小张"},
		{ "小曾","小杨","小陈","小史","小安"},
		{ "小桑","小饶","小楚","小沈","小二"}
	};
	// 创建结构体数组,三个老师
	struct teacher teachers[3];
	// 老师结构体数组长度,用老师数组所占字节总长度除以数组中单个元素所占字节长度
	int teacher_len = sizeof(teachers) / sizeof(teachers[0]);
	// 老师结构体内的学生结构体数组长度,数组名就是数组首地址,也就是指针,指针访问结构体要用 -> 符号
	int student_len = sizeof(teachers->stu_arr) / sizeof(teachers->stu_arr[0]);
	// 
	add(teachers, teacher_len, student_len, teacher_name, student_name);

	print_teacher_stu(teachers, teacher_len, student_len);

	return 0;
}

案例二:

有一个用户结构体,包括成员姓名、年龄、性别,创建结构体数组,数组中存放5名用户。

通过冒泡排序的算法,将数组中的用户按照年龄进行升序排列

#include <iostream>
#include <string>
using namespace std;

struct user {
	string name;
	string gender;
	int age;
};

void bubble_sort(user user_arr[], int len) {
	for (int i = 0; i < len - 1; i++) {
		for (int j = 0; j < len - i - 1; j++) {
			if (user_arr[j].age > user_arr[j + 1].age) {
				// 新建一个结构体变量用来接收暂时存储的值,类似之前的  int temp
				struct user temp = user_arr[j];
				user_arr[j] = user_arr[j + 1];
				user_arr[j + 1] = temp;
			}
		}
	}
}

int main()
{	
	user user_arr[] = {
		{"老王", "男", 23},
		{"老张", "男", 26},
		{"老李", "女", 34},
		{"老刘", "男", 21},
		{"老陈", "女", 33},
	};
	int len = sizeof(user_arr) / sizeof(user_arr[0]);
	bubble_sort(user_arr, len);

	for (int i = 0; i < len; i++) {
		cout << "用户姓名:" << user_arr[i].name
			<< "\t用户性别:" << user_arr[i].gender
			<< "\t用户年龄:" << user_arr[i].age << endl;
	}
	return 0;
}

十、通讯管理系统

1、系统需求

通讯录是一个可以记录亲人、好友信息的工具

要实现的功能如下:

  • 添加联系人:向通讯录中添加新人,信息包括(姓名、性别、年龄、联系电话、家庭住址)最多记录1000人
  • 显示联系人:显示通讯录中所有联系人信息
  • 删除联系人:按照姓名删除指定联系人
  • 查找联系人:按照姓名查看指定联系人信息
  • 修改联系人:按照姓名重新修改联系人信息
  • 清空联系人:清空通讯录中所有联系人
  • 退出通讯录:退出当前使用的通讯录

2、菜单功能

  • 封装函数显示该界面,如 void show_menu()
  • 在main函数中调用封装好的函数

示例

// 菜单界面
void show_menu() {
	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;
}

3、整体框架

通过Switch分支结构,根据用户输入不同的数字进行不同的功能

// 接收用户输入的变量
	int select;

	while (true) {
		// 调用菜单界面
		show_menu();
		// 获取用户输入
		cin >> select;

		switch (select) {
		case 1:  // 添加联系人
			break;
		case 2:  // 显示联系人
			break;
		case 3:  // 删除联系人
			break;
		case 4:  // 查找联系人
			break;
		case 5:  // 修改联系人
			break;
		case 6:  // 清空通讯录
			break;
		case 0:  // 退出通讯录
			break;
		}
	}

4、退出功能

用户选择输入0时,直接return 0结束函数

case 0:  // 退出通讯录
    cout << "退出成功" << endl;
    return 0;
    break;

5、添加联系人

联系人上限1000人,联系人信息包括(姓名、性别、年龄、联系电话、家庭住址)

  • 设计联系人结构体
  • 实际通讯录结构体
  • main函数中创建通讯录
  • 封装添加联系人函数

5.1、设计联系人结构体

// 设计联系人结构体
struct person {
	// 姓名
	string name;
	// 性别  数字1表示男,数字2表示女
	string gender;
	// 年龄
	int age;
	// 电话
	string phone;
	// 地址
	string addr;
};

5.2、设计通讯录结构体

在通讯录结构体中,维护一个容量为1000的存放联系人的数组,并记录当前通讯录中联系人数量

// 通讯录结构体
struct add_ressbooks {
	// 通讯录中保存联系人的联系人数组
	struct person person_array[MAX];
	// 通讯录中当前记录联系人个数
	int person_size;
};

5.3、main函数中创建通讯录

在main函数中创建一个通讯录变量,这就是我们需要一直维护的通讯录

// 创建通讯录结构体变量
add_ressbooks abs;
// 初始化通讯录中的当前人数
abs.person_size = 0;

5.4、封装添加联系人函数

// 加联系人函数
void add_person(add_ressbooks* abs) {
	// 判断通讯录是否已满
	if (abs->person_size == MAX) {
		cout << "通讯录已满,无法添加" << endl;
		return;
	}
	// 开始添加联系人
	// 接收字符串数据
	string string_user;

	// 添加姓名
	cout << "输入姓名" << endl;
	cin >> string_user;
	abs->person_array[abs->person_size].name = string_user;

	while (true) {
		// 添加性别
		cout << "输入性别" << endl;
		cin >> string_user;
		// 判断用户输入的性别是否是男和女,不是则重新开始循环
		if (string_user != "男" && string_user != "女") {
			cout << "输入正确的性别" << endl;
			continue;
		}
		abs->person_array[abs->person_size].gender = string_user;
		break;
	}

	// 添加年龄
	cout << "输入年龄" << endl;
	cin >> int_user;
	abs->person_array[abs->person_size].age = int_user;

	// 添加电话
	cout << "输入电话" << endl;
	cin >> string_user;
	abs->person_array[abs->person_size].phone = string_user;

	// 添加地址
	cout << "输入地址" << endl;
	cin >> string_user;
	abs->person_array[abs->person_size].addr = string_user;

	cout << "联系人添加成功" << endl;

	// 更新通讯录的人数
	abs->person_size++;

	// 按任意键继续
	system("pause");
	// 清空一下屏幕
	system("cls");
}

5.5、把添加联系人函数写到switch中

case 1:  // 添加联系人
    add_person(&abs);  // 利用地址传递,可以修形参
    break;

6、显示联系人

显示通讯录中已经记录的联系人信息

6.1、封装显示联系人函数

// 显示联系人函数
void show_person(add_ressbooks* abs) {
	// 判断当前通讯录是否有联系人
	if (abs->person_size == 0) {
		cout << "当前没有联系人" << endl;
		// 按任意键继续
		system("pause");
		// 清空一下屏幕
		system("cls");
		return;
	}
	// 循环打印联系人结构体中的数据
	for (int i = 0; i < abs->person_size; i++) {
		cout << "姓名:" << abs->person_array[i].name << "\t";
		cout << "性别:" << abs->person_array[i].gender << "\t";
		cout << "年龄:" << abs->person_array[i].age << "\t";
		cout << "电话:" << abs->person_array[i].phone << "\t";
		cout << "地址:" << abs->person_array[i].addr << endl;
	}
	// 按任意键继续
	system("pause");
	// 清空一下屏幕
	system("cls");
}

6.2、添加函数到switch语句中

case 2:  // 显示联系人
    show_person(&abs);
    break;

7、删除联系人

7.1、封装检测联系人是否存在函数

在后面按姓名查找联系人和修改联系人功能都需要 使用该函数

// 检测联系人是否存在,如果存在,返回联系人所在数组中的具体位置,不存在返回-1
// 参数一:通讯录结构体指针;参数二:用户输入的姓名实参
int is_exist(add_ressbooks* abs, string name) {
	// 遍历联系人结构体数组
	for (int i = 0; i < abs->person_size; i++) {
		// 用户输入的姓名在联系人结构体数组中找到了,返回元素索引
		if (abs->person_array[i].name == name) {
			return i;
		}
	}
	// 没有找到则返回-1
	return -1;
}

7.2、封装删除联系人函数

// 删除联系人函数
void delete_person(add_ressbooks* abs) {
	// 接收用户输入的字符串
	string name;
	cout << "输入要删除的联系人姓名" << endl;
	cin >> name;
	// 调用检测联系人是否存在的函数
	int res = is_exist(abs, name);
	// 当函数返回值为-1时,打印没有当前联系人,并结束函数
	if (res == -1) {
		cout << "没有当前联系人" << endl;
		// 按任意键继续
		system("pause");
		// 清空一下屏幕
		system("cls");
		return;
	}
	// 获取到想要删除的联系人索引,从当前索引开始循环
	for (int i = res; i < abs->person_size; i++) {
		// 让数组中索引为i+1的元素覆盖前面索引为i的元素
		abs->person_array[i] = abs->person_array[i + 1];
	}
	// 当循环覆盖完成后,让通讯录结构体中的总人数自减
	abs->person_size--;
	cout << "删除成功" << endl;
	// 按任意键继续
	system("pause");
	// 清空一下屏幕
	system("cls");
}

7.3、添加函数到switch语句中

case 3:  // 删除联系人
    delete_person(&abs);
    break;

8、查找联系人

8.1封装查找联系人函数

// 查找联系人函数
void find_person(add_ressbooks* abs) {
	// 接收用户输入的字符串
	string name;
	cout << "输入要删除的联系人姓名" << endl;
	cin >> name;
	// 调用检测联系人是否存在的函数,并返回联系人索引或-1
	int res = is_exist(abs, name);
	// 当函数返回值为-1时,打印没有当前联系人,并结束函数
	if (res == -1) {
		cout << "没有当前联系人" << endl;
		// 按任意键继续
		system("pause");
		// 清空一下屏幕
		system("cls");
		return;
	}
	// 打印联系人信息
	cout << "姓名:" << abs->person_array[res].name << "\t";
	cout << "性别:" << abs->person_array[res].gender << "\t";
	cout << "年龄:" << abs->person_array[res].age << "\t";
	cout << "电话:" << abs->person_array[res].phone << "\t";
	cout << "地址:" << abs->person_array[res].addr << endl;
	// 按任意键继续
	system("pause");
	// 清空一下屏幕
	system("cls");
	return;
}

8.2、添加函数到switch语句中

case 4:  // 查找联系人
    find_person(&abs);
    break;

9、修改联系人

9.1、封装修改联系人函数

// 修改联系人信息
void modify_person(add_ressbooks* abs) {
	// 接收用户输入的字符串
	string name;
	cout << "输入要修改的联系人姓名" << endl;
	cin >> name;
	// 调用检测联系人是否存在的函数,并返回联系人索引或-1
	int res = is_exist(abs, name);
	// 当函数返回值为-1时,打印没有当前联系人,并结束函数
	if (res == -1) {
		cout << "没有当前联系人" << endl;
		// 按任意键继续
		system("pause");
		// 清空一下屏幕
		system("cls");
		return;
	}
	// 接收字符串数据
	string string_user;

	// 添加姓名
	cout << "输入姓名" << endl;
	cin >> string_user;
	abs->person_array[res].name = string_user;

	while (true) {
		// 添加性别
		cout << "输入性别" << endl;
		cin >> string_user;
		// 判断用户输入的性别是否是男和女,不是则重新开始循环
		if (string_user != "男" && string_user != "女") {
			cout << "输入正确的性别" << endl;
			continue;
		}
		abs->person_array[res].gender = string_user;
		break;
	}

	// 添加年龄
	cout << "输入年龄" << endl;
	cin >> string_user;
	abs->person_array[res].age = string_user;

	// 添加电话
	cout << "输入电话" << endl;
	cin >> string_user;
	abs->person_array[res].phone = string_user;

	// 添加地址
	cout << "输入地址" << endl;
	cin >> string_user;
	abs->person_array[res].addr = string_user;

	cout << "联系人修改成功" << endl;

	// 按任意键继续
	system("pause");
	// 清空一下屏幕
	system("cls");
}

9.2、添加函数到switch语句中

case 5:  // 修改联系人
    modify_person(&abs);
    break;

10、清空通讯录

直接在switch中,把通讯录联系人数量重置为0,虽然在内存中依然存在,但是无法通过显示联系人和查找联系人操作查看了

case 6:  // 清空通讯录
    // 将当期记录联系人数量重置为0,做逻辑清空
    abs.person_size = 0;
    cout << "清空完成" << endl;
    // 按任意键继续
    system("pause");
    // 清空一下屏幕
    system("cls");
    break;

11、全部源码

有一定bug,逻辑有一定漏洞,且没分文件编写,面条板,只是做简单练习的案例

#include <iostream>
#include <string>
using namespace std;
// 宏常量:通讯录最大人数
#define MAX 1000

// 设计联系人结构体
struct person {
	// 姓名
	string name;
	// 性别
	string gender;
	// 年龄
	string age;
	// 电话
	string phone;
	// 地址
	string addr;
};

// 通讯录结构体
struct add_ressbooks {
	// 通讯录中保存联系人的联系人数组
	struct person person_array[MAX];
	// 通讯录中当前记录联系人个数
	int person_size{};
};

// 加联系人函数
void add_person(add_ressbooks* abs) {
	// 判断通讯录是否已满
	if (abs->person_size == MAX) {
		cout << "通讯录已满,无法添加" << endl;
		return;
	}
	// 开始添加联系人
	// 接收字符串数据
	string string_user;

	// 添加姓名
	cout << "输入姓名" << endl;
	cin >> string_user;
	abs->person_array[abs->person_size].name = string_user;

	while (true) {
		// 添加性别
		cout << "输入性别" << endl;
		cin >> string_user;
		// 判断用户输入的性别是否是男和女,不是则重新开始循环
		if (string_user != "男" && string_user != "女") {
			cout << "输入正确的性别" << endl;
			continue;
		}
		abs->person_array[abs->person_size].gender = string_user;
		break;
	}

	// 添加年龄
	cout << "输入年龄" << endl;
	cin >> string_user;
	abs->person_array[abs->person_size].age = string_user;

	// 添加电话
	cout << "输入电话" << endl;
	cin >> string_user;
	abs->person_array[abs->person_size].phone = string_user;

	// 添加地址
	cout << "输入地址" << endl;
	cin >> string_user;
	abs->person_array[abs->person_size].addr = string_user;

	cout << "联系人添加成功" << endl;

	// 更新通讯录的人数
	abs->person_size++;

	// 按任意键继续
	system("pause");
	// 清空一下屏幕
	system("cls");
}

// 显示联系人函数
void show_person(add_ressbooks* abs) {
	// 判断当前通讯录是否有联系人
	if (abs->person_size == 0) {
		cout << "当前没有联系人" << endl;
		// 按任意键继续
		system("pause");
		// 清空一下屏幕
		system("cls");
		return;
	}
	// 循环打印联系人结构体中的数据
	for (int i = 0; i < abs->person_size; i++) {
		cout << "姓名:" << abs->person_array[i].name << "\t";
		cout << "性别:" << abs->person_array[i].gender << "\t";
		cout << "年龄:" << abs->person_array[i].age << "\t";
		cout << "电话:" << abs->person_array[i].phone << "\t";
		cout << "地址:" << abs->person_array[i].addr << endl;
	}
	// 按任意键继续
	system("pause");
	// 清空一下屏幕
	system("cls");
}

// 检测联系人是否存在,如果存在,返回联系人所在数组中的具体位置,不存在返回-1
// 参数一:通讯录结构体指针;参数二:用户输入的姓名实参
int is_exist(add_ressbooks* abs, string name) {
	// 遍历联系人结构体数组
	for (int i = 0; i < abs->person_size; i++) {
		// 用户输入的姓名在联系人结构体数组中找到了,返回元素索引
		if (abs->person_array[i].name == name) {
			return i;
		}
	}
	// 没有找到则返回-1
	return -1;
}

// 删除联系人函数
void delete_person(add_ressbooks* abs) {
	// 接收用户输入的字符串
	string name;
	cout << "输入要删除的联系人姓名" << endl;
	cin >> name;
	// 调用检测联系人是否存在的函数
	int res = is_exist(abs, name);
	// 当函数返回值为-1时,打印没有当前联系人,并结束函数
	if (res == -1) {
		cout << "没有当前联系人" << endl;
		// 按任意键继续
		system("pause");
		// 清空一下屏幕
		system("cls");
		return;
	}
	// 获取到想要删除的联系人索引,从当前索引开始循环
	for (int i = res; i < abs->person_size; i++) {
		// 让数组中索引为i+1的元素覆盖前面索引为i的元素
		abs->person_array[i] = abs->person_array[i + 1];
	}
	// 当循环覆盖完成后,让通讯录结构体中的总人数自减
	abs->person_size--;
	cout << "删除成功" << endl;
	// 按任意键继续
	system("pause");
	// 清空一下屏幕
	system("cls");
}

// 查找联系人函数
void select_person(add_ressbooks* abs) {
	// 接收用户输入的字符串
	string name;
	cout << "输入要查找的联系人姓名" << endl;
	cin >> name;
	// 调用检测联系人是否存在的函数,并返回联系人索引或-1
	int res = is_exist(abs, name);
	// 当函数返回值为-1时,打印没有当前联系人,并结束函数
	if (res == -1) {
		cout << "没有当前联系人" << endl;
		// 按任意键继续
		system("pause");
		// 清空一下屏幕
		system("cls");
		return;
	}
	// 打印联系人信息
	cout << "姓名:" << abs->person_array[res].name << "\t";
	cout << "性别:" << abs->person_array[res].gender << "\t";
	cout << "年龄:" << abs->person_array[res].age << "\t";
	cout << "电话:" << abs->person_array[res].phone << "\t";
	cout << "地址:" << abs->person_array[res].addr << endl;
	// 按任意键继续
	system("pause");
	// 清空一下屏幕
	system("cls");
	return;
}

// 修改联系人信息
void modify_person(add_ressbooks* abs) {
	// 接收用户输入的字符串
	string name;
	cout << "输入要修改的联系人姓名" << endl;
	cin >> name;
	// 调用检测联系人是否存在的函数,并返回联系人索引或-1
	int res = is_exist(abs, name);
	// 当函数返回值为-1时,打印没有当前联系人,并结束函数
	if (res == -1) {
		cout << "没有当前联系人" << endl;
		// 按任意键继续
		system("pause");
		// 清空一下屏幕
		system("cls");
		return;
	}
	// 接收字符串数据
	string string_user;

	// 添加姓名
	cout << "输入姓名" << endl;
	cin >> string_user;
	abs->person_array[res].name = string_user;

	while (true) {
		// 添加性别
		cout << "输入性别" << endl;
		cin >> string_user;
		// 判断用户输入的性别是否是男和女,不是则重新开始循环
		if (string_user != "男" && string_user != "女") {
			cout << "输入正确的性别" << endl;
			continue;
		}
		abs->person_array[res].gender = string_user;
		break;
	}

	// 添加年龄
	cout << "输入年龄" << endl;
	cin >> string_user;
	abs->person_array[res].age = string_user;

	// 添加电话
	cout << "输入电话" << endl;
	cin >> string_user;
	abs->person_array[res].phone = string_user;

	// 添加地址
	cout << "输入地址" << endl;
	cin >> string_user;
	abs->person_array[res].addr = string_user;

	cout << "联系人修改成功" << endl;

	// 按任意键继续
	system("pause");
	// 清空一下屏幕
	system("cls");
}

// 菜单界面
void show_menu() {
	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;
}

int main()
{
	// 创建通讯录结构体变量
	add_ressbooks abs;
	// 初始化通讯录中的当前人数
	abs.person_size = 0;

	// 接收用户输入的变量
	int select;
	// 接收用户输入的字符串变量
	// string str;

	while (true) {
		// 调用菜单界面
		show_menu();
		// 获取用户输入
		cin >> select;

		switch (select) {
		case 1:  // 添加联系人
			add_person(&abs);  // 利用地址传递,可以修形参
			break;
		case 2:  // 显示联系人
			show_person(&abs);
			break;
		case 3:  // 删除联系人
			delete_person(&abs);
			break;
		case 4:  // 查找联系人
			select_person(&abs);
			break;
		case 5:  // 修改联系人
			modify_person(&abs);
			break;
		case 6:  // 清空通讯录
			// 将当期记录联系人数量重置为0,做逻辑清空
			abs.person_size = 0;
			cout << "清空完成" << endl;
			// 按任意键继续
			system("pause");
			// 清空一下屏幕
			system("cls");
			break;
		case 0:  // 退出通讯录
			cout << "退出成功!!!" << endl;
			// 结束main函数
			return 0;
			break;
		default:
			cout << "请输入正确的序号" << endl;
			// 按任意键继续
			system("pause");
			// 清空一下屏幕
			system("cls");
		}
	}
	

	system("pause");
	return 0;
}
posted @   7七柒  阅读(136)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示