【黑马程序员】萌新的C++基础入门笔记(包括C++基础语法到通讯录管理系统)—— 宇昕

C++基础入门

一、C++初识

1.1 第一个C++程序

  • 创建项目
  • 创建文件
  • 编写代码
  • 运行程序
1.1.1 创建项目
1.1.2 创建文件
1.1.3 编写代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
int main()
{

	cout << "Hello World" << endl;

	system("pause");

	return 0;
}
1.1.4 运行程序

1.2 注释

**作用:**在代码中加一些说明和解释,方便自己或其他程序员阅读代码

两种格式

  1. 单行注释:// 描述信息
  2. 多行注释: /* 描述信息 */

1.3 变量

**作用:**给一段制定的内存空间起名,方便操作这段内存,管理内存空间

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

示例:

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
int main()
{

	int a = 10;

	cout << "a = " << a << endl;

	system("pause");

	return 0;
}

1.4 常量

**作用:**用于记录程序中不可更改的数据

C++定义常量两种方式

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

示例

#include <iostream>
#define day 7 //1.#define 宏常量

using namespace std;

int main()
{

	cout << "一周共有" << day << "天" << endl;
	//day = 8;  会报错,不可修改

	//2.const修饰的变量
	const int month = 12;
	//month = 13; 报错,不可修改

	cout << "一年共有" << month << "月" << endl;

	system("pause");

	return 0;
}

1.5 关键字

**作用:**关键字是C++中预先保留的单词(标识符)

  • 在定义变量或者常量时,不要用关键字

C++关键字如下:

asmdoifreturntypedef
autodoubleinlineshorttypeid
booldynamic_castintsignedtypename
breakelselongsizeofunion
caseenummutablestaticunsigned
catchexplicitnamespacestatic_castusing
charesportnewstructvirtual
classexternoperatorswitchvoid
constfalseprivatetemplatevolatile
const_castfloatprotectedthiswchar_t
continueforpublicthrowwhile
defaultfriendregistertrue
deletegotoreinterpret_casttry

提示:在给变量或者常量起名的时候,不要用c++的关键字,否则或产生歧义

1.6 标识符命名规则

**作用:**C++规定给标识符(变量、常量)命名时,有一套自己的规则

  • 标识符不能是关键字
  • 标识符只能由字母,数字,下划线组成 -> abc123_
  • 第一个字符必须是字母或者下划线
  • 标识符中字母分大小写

建议:给标识符命名时,争取见名知义,方便阅读

二、数据类型

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

2.1 整型

**作用:**整型变量表示的是整数类型的数据

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

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

using namespace std;

int main()
{

	//整型 (int较常用)
	// 
	//1、短整型(-32768 ~ 32767)
	short num1 = 32768; //结果是-32768,循环回来了

	//2、整型 (...~...)
	int num2 = 10;

	//3、长整型 (...~...)
	long num3 = 10;

	//4、长长整型 (...~...)
	long long num4 = 10;

	cout << "num1 = " << num1 << endl;
	cout << "num2 = " << num2 << endl;
	cout << "num3 = " << num3 << endl;
	cout << "num4 = " << num4 << endl;

	return 0;
}

2.2 sizeof关键字

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

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

示例:

#include <iostream>

using namespace std;

int main() {

    //sizeof可以求出数据类型占用内存的大小
    //语法:sizeof( 数据类型 / 变量 )
    
	cout << "short 类型所占内存空间为:" << sizeof(short) << endl;//2

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

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

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

    //整型大小比较
    // short < int <= long <= long long
    
	return 0;
}

实型(浮点型)

**作用:**用于表示小数

浮点型变量分两种:

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

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

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

示例:

#include <iostream>

using namespace std;

int main() {

	//1.单精度 float
	//2.双精度 double
	//默认情况下,输出一个小数,会显示出六位有效数字,五位小数

	float f1 = 3.141592653f;
	double d2 = 3.14;

	cout << "f1 = " << f1 << endl;
	cout << "d2 = " << d2 << endl;

	//统计float和double占用内存空间
	//	float 4
	//	double 8

	cout << "float占用的内存空间为" << sizeof(float) << endl;
	cout << "double占用的内存空间为" << sizeof(double) << endl;

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

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

	system("pause");

	return 0;
}

2.4 字符型

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

语法:char ch = 'a';

注意1:在显示字符型变量时,用单引号将字符括起来,不用双引号

注意2:单引号只能有一个字符,不可以是字符串

  • C和C++中字符型变量只占用一个字节

  • 字符型变量并不是把字符本身放在内存中存储,而是将对应的ASCII编码放入到存储单元

示例:

#include <iostream>

using namespace std;

int main() {

	//1.字符型变量创建方式
	char ch = 'a';
	cout << ch << endl;

	//2.字符型变量所占内存大小
	cout << "字符型变量占用内存:" << sizeof(ch) << endl; //1

	//3.字符型变量常见错误
	//char ch2 = "b";  用单引号
	//char ch2 = 'abc';  数量过多

	//4.字符型变量对应ASCII编码
	//a - 97
	//A - 65
	cout << (int)ch << endl; //97 就是 a 对应的ASCII码

	system("pause");
	return 0;
}

ASCII码对照表 —在线工具 (sojson.com)

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

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

2.5 转移字符

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

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

转义字符含义ASCII码
\a响铃77
\b退格8
\f换页12
\n换行10
\r回车13
\t横向制表符9
\v纵向制表符11
\反斜杠92
单引号39
"双引号34
?问号63
\0空字符0
\\代表一个反斜线’\’92
#include <iostream>

using namespace std;

int main() {

	//转义字符

	//换行符 \n

	cout << "hello world\n" << endl;

	//反斜杠 \\
	
	cout << "\\" << endl;
	
	//水平制表符 \t
	//作用:可以整齐地输出数据

	cout << "a\thello" << endl;
	cout << "aaaaa\thello" << endl;

	system("pause");
	return 0;
}

2.6 字符串型

**作用:**用于表示一串字符

两种风格

  1. C风格字符串:char 变量名[] = "字符串值"

    示例:

    #include <iostream>
    
    using namespace std;
    
    int main()
    {
    
    	char ch[] = "Hello World";
    
    	cout << ch << endl;
    
    	return 0;
    }
    

    注意:C风格的字符串要用双引号括起来

    ​ char 字符串名 []

  2. C++风格字符串:string 变量名 = "字符串值"

    示例:

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    int main()
    {
    
    	string ch = "Hello World";
    
    	cout << ch << endl;
    
    	return 0;
    }
    

    注意:需要包含一个头文件 #include <string> vs2022貌似不用

2.7 布尔数据类型

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

bool 类型只有两个值:

  • true — 真(本质是1)(非0的其实都为真)

  • false — 假(本质是0)

    bool类型占1个字节大小

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//1.创建bool数据类型
	bool flag = true; //true代表真
	cout << flag << endl;

	bool flag2 = false; //假
	cout << flag2 << endl;

	//本质上  1代表真  0代表假

	//2.查看bool类型所占内存空间
	cout << "bool类型所占的内存空间:" << sizeof(bool) << endl; //1

	return 0;
}

2.8 数据的输入

作用:用于从键盘获取数据

**关键字:**cin

语法: cin >> 变量

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//1.整型
	//int a = 0;
	//cout << "请给整型变量a赋值:" << endl;
	//cin >> a;
	//cout << "整型变量a = " << a << endl;

	//2.浮点型
	//float b = 3.14f;
	//cout << "请给浮点型变量b赋值:" << endl;
	//cin >> b;
	//cout << "浮点型变量b = " << b << endl;

	//3.字符型
	//char ch = 'a';
	//cout << "请给字符型变量ch赋值:" << endl;
	//cin >> ch;
	//cout << "字符型变量ch = "<< ch << endl;

	//4.字符串型
	//string str = "hello";
	//cout << "请给字符串型变量str赋值:" << endl;
	//cin >> str;
	//cout << "字符串变量str = " << str << endl;

	//5.布尔类型(非0的值都为真)
	bool flag = false;
	cout << "请给布尔类型的flag赋值:" << endl;
	cin >> flag;
	cout << "布尔类型的flag为" << flag << endl;

	return 0;
}

三、运算符

**作用:**用于执行代码的运算

本章我们主要讲解一下几类运算符

运算符类型作用
算术运算符用于四则运算
赋值运算符用于将表达式的值赋给变量
比较运算符用于表达式的比较,并返回一个真值或者假值
逻辑运算符用于根据表达式的值返回真值或者假值

3.1 算数运算符

**作用:**用于四则运算

算数运算符包括以下符号:

运算符术语示例结果
+正号+33
-负号-3-3
+10+515
-10-55
*10*550
/10/52
%取模(取余)10%31
++前置递增a=2;b=++a;a=3;b=3;
++后置递增a=2;b=a++;a=3;b=2;
前置递减a=2;b=–a;a=1;b=1;
后置递减a=2;b=a–;a=1;b=2;

加减乘除代码示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//加减乘除
	int a1 = 10;
	int b1 = 3;

	cout << a1 + b1 << endl;
	cout << a1 - b1 << endl;
	cout << a1 * b1 << endl;
	cout << a1 / b1 << endl; //两个整数相除,结果依然是整数,将小数部分去除

	double f1 = 10;
	double f2 = 3;
	cout << f1 / f2 << endl; //这样结果就有小数

	int a2 = 10;
	int b2 = 20;
	cout << a2 / b2 << endl; //0

	//int a3 = 10;
	//int b3 = 0; //除数不能为0
	//cout << a3 / b3 << endl;  非法操作

	system("pause");

	return 0;
}

取模运算示例:

注意:两个小数是不可以做取模运算的

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//取模运算本质
	int a1 = 10;
	int b1 = 3;

	cout << a1 % b1 << endl; //1

	int a2 = 10;
	int b2 = 20;
	cout << a2 % b2 << endl; //10

	//int a3 = 10;
	//int b3 = 0;
	//cout << a3 % b3 << endl;  非法

	//两个小数是不可以做取模运算的
	//double d1 = 3.14;
	//double d2 = 1.1;
	//cout << d1 % d2 << endl;

	system("pause");

	return 0;
}

递增递减示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//1.前置递增
	int a = 10;
	++a; //让变量进行+1的操作
	cout << "a = " << a << endl;

	//2.后置递增
	int b = 10;
	b++; //让变量进行+1的操作
	cout << "b = " << b << endl;

	//3.前置和后置的区别
	//前置递增,先让变量+1,然后进行表达式运算

	int a2 = 10;
	int b2 = ++a2 * 10;

	cout << "a2 = " << a2 << endl << "b2 = " << b2 << endl; //a2=11,b2=110

	//后置递增,先进行表达式运算,然后变量+1

	int a3 = 10;
	int b3 = a3++ * 10;

	cout << "a3 = " << a3 << endl << "b3 = " << b3 << endl; //a3=11,b3=100

	system("pause");

	return 0;
}

3.2 赋值运算符

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

赋值运算符包括以下几种符号:

运算符术语示例结果
=赋值a=2;b=3;a=2;b=3;
+=加等于a=0;a+=2;a=2;
-=减等于a=5;a-=3;a=2;
*=乘等于a=2;a*2;a=4;
/=除等于a=4;a/=2;a=2;
%=模等于a=3;a%2;a=1;

注:a+=2 就是 a=a+2 其他同理

简略示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	int a = 10;
	a += 2;
	cout << "a = " << a << endl; //12

	system("pause");

	return 0;
}

3.3 比较运算符

**作用:**用于表达式的比较,并返回一个真值或假值(用于判断!)

比较运算符有以下符号:

运算符术语示例结果
==相等于4 == 30
!=不相等4 != 31
<小于4 < 30
>大于4 > 31
<=小于等于4 <= 30
>=大于等于4>= 11

简略示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	bool bo = true;
	bo = 4 == 3;
	cout << bo << endl; //0

	//比较运算符
	//==
	int a = 10;
	int b = 20;
	cout << (a == b) << endl; //0 加()是先运算a == b再运算endl

	//!=
	cout << (a != b) << endl; //1

	//...

	system("pause");

	return 0;
}

3.4 逻辑运算符

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

逻辑运算符有以下符号:

运算符术语示例结果
!!a如果a为假,则!a为真;如果a为真,则!a为假
&&a&&b如果a和b都为真,则结果为真,否则为假
||a||b如果a和b有一个为真,则结果为真,二者都为假时,结果为假

**示例1:**逻辑非

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//逻辑运算符 非 !
	int a = 10;

	cout << !a << endl; //0
	cout << !!a << endl; //1

	system("pause");

	return 0;
}

总结:真变假,假变真

**示例2:**逻辑与

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//逻辑运算符 与 &&
	
	int a = 10;
	int b = 10;
	cout << (a && b) << endl; //1

	int c = 10;
	int d = 0;
	cout << (c && d) << endl; //0

	int e = 0;
	int f = 0;
	cout << (e && f) << endl; //0

	system("pause");

	return 0;
}

总结:都真为真,其余为假

**示例3:**逻辑或

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//逻辑运算符 或 ||

	int a = 10;
	int b = 10;
	cout << (a || b) << endl;

	int c = 10;
	int d = 0;
	cout << (c || d) << endl;

	int e = 0;
	int f = 0;
	cout << (e || f) << endl;

	system("pause");

	return 0;
}

总结:都假为假,其余为真

四、程序流程结构

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

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

4.1 选择语句

4.1.1 if语句

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

if语句的三种形式

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

1.单行格式的if语句:if(条件){条件满足的语句}

屏幕截图 2023-05-04 182131

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	int a = 0;
	cout << "请输入你的分数:";
	cin >> a;

	if (a > 503) //这里不能有分号
	{
		cout << "你能考上一所一本大学" << endl;
	}

	system("pause");

	return 0;
}

2.多行格式if语句:if(条件){条件满足的语句}else{条件不能满足的语句};

屏幕截图 2023-05-04 183531

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	int a = 0;
	cout << "请输入你的分数:";
	cin >> a;

	if (a >= 503) //这里不能有分号
	{
		cout << "你能考上一所一本大学" << endl;
	}
	else
	{
		cout << "你不能考上一本大学" << endl;
	}


	system("pause");

	return 0;
}

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-99pAaMF0-1686840888801)(E:\c.—c.—java-exercise\photo\屏幕截图 2023-05-04 211605.png)]

#include <iostream>
#include <string>

using namespace std;

int main()
{

	int a = 0;
	cout << "请输入你的分数:";
	cin >> a;

	if (a>=0&&a<446) //这里不能有分号
	{
		cout << "你啥也考不上,去专科吧" << endl;
	}
	else if(a>=446&&a<503)
	{
		cout << "你能考上二本大学" << endl;
	}
	else if(a>=503&&a<700)
	{
		cout << "一本啊一本" << endl;
	}
	else if(a>=700&&a<=750)
	{
		cout << "你牛逼" << endl;
	}
	else
	{
		cout << "啥?" << endl;
	}

	system("pause");

	return 0;
}

注意 与&& 或|| 符号的运用

**嵌套if语句:**在if语句中,可以嵌套使用if语句,达到更精确的条件判断

案例需求:

  • 提示用户输入一个高考考试分数,根据分数做如下判断
  • 分数如果大于600分视为考上一本,大于500分考上二本,大于400分考上三本,其余视为未考上本科
  • 在一本分数中,如果大于700分,考入北大,大于650,考入清华,大于600考入人大

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

/*
要求:
	- 提示用户输入一个高考考试分数,根据分数做如下判断
	- 分数如果大于600分视为考上一本,大于500分考上二本,大于400分考上三本,其余视为未考上本科
	- 在一本分数中,如果大于700分,考入北大,大于650,考入清华,大于600,考入人大
*/

	//输入分数
	int fen = 0;
	cout << "请输入你的分数:" << endl;
	cin >> fen;
	cout << "你输入的分数为 " << fen << endl;

	//判断一本600
	if (fen > 600)
	{
		cout << "恭喜你可以考上一本" << endl;

		//判断北大
		if (fen > 700)
		{
			cout << "恭喜你可以考上北大!" << endl;
		}

		//判断清华
		else if (fen > 650)
		{
			cout << "恭喜你可以考上清华!" << endl;
		}

		//判断人大
		else if (fen > 600)
		{
			cout << "恭喜你可以考上人大!" << endl;
		}
	}

	//判断二本500
	else if (fen > 500)
	{
		cout << "恭喜你可以考上二本" << endl;
	}

	//判断三本400
	else if (fen > 400)
	{
		cout << "恭喜你可以考上二本" << endl;
	}
	else
	{
		cout << "你啥jb也没考上兄弟" << endl;
	}

	system("pause");

	return 0;
}
if语句练习案例:三只小猪称体重

有三只小猪ABC,请分别输入三只小猪的体重,并且判断哪只小猪最重?

屏幕截图 2023-05-05 131212
#include <string>
#include <iostream>

using namespace std;

int main()
{

	//有三只小猪ABC,请分别输入三只小猪的体重,并且判断哪只小猪最重?
	
	//1.输入三只小猪的体重
	int arr[3] = {0};

	int i;
	for (i = 0; i < 3; i++)
	{
		cout << "请输入第" << i + 1 << "只小猪的体重:" << endl;
		cin >> arr[i];
		cout << "您输入的第" << i + 1 << "个小猪的体重为:" << arr[i] << endl;
	}

	//2.判断三只小猪哪只最重
	int max = arr[0];
	for (i = 1; i < 3; i++)
	{
		if (arr[i] > max)
		{
			max = arr[i];
		}
	}
	for (i = 0; i < 3; i++)
	{
		if (arr[i] == max)
		{
			cout << "第" << i + 1 << "只小猪最重,它的体重为" << arr[i] << endl;
		}
	}

	system("pause");
	return 0;
}
4.1.2 三目运算符

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

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

解释:

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

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

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{
	//三目运算符
	//创建三个变量 abc
	//将a和b比较,将变量大的值赋给c
	int a = 10;
	int b = 20;
	int c = 0;

	c = (a > b ? a : b);

	cout << "max1 = " <<c << endl;

	//在C++中三目运算符返回的是变量,可以继续赋值
	(a < b ? a : b) = 100;
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;

	return 0;
}
4.1.3 switch语句

**作用:**执行多条件的分支语句

语法:

switch(表达式)
{
        
    case 结果1:执行语句;break;
    
    case 结果2:执行语句;break;
        
    ...
        
    default:执行语句;break;
    
}

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//switch语句
	//给一个电影打分
	//10~9	经典
	//8~7	非常好
	//6~5	一般
	//5以下	烂

	//1.提示用户评分
	cout << "请给电影打分:" << endl;

	//2.用户开始打分
	int score = 0;
	cin >> score;
	cout << "您打出的分数为:" << score << endl;

	//3.根据用户输入的分数提示用户最后的结果
	switch (score)
	{
	case 10:
		cout << "您认为是经典电影" << endl;
		break;
	case 9:
		cout << "您认为是经典电影" << endl;
		break;
	case 8:
		cout << "您认为是非常好电影" << endl;
		break;
	case 7:
		cout << "您认为是非常好电影" << endl;
		break;
	case 6:
		cout << "您认为是一般电影" << endl;
		break;
	case 5:
		cout << "您认为是一般电影" << endl;
		break;
	default:
		cout << "您认为是垃圾电影" << endl;
		break;
	}

	//if 和 switch 区别?
	//switch 缺点,判断只能是整型或者字符型,不可以是一个区间
	//switch 优点,结构清晰,执行效率高

	system("pause");
	return 0;
}

switch优缺点:

  1. 缺点:判断只能是整型或者字符型,不可以是一个区间
  2. 优点:结构清晰,执行效率高

4.2 循环结构

4.2.1 while循环语句

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

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

**解释:**只要循环条件为真,就执行语句

屏幕截图 2023-05-05 155135

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//while循环
	//在屏幕中打印 0~9 这十个数字
	int num = 0;
	while (num < 10)
	{
		cout << num << endl;
		num++;
	}

	system("pause");
	return 0;
}

注意:记得提供挑出循环的出口,否则会出现死循环

while循环练习案例:猜数字

**案例描述:**系统随机生成一个1-100之间的数字,玩家进行猜测,如果猜错,提示玩家数字过大或者过小,如果猜对恭喜玩家胜利,并且退出游戏

屏幕截图 2023-05-05 161445

流程图:

屏幕截图 2023-05-05 161751

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//1.系统生成随机数
	int num = rand() % 100 + 1;	//生成 0 + 1 ~ 99 + 1 的随机数

	cout << "随机数 = " << num << endl;  //可屏蔽,这里做示范

	//2.玩家进行猜测
	int val = 0;
	
	//3.判断玩家的猜测
	while (1)
	{
		cin >> val;

		if (val < num)
		{
			cout << "你输入的数字小了,请重新输入" << endl;
		}
		else if (val > num)
		{
			cout << "你输入的数字大了,请重新输入" << endl;
		}
		else
		{
			cout << "对溜!" << endl;
			break;
		}
	}
	//猜错	提示猜的结果	过大或者过小
	//猜对	恭喜

	system("pause");
	return 0;
}

注:添加随机数种子(小方法)

#include <iostream>
#include <string>
//time系统时间头文件包含
#include <ctime>

using namespace std;

int main()
{

	//添加随机数种子,作用利用当前系统时间生成随机数,防止每次随机数都一样
	srand((unsigned int)time(NULL));

	int num = rand() % 100;

	cout << "随机数:" << num << endl;

	system("pause");
	return 0;
}
4.2.2 do…while循环语句

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

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

**注意:**与while的区别在于do…while会先执行一次循环语句,再判断循环条件

屏幕截图 2023-05-05 170940

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//do...while语句
	//在屏幕中输出 0 到 9 这十个数字

	int num = 0;

	do
	{
		cout << num << endl;
		num++;
	}
	while (num < 10);

	//do...while和while循环的区别在于do...while会先执行一次循环语句

	system("pause");
	return 0;
}

总结:do…while和while循环的区别在于do…while会先执行一次循环语句

练习案例:水仙花数

**案例描述:**水仙花是指一个三位数,它的每个位上的数字的三次幂之和等于它本身

例如:1^3 + 5^3 + 3^3 = 153

请用do…while语句,求出所有三位数中的水仙花数

示例:

#include <iostream>
#include <string>

using namespace std;

/*
案例描述:水仙花是指一个三位数,它的每个位上的数字的三次幂之和等于它本身

例如:1^3 + 5^3 + 3^3 = 153

请用do...while语句,求出所有三位数中的水仙花数
*/

int main()
{

	double num = 100;
	int bai = 0, shi = 0, ge = 0;


	do {
		bai = (int)(num * 0.01);
		shi = (int)((num-bai*100) * 0.1);
		ge = (int)(num - bai * 100 - shi * 10);
		if ((bai * bai * bai + shi * shi * shi + ge * ge * ge) == num)
		{
			cout << num << "是水仙花数" << endl;
		}
		num++;
	} while (num < 1000);

	system("pause");
	return 0;
}

//或者取余
//ge = num % 10;
//shi = num / 10 % 10;
//bai = num / 100;
4.2.3 for循环语句

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

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

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	int i = 0;
	
	for (i = 0; i < 10; i++) //或者在内部定义i for (int i = 0 ; i < 10 ; i++)
	{
		cout << i << endl;
	}

	system("pause");
	return 0;
}


//for循环可拆分为以下形式

//int i = 0;
//for ( ; ; )
//{
//	if (i >= 10)
//	{
//		break;
//	}
//	i++;
//}

详解:

屏幕截图 2023-05-05 181224

注意:for循环中的表达式,要用分号进行分隔

总结:while,do…while,for都是开发中常用的循环语句,for循环结构比较清晰,比较常用

练习案例:敲桌子

案例描述:从1开始数到数字100,如果数字个位含有7,或者数字十位含有7,或者该数字是7的倍数,我们打印敲桌子,其余数字直接打印输出

c6d7ce76d327e87a

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	for (int i = 1; i <= 100; i++)
	{
		if (i % 10 == 7 || i / 10 == 7 || i % 7 == 0)
		{
			cout << "敲桌子" << endl;
		}
		else
		{
			cout << i << endl;
		}
	}

	system("pause");
	return 0;
}
4.2.4 嵌套循环

**作用:**在循环体中再嵌套一层循环,解决一些实际问题

例如我们想在屏幕中打印如下图片,就需要利用嵌套循环

屏幕截图 2023-05-05 182822

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//利用嵌套循环实现星图

	//打印一行星图

	//外层循环
	for (int i = 0; i < 10; i++)
	{
		//内层循环
		for (int j = 0; j < 10; j++)
		{
			cout << "* ";
		}
		cout << endl;
	}

	system("pause");
	return 0;
}

练习案例:乘法口诀表

案例描述:利用嵌套循环,实现九九乘法表

669bc2f8c200491583e3e4088506f3a1

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//九九乘法表
	for (int i = 1; i <= 9; i++)
	{
		for (int j = 1; j <= 9; j++)
		{
			if (j <= i)
			{
				cout << i << " * " << j << " = " << i * j << "\t";
			}
		}
		cout << endl;
	}
	system("pause");
	return 0;
}

4.3 跳转语句

4.3.1 break语句

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

break使用的时机:

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

示例1:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//break的使用时机

	//1.出现在switch语句中
	cout << "请选择副本难度" << endl;
	cout << "1.普通" << endl;
	cout << "2.中等" << endl;
	cout << "3.困难" << endl;
	
	int select = 0; //创建一个选择结果的变量

	cin >> select; //等待用户输入数据

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

	//2.出现在循环语句中
	for (int i = 0; i < 10; i++)
	{
		cout << i << endl;

		//如果i = 5,退出循环,不再打印
		if (i == 5)
		{
			break;
		}
	}

	//3.出现在嵌套循环语句中
	for (int i = 0; i < 10; i++)
	{

		for (int j = 0; j < 10; j++)
		{
			cout << "* ";
			if (j == 5)
			{
				break; //退出内层循环
			}
		}
		cout << endl;
	}

	system("pause");
	return 0;
}
4.3.2 continue语句

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

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//continue语句的用途

	for (int i = 0; i <= 100; i++)
	{
		//如果是奇数输出,偶数不输出
		if (i % 2 == 0)
		{
			continue; //可以筛选条件,执行到此就不再向下执行,执行下一次循环
		}
		cout << i << endl;
	}

	system("pause");
	return 0;
}
4.3.3 goto语句

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

语法:goto 标记;

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

屏幕截图 2023-05-06 162132

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//goto语句

	cout << "1.XXXX" << endl;

	cout << "2.XXXX" << endl;

	goto FLAG;

	cout << "3.XXXX" << endl;

	cout << "4.XXXX" << endl;

	cout << "5.XXXX" << endl;

FLAG:

	cout << "6.XXXX" << endl;

	system("pause");
	return 0;
}

注:不经常用,不建议用

五、数组

5.1 概括

所谓数组,就是一个集合,里面存放了相同的数据元素

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

**特点2:**数组是由连续的内存位置组成的

5.2 一维数组

5.2.1 一维数组定义方式

三种方式:

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

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

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

	//1.数据类型 数组名[数组长度];
	int arr[5];
	//给数组中的元素进行赋值
	//数组元素的下标是从0开始的
	arr[0] = 10;
	arr[1] = 20;
	arr[2] = 30;
	arr[3] = 40;
	arr[4] = 50;

	//访问数据元素
	cout << arr[0] << endl;
	cout << arr[1] << endl;
	cout << arr[2] << endl;
	cout << arr[3] << endl;
	cout << arr[4] << endl;

	//2.数据类型 数组名[数组长度] = {值1,值2,...};
	//如果初始化数据时,没全部填写完,会用0来填补数据
	int arr2[5] = { 10,20,30 };

	cout << arr2[0] << endl;
	cout << arr2[1] << endl;
	cout << arr2[2] << endl;
	cout << arr2[3] << endl;
	cout << arr2[4] << endl;

	//利用循环 输出数组中的元素
	for (int i = 0; i < 5; i++)
	{
		cout << arr2[i] << endl;
	}

	//3.数据类型 数组名[] = { 值1,值2,... };
	//定义数组的时候,必须有初始长度
	int arr3[] = { 90,80,70,60,50,40,30,20,10 };
	for (int j = 0; j < 9; j++)
	{
		cout << arr3[j] << endl;
	}

	system("pause");
	return 0;
}
5.2.2 一维数组数组名

一维数组名称的用途

  1. 可以统计整个数组在内存中的长度 sizeof(arr)
  2. 可以获取数组在内存中的首地址 cout << arr <<endl;

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//数组名的用途

	//1.可以通过数组名统计整个数组占用内存大小
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	cout << "整个数组占用的内存空间为:" << sizeof(arr) << endl;
	cout << "整个数组占用的内存空间为:" << sizeof(arr) << endl;
	cout << "数组中元素个数是多少:" << sizeof(arr)/sizeof(arr[0]) << endl;

	//2.可以通过数组名查看数组首地址
	cout << "数组的首地址为:" << (int)arr << endl;
	cout << "数组中第一个元素的地址:" << (int) & arr[0] << endl;
	cout << "数组中第二个元素的地址:" << (int) & arr[1] << endl;

	//数组名是常量,不可以进行赋值操作,它就等于他的首地址(初始是16进制的)

	system("pause");
	return 0;
}

练习案例1:

案例描述:

在一个数组中记录了五只小猪的体重,如:int arr[5] = {300,350,200,400,250};

要求:找出并打印最重的小猪的体重

#include <iostream>
#include <string>

using namespace std;

int main()
{

	/*
	在一个数组中记录了五只小猪的体重,如:int arr[5] = {300,350,200,400,250};
	要求:找出并打印最重的小猪的体重
	*/

	//定义数组
	int arr[5] = { 300,350,200,400,250 };

	//判断最重的小猪
	int max = arr[0];
	for (int i = 1; i < 5; i++)
	{
		if (max < arr[i])
		{
			max = arr[i];
		}
	}

	//输出最重小猪体重
	cout << "最重的小猪体重为:" << max << endl;

	system("pause");
	return 0;
}

**练习案例2:**数组元素逆置

**案例描述:**请声明一个5个元素的数组,并且将元素逆置

(如原数组为 1,2,3,4,5; 逆置输出后为 5,4,3,2,1; )

#include <iostream>
#include <string>

using namespace std;

int main()
{

	/*
	请声明一个5个元素的数组,并且将元素逆置
	(如原数组为 1,2,3,4,5; 逆置输出后为 5,4,3,2,1; )
	*/

	//定义数组
	int arr[] = { 1,2,3,4,5 };

	//计算数组长度
	int length = sizeof(arr) / sizeof(arr[0]);

	cout << "数组逆置前:" << endl;
	for (int i = 0; i < length; i++)
	{
		cout << arr[i] << endl;
	}

	cout << "数组逆置后:" << endl;
	for (int i = 0; i < length; i++) //例子中,长度5,循环5次
	{
		cout << arr[length - (i + 1)] << endl; //最后的元素就是 arr[length-1]
	}

	system("pause");
	return 0;
}
5.2.3 冒泡排序

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cEXfCwL9-1686840888802)(E:\c.—c.—java-exercise\photo\屏幕截图 2023-05-06 180114.png)]

**示例:**将数组{4,2,8,0,5,7,1,3,9}进行升序排序

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//冒泡排序
	//题目:将数组{4,2,8,0,5,7,1,3,9}进行升序排序
	int arr[] = { 4,2,8,0,5,7,1,3,9 };
	int length = sizeof(arr) / sizeof(arr[0]);
	int a = 0;
	int b = 0;
	
	for (int j = 0; j < length - 1; j++) //3.总共需要排序 length-1 次
	{
		for (int i = 0; i < length - (j + 1); i++) //2.总共有length个元素,那就调换 length-1 次
		{
			if (arr[i] > arr[i + 1]) //1.如果前一个元素比后一个元素大,就调换一下它俩的位置,最后挑一个最大的到最右边
			{
				a = arr[i];
				b = arr[i + 1];
				arr[i + 1] = a;
				arr[i] = b;
			}
		}
	}

	//输出最终数组
	cout << "最终数组为:" << endl;
	for (int i = 0; i < length; i++)
	{
		cout << arr[i] << " " ;
	}

	system("pause");
	return 0;
}

5.3 二维数组

二位数组就是在一维数组的基础上,多加一个维度

屏幕截图 2023-05-06 192827
5.3.1 二维数组定义方式

四种方式:

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

建议:以上4种定义方式,利用==第二种更加直观,提高代码的可读性==

图例:arr[2][3]

屏幕截图 2023-05-06 193934

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//2.二维数组的定义方式

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

	//1. 数据类型 数组名[行数][列数];
	int arr[2][3] = { 0 };

	arr[0][1] = 2;
	cout << arr[0][1] << endl;

	//遍历方法:外层循环打印行数,内层循环打印列数
	for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			cout << arr[i][j] << " ";
		}
		cout << endl;
	}

	//2.数据类型 数组名[行数][列数] = {{数据1,数据2},{数据3,数据4}};
	int arr1[2][3] = {
		{1,2,3},
		{4,5,6}
	};
	for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			cout << arr1[i][j] << " ";
		}
		cout << endl;
	}

	//3.数据类型 数组名[ ][列数] = {数据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;
	}

	//4.数据类型 数组名[ ][列数] = {数据1,数据2,数据3,数据4};
	int arr3[][3] = { 1,2,3,4,5,6 };
	for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			cout << arr3[i][j] << " ";
		}
		cout << endl;
	}


	system("pause");
	return 0;
}

第二种最直观最常用

5.3.2 二维数组数组名
  • 查看二维数组所占内存空间
  • 获取二维数组首地址

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//二维数组名称用途

	//1.可以查看占用的内存空间大小
	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;

	//2.可以查看二位数组的首地址
	cout << "二维数组首地址:" << (int)arr << endl;
	cout << "二维数组第一行的首地址:" << (int)arr[0] << endl;
	cout << "二维数组第二行的首地址:" << (int)arr[1] << endl;

	cout << "二维数组第一个元素的首地址:" << (int)&arr[0][0] << endl; // &!!!


	system("pause");
	return 0;
}
5.3.3 二维数组应用案例

考试成绩统计:

案例描述:有三民同学(张三,李四,王五),在一次考试中的成绩分别如下表,请分别输出三名同学的总成绩

语文数学英语
张三100100100
李四9050100
王五607080

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	/*
	案例描述:有三民同学(张三,李四,王五),在一次考试中的成绩分别如下表
				请分别输出三名同学的总成绩
	*/

	int sum = 0;

	int arr[3][3] =
	{
		{100,100,100},
		{90,50,100},
		{60,70,80}
	};

	string name[3] = { "张三","李四","王五" };

	for (int j = 0; j < 3 ; j++)
	{
		for (int i = 0; i < 3; i++)
		{
			sum = sum + arr[j][i];
		}
		
		cout << name[j] << "同学的总成绩为:" << sum << endl;

		sum = 0;
	}

	system("pause");
	return 0;
}

六、函数

6.1 概述

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

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

6.2 函数的定义

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

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

语法:

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

图例:

屏幕截图 2023-05-06 222220 屏幕截图 2023-05-06 223422

加法示例代码:

#include <iostream>
#include <string>

using namespace std;

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

int main()
{
	system("pause");
	return 0;
}
  • 返回值类型:一个函数可以返回一个值,在函数定义中
  • 函数名:给函数起个名称
  • 参数列表:使用该函数时,传入的数据
  • 函数体语句:花括号内的代码,函数内需要执行的语句
  • return 表达式:和返回值类型挂钩,函数执行完后,返回相应的数据

6.3 函数的调用

**功能:**使用定义好的函数

语法:函数名(参数)

示例:

#include <iostream>
#include <string>

using namespace std;

//函数的定义
//函数定义时,num1和num2并没有真的数据,他只是一个形式上的参数,简称形参
int add(int num1, int num2)
{
	int sum = num1 + num2;
	return sum;
}

int main()
{
	cout << "加法计算,请输入两个数字,中间用空格隔开:" << endl;
	int b, c;
	cin >> b;
	cin >> c;

	// a 和 b 称为 实际参数,简称实参
	//当调用函数的时候,实参的值会传递给形参
	int a = add(b,c);
	cout << "两数相加为:" << a << endl;

	system("pause");
	return 0;
}

6.4 值传递

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

示例:

#include <iostream>
#include <string>

using namespace std;

//值传递
//定义函数,实现两个数字交换的函数

//如果函数不需要返回值,声明的时候可以写 void(翻译:无效)
void swap(int num1, int num2)
{

	cout << "交换前:" << endl;
	cout << "num1 = " << num1 << endl;
	cout << "num2 = " << num2 << endl;

	int temp = num1;
	num1 = num2;
	num2 = temp;

	cout << "交换后:" << endl;
	cout << "num1 = " << num1 << endl;
	cout << "num2 = " << num2 << endl;

	return;
}

int main()
{

	int a = 10;
	int b = 20;
	
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;

	//当我们做值传递的时候,函数的形参发生改变,不会影响到实参
	swap(a, b);

	cout << "a = " << a << endl;
	cout << "b = " << b << endl;

	system("pause");
	return 0;
}

6.5 函数的常见样式

常见样式有4种

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

示例:

#include <iostream>
#include <string>

using namespace std;

//函数的常见样式

//1.无参无返
void test01()
{
	cout << "helloworld" << endl;
}

//2.有参无返
void test02(int a)
{
	cout << "test02 a = " << a << endl;
}

//3.无参有返
int test03()
{
	cout << "test03" << endl;

	return 1000;
}

//4.有参有返
int test04(int num1)
{
	int sum = num1 + 10;
	return sum;
}

int main()
{

	//无参无返的函数调用
	test01();

	//有参无返的函数调用
	test02(100);

	//无参有返函数调用
	int num1 = test03();
	cout << "num1 = " << num1 << endl;

	//有参有返函数调用
	int num2 = 10;
	cout << "num2 + 10 = " << test04(num2) << endl;

	system("pause");
	return 0;
}

6.6 函数的声明

**作用:**告诉编译器函数名称及如何调用函数,函数的实际主体可以单独定义

  • 函数的声明可以多次,但是函数的定义只能有一次

示例:

#include <iostream>
#include <string>

using namespace std;

//函数的声明
//比较函数,实现两个整型数字进行比较,返回较大的值

//定义
//int max(int a, int b)
//{
//	//int Max = (a >= b ? a : b);
//	//return Max;
//
//	return a >= b ? a : b;
//
//}

//提前告诉编译器函数的存在,可以利用函数的声明(如果定义在main前可以不用声明)
//声明可以多次,定义只能有一次
int max(int a, int b);
//这一步其实vs2022可以不用了

int main()
{

	//声明可以多次,定义只能有一次

	int a = 10;
	int b = 20;

	cout << max(a, b) << endl;

	system("pause");
	return 0;
}


int max(int a, int b)
{
	//int Max = (a >= b ? a : b);
	//return Max;

	return a >= b ? a : b;

}

6.7 函数的分文件编写

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

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

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

示例:

头文件 swap.h

//声明
void swap(int a, int b);

源文件 swap.cpp

#include <iostream>
#include "swap.h" //双引号代表自定义

using namespace std;

//定义
void swap(int a, int b)
{
	int c = a;
	a = b;
	b = c;

	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
}

主文件 函数的分文件编写

#include <iostream>
#include <string>

#include "swap.h"

using namespace std;

//函数的分文件编写
//实现两个数字交换的函数

//函数的声明
//void swap(int a, int b);

//函数的定义
//void swap(int a, int b)
//{
//	int c = a;
//	a = b;
//	b = c;
//
//	cout << "a = " << a << endl;
//	cout << "b = " << b << endl;
//}

int main()
{

	int a = 10;
	int b = 20;

	swap(a, b);

	system("pause");
	return 0;
}

注:#include “swap.h” //双引号代表自定义

七、指针

7.1 指针的基本概念

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

  • 内存编号是从0开始记录的,一般用十六进制数字表示
  • 可以利用指针变量保存地址
屏幕截图 2023-05-07 014454

可以认为,指针就是一个地址

实际上,指针是一个变量,其中保存着地址

7.2 指针变量的定义和使用

指针变量定义语法:数据类型 * 变量名

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//1.定义指针
	int a = 10;
	//指针定义的语法:数据类型 * 指针变量名;
	int* p = &a; //让指针记录变量a的地址

	cout << "a的地址为:" << &a << endl;
	cout << "指针p为:" << p << endl;

	//2.使用指针
	//可以通过解引用的方式来找到指针指向的内存
	//指针前加一个 * 代表解引用,找到指针指向的内存中的数据

	*p = 1000;
	cout << "a = " << a << endl;
	cout << "*p = " << *p << endl;

	system("pause");
	return 0;
}

7.3 指针所占空间

提问:指针也是种数据类型,那么这种数据类型占用多少内存空间?

  1. 32位操作系统下,任何类型的指针都是4个字节
  2. 64位操作系统下,占8个字节

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//指针所占内存空间
	int a = 10;
	//int* p;
	//p = &a;

	int* p = &a;

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

	system("pause");
	return 0;
}

7.4 空指针和野指针

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

**用途:**初始化指针变量

**注意:**空指针指向的内存是不可以访问的,0-255的内存是系统占用的,我们不能访问

示例1:空指针

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//空指针
	//1.用于给指针变量初始化
	int* p = NULL; //NULL = 0;

	//2.空指针是不能用于访问的
	//0~255之间的内存编号是系统占用的,因此不可以访问
	 
	//*p = 100;

	int a = 10;
	p = &a;

	cout << "*p = " << *p << endl;

	system("pause");
	return 0;
}

**野指针:**指针变量指向非法的内存空间(你无法操控的内存空间等)

示例2:野指针

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//野指针
	//在程序中,尽量避免出现野指针
	int* p = (int*)0x1100;

	//cout << *p << endl;

	system("pause");
	return 0;
}

总结:空指针和野指针都不是我们申请的空间,因此不要访问

7.5 const修饰指针

const修饰指针的三种情况:

  1. const 修饰指针 — 常量指针
  2. const 修饰常量 — 指针常量
  3. const 既修饰指针,又修饰常量

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Iv1H2HNl-1686840888803)(E:\c.—c.—java-exercise\photo\屏幕截图 2023-05-07 175813.png)]

  • 常量指针:const int* p = &a;
  • 特点:指针的指向可以改,但是指针指向的值不能改,即const作用在指向的变量上

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GpDuH2yV-1686840888803)(E:\c.—c.—java-exercise\photo\屏幕截图 2023-05-07 180925.png)]

  • 指针常量:int* const p = &a;

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

  • const即修饰指针,又修饰常量

  • const int* const p = &a;

  • 特点:指针的指向和指针的值都不能改

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//1.常量指针
	int a = 10;
	int b = 10;

	const int* p = &a;
	//指针指向的值不能改,指向可以改
	//*p = 20; 错误
	p = &b; //正确

	//2.指针常量
	int* const p1 = &a;
	*p1 = 20; //正确
	//p2 = &b; 错误

	//3.const修饰常量和指针
	const int* const p2 = &a;
	//*p2 = 20; 错误
	//p2 = &b; 错误

	system("pause");
	return 0;
}

7.6 指针和数组

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

示例:

#include <iostream>
#include <string>

using namespace std;

int main()
{

	//指针和数组
	//利用指针访问数组

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

	cout << "第一个元素是:" << arr[0] << endl;

	int* p = arr; //arr存放了数组的首地址

	cout << "利用指针来访问第一个元素:" << *p << endl;

	p++; //往后推四个字节,整型指针直接++就行

	cout << "利用指针来访问第二个元素:" << *p << endl;


	cout << "利用指针遍历数组:" << endl;
	int* p2 = arr;
	for (int i = 0; i < 10; i++)
	{
		cout << "数组中第" << i + 1 << "个元素为:" << *p2 << endl;
		p2++;
	}

	system("pause");
	return 0;
}

7.7 指针和函数

**作用:**利用指针作函数的参数,可以修改实参的值

示例:

#include <iostream>
#include <string>

using namespace std;

//实现两个数字互换
void swap1(int num1, int num2)
{
	int temp = num1;
	num1 = num2;
	num2 = temp;
	
	cout << "swap1 a = " << num1 << endl;
	cout << "swap1 b = " << num2 << endl;
}

void swap2(int* p1, int* p2)
{
	int temp = *p1;
	*p1 = *p2;
	*p2 = temp;
}

int main()
{

	//指针和函数

	int a = 10;
	int b = 20;

	//1.值传递
	//swap1(a, b);

	//2.地址传递
	//如果是地址传递,可以修饰实参
	//也就是说传进去地址,然后解地址直接操作地址指向的内存
	swap2(&a, &b);

	cout << "a = " << a << endl; //20
	cout << "b = " << b << endl; //10

	system("pause");
	return 0;
}
  1. 值传递:传进去的是值,实参不被操作
  2. 地址传递:可以修饰实参,也就是说传进去地址,然后解地址直接操作地址指向的内存

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

7.8 指针、数组、函数

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

例如:

数组:int arr[10] = {4,3,6,9,1,2,10,8,7,5};

!注:在 C++ 中,要声明一个二维数组作为函数参数,需要指定数组的列数。!

示例:

#include <iostream>
#include <string>

using namespace std;

void bublleSort(int* arr,int length) //int* arr也可以写成int arr[]
{
	for (int i = 0; i < length-1; i++)
	{
		for (int j = 0; j < length-1; j++)
		{
			if (*(arr + j) > *(arr + 1 + j)) //也可以写成 arr[j] > arr[j + 1]
			{
				int temp = *(arr + 1 + j);
				*(arr + 1 + j) = *(arr + j);
				*(arr + j) = temp;
			}
		}
	}
}

int main()
{

	/*
	案例描述:封装一个函数,利用冒泡排序,实现对整型数组的升序排序
	int arr[10] = {4,3,6,9,1,2,10,8,7,5};
	*/

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

	bublleSort(arr, 10);

	for (int i = 0; i < 10; i++)
	{
		cout << arr[i] << endl;
	}

	system("pause");
	return 0;
}

八、结构体

8.1 结构体基本概念

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

8.2 结构体定义和使用

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

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

  • struct 结构体名 变量名
  • struct 结构体名 变量名 = {成员1值,成员2值…}
  • 定义结构体时顺便创建变量

示例:

#include <iostream>
#include <string>

using namespace std;

//1.创建学生数据类型:包括(姓名,年龄,分数)
//自定义数据类型,一些类型集合组成的一个类型
//语法 struct 类型名称 {成员列表}
struct Student //放属性的
{
	//成员列表

	//姓名
	string name;

	//年龄
	int age;

	//分数
	double score;
}s3; //顺便创建结构体变量

//2.通过学生数据类型创建具体的学生

//2.1 struct Student s1;
//2.2 struct Student s2 = {...};
//2.3 在定义结构体时顺便创建结构体变量

int main()
{

//2.1 struct Student s1
	//struct关键字可以省略
	/*struct*/ Student s1; //s1算是成员
	//给 s1 属性赋值,通过 . 访问结构体变量中的属性
	s1.name = "张三";
	s1.age = 18;
	s1.score = 100;

	cout << "姓名:" << s1.name << endl;
	cout << "年龄:" << s1.age << endl;
	cout << "成绩:" << s1.score << endl;

//2.2 struct Student s2 = {...}
//struct可以省略
	struct Student s2 = { "李四",20,80 };
	cout << "姓名:" << s2.name << endl;
	cout << "年龄:" << s2.age << endl;
	cout << "成绩:" << s2.score << endl;

//2.3 在定义结构体时顺便创建结构体变量(创建代码示例在上面)
//一般不用
	s3.name = "王五";
	s3.age = 19;
	s3.score = 90;

	system("pause");
	return 0;
}

总结1:定义结构体时的关键字struct,不可省略

总结2:创建结构体变量时,关键字struct,可以省略

总结3:结构体变量利用操作符 . 访问成员(属性)

8.3 结构体数组

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

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

示例:

#include <iostream>
#include <string>

using namespace std;

//1.定义结构体
struct student
{
	string name;
	int age;
	double score;
};

int main()
{

	//2.创建结构体数组
	struct student stuArray[3] =
	{
		{"张三",18,100},
		{"李四",19,90},
		{"王五",18,80}
	};

	//3.给结构体数组中的元素赋值
	stuArray[2].name = "赵六";
	stuArray[2].age = 80;
	stuArray[2].score = 60;

	//4.遍历结构体数组
	for (int i = 0; i < 3; i++)
	{
		cout << "姓名:" << stuArray[i].name << endl;
		cout << "年龄:" << stuArray[i].age << endl;
		cout << "分数:" << stuArray[i].score << endl;
	}

	system("pause");
	return 0;
}

8.4 结构体指针

**作用:**通过指针访问结构体中的成员

  • 利用操作符 -> 可以通过结构体指针访问结构体属性

示例:

#include <iostream>
#include <string>

using namespace std;

//结构体指针

//定义学生的结构体
struct student
{
	string name;
	int age;
	int score;
};

int main()
{

	//创建学生的结构体变量
	student s = { "张三",18,100 };

	//通过指针指向结构体变量
	student* p = &s;

	//通过指针访问结构体变量中的数据
	//通过结构体指针 访问结构体中的属性,需要利用 '->'
	cout << "姓名:" << p->name << endl;
	cout << "年龄:" << p->age << endl;
	cout << "成绩:" << p->score << endl;

	system("pause");
	return 0;
}

总结:结构体指针可以通过 -> 操作符 来访问结构体中的成员

8.5 结构体嵌套结构体

**作用:**结构体中的成员可以是另一个结构体

**例如:**每个老师辅导一个学生,一个老师的结构体中,记录一个学生的结构体

示例:

#include <iostream>
#include <string>

using namespace std;

//学生结构体的定义
struct student
{
	string name;	//学生姓名
	int age;		//学生年龄
	int score;		//学生分数
};

//教师结构体的定义
struct teacher
{
	int id;			//职工id
	string name;	//职工姓名
	int age;		//职工年龄
	student stu1;	//子结构体 教的学生
};

int main()
{

	teacher t;
	t.id = 10000;
	t.name = "老王";
	t.age = 50;
	t.stu1.name = "小王";
	t.stu1.age = 20;
	t.stu1.score = 60;

	cout << "老师编号:" << t.id << endl;
	cout << "老师名字:" << t.name << endl;
	cout << "老师年龄:" << t.age << endl;
	cout << "老师辅导的学生姓名:" << t.stu1.name << endl;
	cout << "老师辅导的学生年龄:" << t.stu1.age << endl;
	cout << "老师辅导的学生分数:" << t.stu1.score << endl;

	system("pause");
	return 0;
}

总结:在结构体中可以定义另一个结构体作为成员,用来解决实际问题

8.6 结构体做函数参数

**作用:**将结构体作为参数向函数中传递

传递方式有两种:

  • 值传递(实参不被改变)
  • 地址传递(实参被改变)

示例:

#include <iostream>
#include <string>

using namespace std;

//学生结构体定义
struct student
{
	//姓名
	string name;
	//年龄
	int age;
	//分数
	int score;
};

//打印学生信息的函数
//1.值传递
void printStudent1(student s)
{
	s.score = 100;
	cout << "在子函数中 姓名:" << s.name << endl;
	cout << "在子函数中 年龄:" << s.age << endl;
	cout << "在子函数中 分数:" << s.score << endl; //100
}

//2.地址传递
void printStudent2(student* p)
{
	p->score = 100;
	cout << "在子函数2中 姓名:" << p->name << endl;
	cout << "在子函数2中 年龄:" << p->age << endl;
	cout << "在子函数2中 分数:" << p->score << endl; //100
}

int main()
{

	//结构体做函数参数
	//将学生传入到一个参数中,打印学生身上的所有信息

	//创建结构体变量
	student s;
	s.name = "张三";
	s.age = 20;
	s.score = 85;

	printStudent1(s);
	cout << "main函数中打印 姓名:" << s.name << endl;
	cout << "main函数中打印 年龄:" << s.age << endl;
	cout << "main函数中打印 分数:" << s.score << endl; //85

	printStudent2(&s);
	cout << "main函数中打印 姓名:" << s.name << endl;
	cout << "main函数中打印 年龄:" << s.age << endl;
	cout << "main函数中打印 分数:" << s.score << endl;  //100

	system("pause");
	return 0;
}

总结:如果不想修改主函数中的数据,用值传递,反之用地址传递

8.7 结构体中 const 的使用场景

**作用:**用const来防止误操作

  • 值传递实际是复制出副本,太大不好优化
  • 要调用大的数据时可以直接地址传递

示例:

#include <iostream>
#include <string>

using namespace std;

//const的使用场景

struct student
{
	string name;//姓名
	int age;//年龄
	int score;//分数
};

//将函数中的形参改为指针,可以减少内存空间,而且不会复制新的副本出来
void printStudent(const student* p) //指针只占4个字节
{
	//p->name = "李四"; 不行 加入const之后,一旦有修改的操作就会报错,可以防止我们误操作
	cout << "学生姓名为:" << p->name << endl; // (*p).name 也可以
	cout << "学生年龄为:" << p->age << endl;
	cout << "学生分数为:" << p->score << endl;
}

int main()
{

	//创建结构体变量
	student s = { "张三",15,70 };

	//通过函数打印结构体变量的信息
	printStudent(&s);

	system("pause");
	return 0;
}

8.8 结构体案例

8.8.1 案例1

案例描述:

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

设计学生和老师的结构体,其中在老师的结构体中,有老师姓名和一个存放5名学生的数组作为成员

学生的成员有姓名、考试分数,创建数组存放3名老师,通过函数给每个老师及所带的学生赋值

最终打印出老师数据以及老师所带的学生数据

示例:

#include <iostream>
#include <string>
#include <ctime>

using namespace std;

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

设计学生和老师的结构体,其中在老师的结构体中,有老师姓名和一个存放5名学生的数组作为成员

学生的成员有姓名、考试分数,创建数组存放3名老师,通过函数给每个老师及所带的学生赋值

最终打印出老师数据以及老师所带的学生数据
*/

//创建老师结构体
struct student
{
	string name;//学生姓名
	int score;//学生分数
};

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

//创建赋值函数
void assign(teacher teacher[], int len)
{
	string nameSeed = "ABCDE";
	//给老师赋值
	for (int i = 0; i < len; i++)
	{
		teacher[i].name = "teacher_";
		teacher[i].name += nameSeed[i];

		//给学生赋值
		for (int j = 0; j < 5; j++)
		{
			teacher[i].student[j].name = "student_";
			teacher[i].student[j].name += nameSeed[j];

			int random = rand() % 101; //随机数

			teacher[i].student[j].score = random;
		}
	}
}


//打印所有信息
void printInfo(teacher teacher[], int len)
{
	for (int i = 0; i < 3; i++)
	{

		cout << "教师姓名:" << teacher[i].name << endl;
		cout << "学生信息:" << endl;

		for (int j = 0; j < 5; j++)
		{
			cout << "学生姓名:" << teacher[i].student[j].name << endl;
			cout << "学生成绩:" << teacher[i].student[j].score << endl;
		}
	}
}

int main()
{
	//随机数种子
	srand((unsigned int)time(NULL));
	//srand是C语言中的随机数种子函数,它与rand()函数一同使用,用来产生随机数。
	//无符号整数(Unsigned Integer)是一种整数类型,用于存储正整数或零。它与有符号整数类型相似,但有一个重要的区别,即它不允许存储负数。
	//time(NULL)函数返回当前时间的UTC时间戳,以秒为单位。
	//记得包含头文件 #include <ctime>

	//给学生和老师赋值
	teacher teacher[3];
	int len = sizeof(teacher) / sizeof(teacher[0]);
	assign(teacher,len);
	
	//打印所有老师和学生的信息
	printInfo(teacher, len);

	system("pause");
	return 0;
}
8.8.2 案例2

案例描述:

设计一个英雄的结构体,包括成员姓名,年龄,性别;创建结构体数组,数组中存放5名英雄。

通过冒泡排序的算法,将数组中的英雄按照年龄进行升序排序,最终打印排序后的结果。

#include <iostream>
#include <string>

using namespace std;

struct hero
{
	string name;//名字
	int age;//年龄
	string sex;//性别
};

//冒泡排序算法
void bubbleSort(hero revenger[], int len)
{
	for (int i = 0; i < len - 1; i++)
	{
		for (int j = 0; j < len - 1; j++)
		{
			if (revenger[j].age > revenger[j + 1].age)
			{
				hero temp = revenger[j];
				revenger[j] = revenger[j + 1];
				revenger[j + 1] = temp;
			}
		}
	}
}

int main()
{

	/*
	设计一个英雄的结构体,包括成员姓名,年龄,性别;创建结构体数组,数组中存放5名英雄。

	通过冒泡排序的算法,将数组中的英雄按照年龄进行升序排序,最终打印排序后的结果。
	*/

	hero revenger[5] =
	{
		{"张三",18,"男"},
		{"李四",19,"女"},
		{"王五",20,"男"},
		{"寅子",40,"男"},
		{"表哥",23,"男"}
	};
	int len = sizeof(revenger) / sizeof(revenger[0]);

	//冒泡排序
	bubbleSort(revenger, len);

	//打印排序后的结果
	for (int i = 0; i < len; i++)
	{
		cout << "英雄名字:" << revenger[i].name << endl;
		cout << "英雄年龄:" << revenger[i].age << endl;
		cout << "英雄性别:" << revenger[i].sex << endl;
		cout << endl;
	}

	system("pause");
	return 0;
}

九、课外补充

9.1 EasyX图形库

9.1.1 EasyX简单介绍

  1. 安装:本质上,查找VS的安装目录,并将相关文件分别拷贝至lib目录和include目录
  2. 安装成功后,包含头文件 graphics.h 即可开始学习
  3. 帮助文档链接:https://docs.easyx.cn/zh-cn/intro’
  4. 仅用于c++
9.1.2 EasyX颜色

补充:光的三原色是红、黄、蓝,我们表示颜色的使用就用三原色来表示

  • 用RGB宏合成颜色,实际上合成出来的颜色是一个十六进制的整数

    RGB(红色部分,绿色部分,蓝色部分);

    每个颜色部分的值都是从0~255

9.1.3 EasyX坐标和设备
  • 坐标默认的原点在窗口的左上角,X轴向右为正,Y轴向下为正,度量单位是像素点
  • 设备:简单来说,就是绘图表面
    1. 在EasyX中,设备分两种,一种是默认的绘图窗口,另一种是IMAGE对象。通过SetWorkingImage()函数可以设置当前用于绘图的设备。设置当前用于绘图的设备以后,所有的绘图函数都会绘制在该设备上。(后面有详解)
9.1.4 窗口函数用于窗口的一些操作
初始化窗口
  • initgraph(int width,int height,int flag = NULL); 用于初始化绘图窗口(创建窗口)

    width 指定窗口的宽度

    height 指定窗口的高度

    flag 窗口的样式,默认为NULL

  • closegraph(); 关闭绘图窗口

  • cleardevice(); 清空绘图设备

绘图函数
  • 绘图函数从填充样式分类可分为无填充,有边框填充,无边框三种。

    以画圆为例:

    1. circle() 无填充
    2. fillcircle() 有边框填充
    3. solidcircle() 无边框填充
  • 从形状来分,常用的可以分为八种

    1. circle 画
    2. ellipse 画椭圆
    3. pie 画扇形
    4. polygon 画多边形
    5. rectangle 画矩形
    6. roundrect 画圆角矩形
    7. line 画线
    8. putpixel 画
  • 设置填充颜色 setfillcolor(颜色);

  • 设置线条颜色 setlinecolor(颜色);

  • 设置线条样式 setlinestyle(高度,宽度,字体);

设置背景颜色,以下两步必不可少(可以理解为设置的颜色在默认黑色背景的底下,然后清屏清除的是黑色)

  • 设置背景颜色 setbkcolor(颜色);

  • 清屏-清除原本背景颜色 cleardevice();

  • outtextxy(int x,int y,LPCTSTR str); 在指定位置输出字符串

  • settextcolor(COLORREF color); 设置当前文字颜色

  • settextstyle(int nHeight,int nWidth,LPCTSTR IpszFace) 设置字体样式

    1. nHeight 指定高度
    2. nWidth 字符的平均宽度。如果为0,则比例自适应
    3. IpszFace 字体名称
    4. 示例:settextstyle(50, 0, "楷体");

以下两种函数可用于文本的垂直和水平居中显示

  • textheight(LPCTSTR str); 获取字符串实际占用的像素高度
  • textwidth(LPCTSTR str); 获取字符串实际占用的像素宽度

文字在矩形框居中示例代码:

fillrectangle(200, 50, 500, 100);//填充一个矩形,参数为 左上角坐标+右下角坐标
settextcolor(RGB(30, 30, 30));
char arr[] = "居中显示测试";

int width = textwidth(arr);//像素所占宽度
int height = textheight(arr);//像素所占高度

outtextxy(300 / 2 - width / 2 + 200, 50 / 2 - height / 2 + 50, "居中显示测试");//绘制字符串

全部示例代码:

#include <iostream>
#include <string>
#include <graphics.h>

using namespace std;

int main()
{
	//创建一个窗口,确定窗口大小,show console 显示控制台
	initgraph(640,480,SHOWCONSOLE);

	//设置背景以下两步必不可少
	//设置背景颜色
	setbkcolor(YELLOW);
	cleardevice();//清屏,清除黑色背景

	//画粑粑,圆
	setlinestyle(PS_SOLID, 5);//设置线条样式
	setfillcolor(GREEN);//设置填充颜色
	setlinecolor(BLUE);//设置线条颜色
	circle(50, 50, 50);
	fillcircle(50, 150, 50);
	solidcircle(50, 250, 50);

	//设置字体颜色
	settextcolor(BLACK);

	//设置字体大小,样式,字体..
	settextstyle(20, 0, "楷体");

	//设置背景模式 transparent-透明
	setbkmode(TRANSPARENT);

	//设置字体颜色
	settextcolor(RGB(85, 177, 85));

	//绘制文字
	outtextxy(50, 50, 'a');//绘制字符

	outtextxy(60, 50, "大家好");//绘制字符串

	//把文字居中
	fillrectangle(200, 50, 500, 100);//填充一个矩形,参数为 左上角坐标+右下角坐标
	settextcolor(RGB(30, 30, 30));
	char arr[] = "居中显示测试";

	int width = textwidth(arr);//像素所占宽度
	int height = textheight(arr);//像素所占高度

	outtextxy(300 / 2 - width / 2 + 200, 50 / 2 - height / 2 + 50, "居中显示测试");//绘制字符串


	//如果参数错误,找不到对应的函数
	//是由于字符集导致的,那么解决方案有三种
	// 
	//1.在字符串前面加大写的L           常用
	//outtextxy(50, 50, L"大家好");
	// 
	//2.用TEXT()把字符串包起来
	//outtextxy(50, 50, TEXT("大家好"));
	//
	//3.用__TEXT()把字符串包起来
	//
	//实际上 TEXT() -> __TEXT() -> L"文本"
	//
	//4.不用添加任何代码,进 项目 -> 属性 -> 配置属性 -> 常规 -> 字符集 -> 改为多字节字符集    推荐使用这个!
	int maye = 0;
	cin >> maye;
	cout << maye << endl;

	//关闭窗口
	closegraph();

	system("pause");
	return 0;
}
显示图片
  • 在使用图像之前,需要定义一个变量(对象),然后把图片加载进变量才能使用。

    1. 平时定义变量都是使用的基础数据类型,比如:int temp;
    2. 在使用图像的时候需要使用EasyX提供给我们的类型:IMAGE,如IMAGE img;
  • loadimage(IMAGE* pDstlmg,LPCTSTR plmgFile,int nWidth = 0,int nHeight = 0,bool bResize = false);从文件中读取图像

    1. pDstlmg //保存图像的IMAGE对象指针
    2. plmgFile //图片文件名
    3. nWidth = 0 //图片的拉伸宽度
    4. nHeight = 0 //图片的拉伸高度
    5. bResize = false //是否调整IMAGE的大小以适应图片
  • putimage(int dstX,int dstY,IMAGE* pSrclmg,DWORD dwRop = SRCCOPY);在当前设备上绘制指定的图像

    1. dstX //绘制位置的x坐标
    2. dstY //绘制位置的y坐标
    3. pSrclmg //要绘制的IMAGE对象指针
    4. dwRop = SRCCOPY //三元光栅操作码

示例代码:

#include <iostream>
#include <string>
#include <graphics.h>

using namespace std;

int main()
{

	initgraph(640, 480, SHOWCONSOLE);
	cleardevice();

	//输出图片
	IMAGE img;//定义一个对象
	//加载图片
	//相对路径 ./表示当前文件夹下(源文件所在的目录),../是当前文件夹的上一级目录
	//绝对路径 
	loadimage(&img, "../666.jpg",640,480);
	putimage(0, 0, &img);//(0,0)图片锚点是左上角

	system("pause");
	return 0;
}
鼠标操作

示例:

#include <iostream>
#include <string>
#include <easyx.h>

using namespace std;

void button(int x, int y, int w, int h,const char arr[])
{
	setbkmode(TRANSPARENT);
	setfillcolor(BROWN);
	settextstyle(30, 0, "黑体");
	fillroundrect(x, y, x + w, x + h, 10, 10);//10是圆角有多圆

	int width = textwidth(arr);
	int height = textheight(arr);

	outtextxy(w / 2 - width / 2 + x, h / 2 - height / 2 + y, arr);
}

int main()
{

	initgraph(640, 480, EX_SHOWCONSOLE);
	button(50,50,150,150,"botton");

	ExMessage msg;
	while (1)
	{
		if (peekmessage(&msg, EX_MOUSE))
		{
			switch (msg.message)
			{
			case WM_LBUTTONDOWN:
				if (msg.x >= 50 && msg.x <= 50 + 150 && msg.y >= 50 && msg.y <= 50 + 150)
				{
					cout << "我是按钮,我被点击了" << endl;
				}
				break;
			default:
				break;
			}
		}
	}

	system("pause");
	return 0;
}
非EasyX函数——键盘消息函数

键盘消息函数用于获取键盘按键消息

  • getch();

    需要头文件conio.h

  • getAsyncKeyState(键值);

    需要头文件windows.h,但是由于EasyX包含了windows头文件,所以无需自己包含

    (其他需要windows头文件的函数也一样,但是需要在graphics.h的下方包含:比如放音乐的头文件mmsystem.h)

  • getch(); 需要使用返回值来判断

    1. 与非ASCII表字符的按键比较,需要使用虚拟键值

      上:72 下:80 左:75 右:77

    2. 如果是与字母比较直接写字母,比如’A’

    3. 详细使用方法,请看下图 (↓)

  • getAsyncKeyState(键值);需要传入一个键值,如果按下返回真

    上:VK_UP 下:VK_DOWN 左:VK_LEFT 右:VK_RIGHT

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GRW96qyd-1686840888804)(E:\c.—c.—java-exercise\photo\QQ截图20230516183514.png)]

  • 在设备上不断进行绘图操作时,会产生闪屏现象,针对这个现象,我们需要两个函数处理:
    1. BeginBatchDraw(); 开始批量绘图
    2. —中间放置绘图代码—
    3. EndBatchDraw(); 结束批量绘制
  • GetHWnd(); 获取窗口句柄,获取之后可以用来操作窗口

9.2 容器map

9.2.1 map简介

map是c++标准模板库(STL)的一个关联容器,提供一对一的映射关系

“第一个”称为关键字(key),别名first,每个关键字只能在map中出现一次

“第二个”称为该关键字的值(value),别名second

**例:**建立一个朋友数据表,保存多个“姓名-电话号码”的对应关系,并保存在某种数据结构中

​ 如:张三-123456

那么,可以定义一个map对象

map < string , string > friends;

把 朋友-电话号码 保存在friends中:

friends.insert("张三","123456"); //通过insert函数把张三以及对应他的电话号码保存在friends里面

要查询朋友的号码,通过

cout << "张三的电话号码是:" << friends.find("张三");

#include <iostream>
#include <string>
#include <map>

using namespace std;

int main()
{

	map<string, string>friends; //创建一个map映射

	friends.insert(pair<string, string>("张三", "123456"));
    //pair 由两个元素组成,分别命名为 first 和 second,它们可以是不同类型的任意数据类型,如 int,string 等。
    //pair<string, string> 表示一个键和关联值都是 string 类型的 pair 对象。例如 pair<string, string> mypair ("hello", "world"); 用来定义一个字符串 “hello” 与字符串 “world” 的键值对形式的 pair 对象。

	cout << "张三的电话号码是:" << friends.find("张三")->second; //find查询功能,second指电话号码

	system("pause");
	return 0;
}

**例:**给出一段英文

abacsdf

统计其中每个字母出现的次数

定义 map<char,int>cnt; //把每个字母出现的次数保存在cnt中

#include <iostream>
#include <string>
#include <map>

using namespace std;

int main()
{
    map<char, int> cnt;    // 把每个字符出现的次数保存在 cnt 中

    cnt.insert(pair<char, int>('a', 1));
    cnt.insert(pair<char, int>('c', 1));    // 插入 ('c', 1) 键值对

    // 将 a 字符的值增加 1
    cnt['a']++;

    // 输出每个字符出现的次数
    for (auto& p : cnt) {
        cout << p.first << ": " << p.second << endl;
    }
    /*
    这是一个 C++ 11 引入的基于范围的 for 循环,也称为 for-each 循环,用于遍历容器(比如 vector,map,set 等)中的元素,无需使用迭代器,简化了代码的书写。
    对于 map 容器,每个元素都是一对键值对,
    因此 for (auto& p : cnt) 表示遍历 cnt 容器的所有元素,对于每个元素,auto& p 表示取出容器中的一个键值对,即键在 p.first 中,关联值在 p.second 中。
    */

    system("pause");
    return 0;
}

map以模版(泛型)的方式实现,可以储存任意类型的数据,包括使用者自定义的数据类型

如:

map<int,int>mp;
map<int,string>m2;
map<string,string>m3;
map<float,int>m4;
map<person,int>m6; //创建一个key位person型、value为int类型的map对象

在map内部所有的数据都是有序的

map由一棵红黑树实现,这棵树具有对数据自动排序的功能

9.2.2 插入元素

map<int,string>student;

方式一:用insert函数插入pair

student.insert(pair<int,string>(0,"Zhangsan"));

方式二:用insert函数插入value_type数据:

student.insert(map<int,string>::value_type(1,"Lisi"));

方式三:用类似数组的方式增加元素:

student[123]="Wangwu";

9.2.3 查找元素

find()返回一个迭代器,指向查找的元素,

找不到,则返回map::end()位置(NULL)

iter = student.find(123);
if(iter!=student.end())
	cout<<"found,the value is"<<iter->second;
else
    cout<<"not found";

如果关键字是整型,也可以通过

student[1]读取关键字1对应的值,如"Lisi"

9.2.4 引用方法

map<int,int>mp1;

第一种情况

int sum = 100;

mp1[10] = 3;

sum += map1[10]; //mp1中存在关键字10,它的对应值是3,所以sum累加后变为103

第二种情况

int sum = 100;

sum += map1[10]; //mp1中不存在关键字10,所以mp1返回的值是0,sum累加后仍为100

第三种情况

mp1[10]=3;

mp1[10]++; //mp1[10]的值变为4

第四种情况

mp1[20]++; //因关键字20不存在,增加一个关键字20,且其值从0自增到1

即mp1增加一个元素<20,1>

9.3 二叉数基本

根节点

左子树指针

右子树指针

孩子节点 LChild/2=parent(完全二叉树中任何一个孩子节点除以2都等于父亲节点)

父节点

兄弟节点

姊妹节点

二叉树编序号从1开始

单一个体:结构体写法

9.3.1 基本概念
  1. 空二叉树:就是结构体指针 tree=NULL
  2. 只有根节点的二叉树
  3. 只有左子树或者子树的二叉树
  4. 左右子树都存在的二叉树
    1. 完全二叉树:除了叶子节点(最后一个节点)之外,其他都是满的
    2. 满二叉树:左右子树都是完整
9.3.2 遍历

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TIxaiCgR-1686840888812)(E:\c.—c.—java-exercise\photo\屏幕截图 2023-06-13 204018.png)]

另:

层次遍历:就是从上到下依次遍历 ABC

前序遍历也叫先序遍历

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IU8imgVy-1686840888813)(E:\c.—c.—java-exercise\photo\屏幕截图 2023-06-13 204508.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gCqSp7Sg-1686840888814)(E:\c.—c.—java-exercise\photo\屏幕截图 2023-06-13 205400.png)]

9.3.3 创建、连接二叉树

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9oYOjK4q-1686840888814)(E:\c.—c.—java-exercise\photo\屏幕截图 2023-06-13 212339.png)]

十、通讯录管理系统

10.1 系统要求

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

本教程主要利用C++来实现一个通讯录管理系统

系统中需要实现的功能如下:

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

10.2 创建项目

10.3 菜单功能

**功能描述:**用户选择功能的界面

菜单界面效果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-65HPKZsn-1686840888814)(E:\c.—c.—java-exercise\photo\屏幕截图 2023-06-14 195405.png)]

步骤:

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

代码:

#include <iostream>
#include <stdio.h>

using namespace std;

void showMenu() //菜单界面View函数
{	//在控制台窗口打印菜单
	cout << "*****************************" << endl;
	cout << "*****	1、添加联系人	*****" << endl;
	cout << "*****	2、显示联系人	*****" << endl;
	cout << "*****	3、删除联系人	*****" << endl;
	cout << "*****	4、查找联系人	*****" << endl;
	cout << "*****	5、修改联系人	*****" << endl;
	cout << "*****	6、清空联系人	*****" << endl;
	cout << "*****	7、退出通讯录	*****" << endl;
	cout << "*****************************" << endl;
}

int main()
{
	showMenu();

	return 0;
}

10.4 退出功能

**功能描述:**退出通讯录系统

思路:根据用户不同的选择,进入不同的功能,可以使用switch分支结构,将整个架构进行搭建

当用户选择0时,执行退出,选择其他先不做操作,也不会退出程序

代码:

int main()
{
	int op;
	while (1)
	{
		showMenu();
		cin >> op;
		switch (op)
		{
		case 1:

			break;
		case 2:

			break;
		case 3:

			break;
		case 4:

			break;
		case 5:

			break;
		case 6:

			break;
		case 0:
			cout << "退出成功" << endl;
			break;
		default:
			cout << "未找到指令,请重新输入" << endl;
			break;
		}
		break;
	}

	return 0;
}

10.5 添加联系人

功能描述:

实现添加联系人功能,联系人上限为1000人,联系人信息包括(姓名、性别、年龄、联系电话、家庭住址)

添加联系人实现步骤:

  • 设计联系人结构体
  • 设计通讯录结构体
  • main函数中创建通讯录
  • 封装添加联系人函数
  • 测试添加联系人功能
10.5.1 设计联系人结构体

联系人信息包括:姓名、性别、年龄、联系电话、家庭住址

设计如下:

#include <string>

struct Contact //创建联系人结构体
{
	string name; //姓名
	int sex; //性别:1男,2女
	double age; //年龄
	int number; //号码
	string address; //地址
	
};
10.5.2 设计通讯录结构体

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

设计如下

#define MAX 1000 //最大人数

struct addressBooks //创建通讯录结构体
{
	Contact personArray[MAX]; //通讯录中保存联系人的数组
	int Size; //通讯录中人员的个数
};
10.5.3 main函数中创建通讯录 & 添加联系人函数
//--------------------------Service---------------------------
void addPerson(addressBooks* abs)
{
	//判断通讯录是否已满,如果满了就不再添加
	if (abs->Size == MAX)
	{
		cout << "通讯录已满,无法添加" << endl;
		return;
	}
	else
	{
		//添加具体联系人

		//姓名
		NAME:
		string name1;
		cout << "请输入姓名:" << endl;
		cin >> name1;
		//检测是否有同名
		if(findPerson(abs,name1)==0) //用到之后写的查找联系人是否存在函数
		{
			abs->personArray[abs->Size].name = name1;
		}
		else
		{
			cout << "有同名联系人,请重新输入" << endl;
			goto NAME;
		}

		//性别
		int sex1;
		cout << "请输入性别:1.男	2.女" << endl;
		while (1)
		{
			cin >> sex1;
			if (sex1 == 1 || sex1 == 2)
			{
				abs->personArray[abs->Size].sex = sex1;
				break;
			}
			else
			{
				cout << "输入错误,请重新输入" << endl;
			}
		}

		//年龄
		double age1 = 0;
		cout << "请输入年龄:" << endl;
		cin >> age1;
		abs->personArray[abs->Size].age = age1;

		//电话
		string number1;
		cout << "请输入电话:" << endl;
		cin >> number1;
		abs->personArray[abs->Size].number = number1;

		//住址
		string address1;
		cout << "请输入地址:" << endl;
		cin >> address1;
		abs->personArray[abs->Size].address = address1;

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

		//提示完成
		cout << "联系人添加完成" << endl;

		system("pause"); //按任意键继续
		system("cls"); //清屏操作
	}
}

int main()
{
	//创建通讯录结构体变量
	addressBooks abs;

	//初始化通讯录中当前人员个数
	abs.Size = 0;

	int op = 0;

	while (1)
	{
		showMenu();
		cin >> op;
		switch (op)
		{
		case 1: //添加联系人
			addPerson(&abs); //利用地址传递,可以修饰实参
			break;
		case 2: //显示联系人

			break;
		case 3: //删除联系人

			break;
		case 4: //查找联系人

			break;
		case 5: //修改联系人

			break;
		case 6: //清空联系人

			break;
		case 0: //退出通讯录
			cout << "退出成功" << endl;
			return 0;
		default:
			cout << "未找到指令,请重新输入" << endl;
			break;
		}
	}

	return 0;
}

10.6 显示联系人

功能描述:显示通讯录中已有的联系人信息

显示联系人实现步骤:

  • 封装显示联系人函数
  • 测试显示联系人功能
10.6.1 封装显示联系人函数

思路:判断如果当前通讯录中没有人员,就提示记录为空,人数大于0,显示通讯录中信息

显示联系人代码:

//显示联系人

void showPerson(addressBooks* abs)
{
	if (abs->Size == 0)
	{
		cout << "记录为空" << endl;

		system("pause");
		system("cls"); //清屏操作
	}
	else
	{
		int i;

		for (i = 0; i < abs->Size; i++)
		{
			cout << "姓名:" << abs->personArray[i].name << endl;
			cout << "性别:" << (abs->personArray[i].sex == 1?"男":"女") << endl;
			cout << "年龄:" << abs->personArray[i].age << endl;
			cout << "电话:" << abs->personArray[i].number << endl;
			cout << "地址:" << abs->personArray[i].address << endl;
			cout << endl;
		}

		system("pause");
		system("cls"); //清屏操作
	}
}

10.7 删除联系人

功能描述:按照姓名进行删除指定联系人

删除联系人实现步骤

  • 封装检测联系人是否存在
  • 封装删除联系人函数
  • 测试删除联系人功能
10.7.1 封装检测联系人是否存在

设计思路:

删除联系人前,我们需要先判断用户输入的联系人是否存在,如果存在删除,不存在提示用户没有要删除的联系人,因此我们可以把检测联系人是否存在封装成一个函数中,如果存在,返回联系人在通讯录中的位置,不存在返回-1

//检测联系人是否存在

int findPerson(addressBooks* abs, string name)
{
	int i;
	for (i = 0; i < abs->Size; i++)
	{
		if (name == abs->personArray[i].name)
		{
			return i;
		}
	}
	return -1;
}
10.7.2 封装删除联系人函数
//删除联系人

void delPerson(addressBooks* abs, int i)
{
	for (int j = i; j < abs->Size; j++)
	{
		abs->personArray[j] = abs->personArray[j + 1];
		abs->Size--;
	}
}

10.8 查找联系人

功能描述:按照姓名查看联系人信息

查找联系人实现步骤

  • 封装查找联系人函数
  • 测试查找指定联系人
10.8.1 封装查找联系人函数

注:上面已经实现过该函数,做部分修改即可

实现思路:判断用户指定的联系人是否存在,如果存在显示信息,不存在提示查无此人

查找联系人代码:

		case 4: //查找联系人
		{
			cout << "请输入要查找的联系人姓名:" << endl;
			string tmpname;
			cin >> tmpname;
			int tmp = findPerson(&abs, tmpname);
			if (tmp == -1)
			{
				cout << "查无此人" << endl;
				system("pause");
				system("cls"); //清屏操作
			}
			else
			{
				cout << endl;
				cout << "姓名:" << abs.personArray[tmp].name << endl;
				cout << "性别:" << (abs.personArray[tmp].sex == 1 ? "男" : "女") << endl;
				cout << "年龄:" << abs.personArray[tmp].age << endl;
				cout << "电话:" << abs.personArray[tmp].number << endl;
				cout << "地址:" << abs.personArray[tmp].address << endl;
				cout << endl;
				system("pause");
				system("cls"); //清屏操作
			}
				break;
		}

10.9 修改联系人

功能描述:按照姓名重新修改指定联系人

修改联系人实现步骤

  • 封装修改联系人函数
  • 测试修改联系人函数
10.9.1 封装修改联系人函数

实现思路:查找用户输入的联系人,如果查找成功进行修改操作,查找失败提示查无此人

修改联系人代码:

//修改联系人

void modifyPerson(addressBooks* abs)
{
	cout << "请输入您想修改的联系人姓名:" << endl;
MODIFY:
	string tmpname;
	cin >> tmpname;
	int tmp = findPerson(abs, tmpname); //查找联系人
	if (tmp == -1) //未找到联系人
	{
		cout << "未查找到你想修改的联系人,请选择:"<<endl;
		char op;
		cout << "1.重新输入联系人姓名	或	2.退出修改" << endl;
		MODIFY3:
		cin >> op;
		switch (op)
		{
		case '1':
			cout << "请输入您想修改的联系人姓名:" << endl;
			goto MODIFY;

		case '2':
			system("cls");
			break;

		default:
			cout << "指令错误,请重新输入:" << endl;
			goto MODIFY3;
		}
	}

	else //找到联系人
	{

		cout << "找到了您想修改的联系人:" << tmpname << endl;

		cout << "请选择您想修改的联系人信息:" << endl;
		char op;
		cout << "1.姓名	2.性别	3.年龄	4.电话	5.住址	6.退出修改" << endl;
	MODIFY2:
		cin >> op;

		switch (op)
		{
		case '1':
		{
			//修改姓名
			cout << "请输入修改后的姓名:" << endl;
			string name1;
			cin >> name1;
			abs->personArray[tmp].name = name1;
			cout << "修改成功!" << endl;
			goto MODIFY2;
		}

		case '2':
		{
			//修改性别
			cout << "请输入修改后的性别:1.男	2.女" << endl;
		MODIFY1:
			int sex1;
			cin >> sex1;
			if (sex1 == 1 || sex1 == 2)
			{
				abs->personArray[tmp].sex = sex1;
				cout << "修改成功!" << endl;
				goto MODIFY2;
			}
			else
			{
				cout << "输入错误,请重新输入 1 or 2 :" << endl;
				goto MODIFY1;
			}
		}

		case '3':
		{
			//修改年龄
			cout << "请输入修改后的年龄:" << endl;
			double age1;
			cin >> age1;
			abs->personArray[tmp].age = age1;
			cout << "修改成功!" << endl;
			goto MODIFY2;
		}

		case '4':
		{
			//修改联系电话
			cout << "请输入修改后的电话:" << endl;
			string number1;
			cin >> number1;
			abs->personArray[tmp].number = number1;
			cout << "修改成功!" << endl;
			goto MODIFY2;
		}

		case '5':
		{
			//修改住址
			cout << "请输入修改后的住址:" << endl;
			string address1;
			cin >> address1;
			abs->personArray[tmp].address = address1;
			cout << "修改成功!" << endl;
			goto MODIFY2;
		}

		case '6':
		{
			//退出选择
			system("cls");
			break;
		}

		default:
			cout << "指令输入错误,请重新输入:" << endl;
			goto MODIFY2;
		}
	}
}

10.10 清空联系人

功能描述:清空通讯录中的所有信息

清空联系人实现步骤

  • 封装清空联系人函数
  • 测试清空联系人
10.10.1 封装清空联系人函数

实现思路:将通讯录所有联系人信息清除掉,只要将通讯录记录的联系人数置为0,做逻辑清空即可

清空联系人代码:

//清空联系人
void cleanPerson(addressBooks* abs)
{
	cout << "您确定要清空通讯录么?" << endl;
	char op;	
	cout << "1.是	2.否" << endl;
CLEAN:
	cin >> op;
	switch (op)
	{
	case '1':
	{
		abs->Size = 0;
		cout << "通讯录已清空" << endl;
		system("pause");
		system("cls");
	}
	case '2':
	{
		system("cls");
		break;
	}
	default:
	{
		cout << "指令错误,请重新输入:" << endl;
		goto CLEAN;
	}
	}
}

10.11 总结

全部代码:

#include <iostream>
#include <stdio.h>
#include <string>

using namespace std;

#define MAX 1000 //最大人数

struct Contact //创建联系人结构体
{
	string name; //姓名
	int sex; //性别:1男,2女
	double age; //年龄
	string number; //号码
	string address; //地址

};

struct addressBooks //创建通讯录结构体
{
	struct Contact personArray[MAX]; //通讯录中保存联系人的数组
	int Size; //通讯录中人员的个数
};

//--------------------------View-----------------------------
void showMenu() //菜单界面View函数
{	//在控制台窗口打印菜单
	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;
	cout << "请输入指令:" << endl;
}

//--------------------------Service---------------------------

//检测联系人是否存在

int findPerson(addressBooks* abs, string name)
{
	int i;
	for (i = 0; i < abs->Size; i++)
	{
		if (name == abs->personArray[i].name)
		{
			return i;
		}
	}
	return -1;
}

//添加联系人

void addPerson(addressBooks* abs)
{
	//判断通讯录是否已满,如果满了就不再添加
	if (abs->Size == MAX)
	{
		cout << "通讯录已满,无法添加" << endl;
		return;
	}
	else
	{
		//添加具体联系人

		//姓名
	NAME:
		string name1;
		cout << "请输入姓名:" << endl;
		cin >> name1;
		if (abs->Size == 0)
		{
			abs->personArray[abs->Size].name = name1;
		}
		else
		{
			//检测是否有同名
			if (findPerson(abs, name1) == -1) //用到之后写的查找联系人是否存在函数
			{
				abs->personArray[abs->Size].name = name1;
			}
			else
			{
				cout << "有同名联系人,请重新输入" << endl;
				goto NAME;
			}
		}

		//性别
		int sex1;
		cout << "请输入性别:1.男	2.女" << endl;
		while (1)
		{
			cin >> sex1;
			if (sex1 == 1 || sex1 == 2)
			{
				abs->personArray[abs->Size].sex = sex1;
				break;
			}
			else
			{
				cout << "输入错误,请重新输入" << endl;
			}
		}

		//年龄
		double age1 = 0;
		cout << "请输入年龄:" << endl;
		cin >> age1;
		abs->personArray[abs->Size].age = age1;

		//电话
		string number1;
		cout << "请输入电话:" << endl;
		cin >> number1;
		abs->personArray[abs->Size].number = number1;

		//住址
		string address1;
		cout << "请输入地址:" << endl;
		cin >> address1;
		abs->personArray[abs->Size].address = address1;

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

		//提示完成
		cout << "联系人添加完成" << endl;

		system("pause");
		system("cls"); //清屏操作
	}
}

//显示联系人

void showPerson(addressBooks* abs)
{
	if (abs->Size == 0)
	{
		cout << "当前记录为空" << endl;

		system("pause");
		system("cls"); //清屏操作
	}
	else
	{
		int i;

		for (i = 0; i < abs->Size; i++)
		{
			cout << "姓名:" << abs->personArray[i].name << endl;
			cout << "性别:" << (abs->personArray[i].sex == 1?"男":"女") << endl;
			cout << "年龄:" << abs->personArray[i].age << endl;
			cout << "电话:" << abs->personArray[i].number << endl;
			cout << "地址:" << abs->personArray[i].address << endl;
			cout << endl;
		}

		system("pause");
		system("cls"); //清屏操作
	}
}

//删除联系人

void delPerson(addressBooks* abs, int i)
{
	for (int j = i; j < abs->Size; j++)
	{
		abs->personArray[j] = abs->personArray[j + 1];
		abs->Size--;
	}
}

//修改联系人

void modifyPerson(addressBooks* abs)
{
	cout << "请输入您想修改的联系人姓名:" << endl;
MODIFY:
	string tmpname;
	cin >> tmpname;
	int tmp = findPerson(abs, tmpname); //查找联系人
	if (tmp == -1) //未找到联系人
	{
		cout << "未查找到你想修改的联系人,请选择:"<<endl;
		char op;
		cout << "1.重新输入联系人姓名	或	2.退出修改" << endl;
		MODIFY3:
		cin >> op;
		switch (op)
		{
		case '1':
			cout << "请输入您想修改的联系人姓名:" << endl;
			goto MODIFY;

		case '2':
			system("cls");
			break;

		default:
			cout << "指令错误,请重新输入:" << endl;
			goto MODIFY3;
		}
	}

	else //找到联系人
	{

		cout << "找到了您想修改的联系人:" << tmpname << endl;

		cout << "请选择您想修改的联系人信息:" << endl;
		char op;
		cout << "1.姓名	2.性别	3.年龄	4.电话	5.住址	6.退出修改" << endl;
	MODIFY2:
		cin >> op;

		switch (op)
		{
		case '1':
		{
			//修改姓名
			cout << "请输入修改后的姓名:" << endl;
			string name1;
			cin >> name1;
			abs->personArray[tmp].name = name1;
			cout << "修改成功!" << endl;
			goto MODIFY2;
		}

		case '2':
		{
			//修改性别
			cout << "请输入修改后的性别:1.男	2.女" << endl;
		MODIFY1:
			int sex1;
			cin >> sex1;
			if (sex1 == 1 || sex1 == 2)
			{
				abs->personArray[tmp].sex = sex1;
				cout << "修改成功!" << endl;
				goto MODIFY2;
			}
			else
			{
				cout << "输入错误,请重新输入 1 or 2 :" << endl;
				goto MODIFY1;
			}
		}

		case '3':
		{
			//修改年龄
			cout << "请输入修改后的年龄:" << endl;
			double age1;
			cin >> age1;
			abs->personArray[tmp].age = age1;
			cout << "修改成功!" << endl;
			goto MODIFY2;
		}

		case '4':
		{
			//修改联系电话
			cout << "请输入修改后的电话:" << endl;
			string number1;
			cin >> number1;
			abs->personArray[tmp].number = number1;
			cout << "修改成功!" << endl;
			goto MODIFY2;
		}

		case '5':
		{
			//修改住址
			cout << "请输入修改后的住址:" << endl;
			string address1;
			cin >> address1;
			abs->personArray[tmp].address = address1;
			cout << "修改成功!" << endl;
			goto MODIFY2;
		}

		case '6':
		{
			//退出选择
			system("cls");
			break;
		}

		default:
			cout << "指令输入错误,请重新输入:" << endl;
			goto MODIFY2;
		}
	}
}

//清空联系人
void cleanPerson(addressBooks* abs)
{
	cout << "您确定要清空通讯录么?" << endl;
	char op;	
	cout << "1.是	2.否" << endl;
CLEAN:
	cin >> op;
	switch (op)
	{
	case '1':
	{
		abs->Size = 0;
		cout << "通讯录已清空" << endl;
		system("pause");
		system("cls");
	}
	case '2':
	{
		system("cls");
		break;
	}
	default:
	{
		cout << "指令错误,请重新输入:" << endl;
		goto CLEAN;
	}
	}
}

int main()
{
	//创建通讯录结构体变量
	addressBooks abs;

	//初始化通讯录中当前人员个数
	abs.Size = 0;

	char op = 0;

	while (1)
	{
		showMenu();
		cin >> op;
		switch (op)
		{
		case '1': //添加联系人
			addPerson(&abs); //利用地址传递,可以修饰实参
			break;
		case '2': //显示联系人
			showPerson(&abs);
			break;
		case '3': //删除联系人
		{
			cout << "请输入要删除的联系人姓名:" << endl;
			string tmpname;
		DELPERSON:
			cin >> tmpname;
			int tmp = findPerson(&abs, tmpname);
			if (tmp == -1)
			{
				cout << "未找到您要删除的联系人,请重新输入:" << endl;
				goto DELPERSON;
			}
			else
			{
				delPerson(&abs, tmp);
				cout << "删除成功" << endl;
			}
			break;
		}
		case '4': //查找联系人
		{
			cout << "请输入要查找的联系人姓名:" << endl;
			string tmpname;
			cin >> tmpname;
			int tmp = findPerson(&abs, tmpname);
			if (tmp == -1)
			{
				cout << "查无此人" << endl;
				system("pause");
				system("cls"); //清屏操作
			}
			else
			{
				cout << endl;
				cout << "姓名:" << abs.personArray[tmp].name << endl;
				cout << "性别:" << (abs.personArray[tmp].sex == 1 ? "男" : "女") << endl;
				cout << "年龄:" << abs.personArray[tmp].age << endl;
				cout << "电话:" << abs.personArray[tmp].number << endl;
				cout << "地址:" << abs.personArray[tmp].address << endl;
				cout << endl;
				system("pause");
				system("cls"); //清屏操作
			}
				break;
		}
		case '5': //修改联系人
			modifyPerson(&abs);
			break;
		case '6': //清空联系人
			cleanPerson(&abs);
			break;
		case '0': //退出通讯录
			cout << "退出成功!" << endl;
			return 0;
		default:
			cout << "未找到指令,请重新输入" << endl;
			system("pause");
			system("cls");
			break;
		}
	}

	return 0;
}

].sex = sex1;
break;
}
else
{
cout << “输入错误,请重新输入” << endl;
}
}

	//年龄
	double age1 = 0;
	cout << "请输入年龄:" << endl;
	cin >> age1;
	abs->personArray[abs->Size].age = age1;

	//电话
	string number1;
	cout << "请输入电话:" << endl;
	cin >> number1;
	abs->personArray[abs->Size].number = number1;

	//住址
	string address1;
	cout << "请输入地址:" << endl;
	cin >> address1;
	abs->personArray[abs->Size].address = address1;

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

	//提示完成
	cout << "联系人添加完成" << endl;

	system("pause");
	system("cls"); //清屏操作
}

}

//显示联系人

void showPerson(addressBooks* abs)
{
if (abs->Size == 0)
{
cout << “当前记录为空” << endl;

	system("pause");
	system("cls"); //清屏操作
}
else
{
	int i;

	for (i = 0; i < abs->Size; i++)
	{
		cout << "姓名:" << abs->personArray[i].name << endl;
		cout << "性别:" << (abs->personArray[i].sex == 1?"男":"女") << endl;
		cout << "年龄:" << abs->personArray[i].age << endl;
		cout << "电话:" << abs->personArray[i].number << endl;
		cout << "地址:" << abs->personArray[i].address << endl;
		cout << endl;
	}

	system("pause");
	system("cls"); //清屏操作
}

}

//删除联系人

void delPerson(addressBooks* abs, int i)
{
for (int j = i; j < abs->Size; j++)
{
abs->personArray[j] = abs->personArray[j + 1];
abs->Size–;
}
}

//修改联系人

void modifyPerson(addressBooks* abs)
{
cout << “请输入您想修改的联系人姓名:” << endl;
MODIFY:
string tmpname;
cin >> tmpname;
int tmp = findPerson(abs, tmpname); //查找联系人
if (tmp == -1) //未找到联系人
{
cout << “未查找到你想修改的联系人,请选择:”<<endl;
char op;
cout << “1.重新输入联系人姓名 或 2.退出修改” << endl;
MODIFY3:
cin >> op;
switch (op)
{
case ‘1’:
cout << “请输入您想修改的联系人姓名:” << endl;
goto MODIFY;

	case '2':
		system("cls");
		break;

	default:
		cout << "指令错误,请重新输入:" << endl;
		goto MODIFY3;
	}
}

else //找到联系人
{

	cout << "找到了您想修改的联系人:" << tmpname << endl;

	cout << "请选择您想修改的联系人信息:" << endl;
	char op;
	cout << "1.姓名	2.性别	3.年龄	4.电话	5.住址	6.退出修改" << endl;
MODIFY2:
	cin >> op;

	switch (op)
	{
	case '1':
	{
		//修改姓名
		cout << "请输入修改后的姓名:" << endl;
		string name1;
		cin >> name1;
		abs->personArray[tmp].name = name1;
		cout << "修改成功!" << endl;
		goto MODIFY2;
	}

	case '2':
	{
		//修改性别
		cout << "请输入修改后的性别:1.男	2.女" << endl;
	MODIFY1:
		int sex1;
		cin >> sex1;
		if (sex1 == 1 || sex1 == 2)
		{
			abs->personArray[tmp].sex = sex1;
			cout << "修改成功!" << endl;
			goto MODIFY2;
		}
		else
		{
			cout << "输入错误,请重新输入 1 or 2 :" << endl;
			goto MODIFY1;
		}
	}

	case '3':
	{
		//修改年龄
		cout << "请输入修改后的年龄:" << endl;
		double age1;
		cin >> age1;
		abs->personArray[tmp].age = age1;
		cout << "修改成功!" << endl;
		goto MODIFY2;
	}

	case '4':
	{
		//修改联系电话
		cout << "请输入修改后的电话:" << endl;
		string number1;
		cin >> number1;
		abs->personArray[tmp].number = number1;
		cout << "修改成功!" << endl;
		goto MODIFY2;
	}

	case '5':
	{
		//修改住址
		cout << "请输入修改后的住址:" << endl;
		string address1;
		cin >> address1;
		abs->personArray[tmp].address = address1;
		cout << "修改成功!" << endl;
		goto MODIFY2;
	}

	case '6':
	{
		//退出选择
		system("cls");
		break;
	}

	default:
		cout << "指令输入错误,请重新输入:" << endl;
		goto MODIFY2;
	}
}

}

//清空联系人
void cleanPerson(addressBooks* abs)
{
cout << “您确定要清空通讯录么?” << endl;
char op;
cout << “1.是 2.否” << endl;
CLEAN:
cin >> op;
switch (op)
{
case ‘1’:
{
abs->Size = 0;
cout << “通讯录已清空” << endl;
system(“pause”);
system(“cls”);
}
case ‘2’:
{
system(“cls”);
break;
}
default:
{
cout << “指令错误,请重新输入:” << endl;
goto CLEAN;
}
}
}

int main()
{
//创建通讯录结构体变量
addressBooks abs;

//初始化通讯录中当前人员个数
abs.Size = 0;

char op = 0;

while (1)
{
	showMenu();
	cin >> op;
	switch (op)
	{
	case '1': //添加联系人
		addPerson(&abs); //利用地址传递,可以修饰实参
		break;
	case '2': //显示联系人
		showPerson(&abs);
		break;
	case '3': //删除联系人
	{
		cout << "请输入要删除的联系人姓名:" << endl;
		string tmpname;
	DELPERSON:
		cin >> tmpname;
		int tmp = findPerson(&abs, tmpname);
		if (tmp == -1)
		{
			cout << "未找到您要删除的联系人,请重新输入:" << endl;
			goto DELPERSON;
		}
		else
		{
			delPerson(&abs, tmp);
			cout << "删除成功" << endl;
		}
		break;
	}
	case '4': //查找联系人
	{
		cout << "请输入要查找的联系人姓名:" << endl;
		string tmpname;
		cin >> tmpname;
		int tmp = findPerson(&abs, tmpname);
		if (tmp == -1)
		{
			cout << "查无此人" << endl;
			system("pause");
			system("cls"); //清屏操作
		}
		else
		{
			cout << endl;
			cout << "姓名:" << abs.personArray[tmp].name << endl;
			cout << "性别:" << (abs.personArray[tmp].sex == 1 ? "男" : "女") << endl;
			cout << "年龄:" << abs.personArray[tmp].age << endl;
			cout << "电话:" << abs.personArray[tmp].number << endl;
			cout << "地址:" << abs.personArray[tmp].address << endl;
			cout << endl;
			system("pause");
			system("cls"); //清屏操作
		}
			break;
	}
	case '5': //修改联系人
		modifyPerson(&abs);
		break;
	case '6': //清空联系人
		cleanPerson(&abs);
		break;
	case '0': //退出通讯录
		cout << "退出成功!" << endl;
		return 0;
	default:
		cout << "未找到指令,请重新输入" << endl;
		system("pause");
		system("cls");
		break;
	}
}

return 0;

}




## 十一、基础入门完结:2023/6/15	---宇昕
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值