C++基础

1. C++初识

1.1. HelloWorld

  • 创建项目
    • 和文档当中的相同
  • 创建源文件
    • 就是把C语言的源文件的扩展名.c改为.cpp

  • 代码
#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

int main() {

	cout << "Hello World!\n" << endl;

	system("pause");

	return 0;
}

1.2. 注释

// 多行注释
/*
	1. 单行注释
		// 单行注释

	2. 多行注释
		
*/

// 代码的含义是在屏幕中输出一个"Hello World!"
	cout << "Hello World!\n" << endl;

1.3. 变量

  • 变量存在的意义
    • 方便管理内存空间
  • 创建语法
数据类型 变量名 = 初始值;
int 	i	=	1;
  • 代码
#include <iostream>
using namespace std;

int main() {
	// 定义变量
	int a = 10;

	// 输出变量a
	cout << "a = " << a << endl;
	system("pause");

	return 0;
}

1.4. 常量

#define _CRT_SECURE_NO_WARNINGS 1

/*
	常量的定义方式
		1. #define 宏常量
			
		2. const修饰的变量
*/

#include <iostream>
using namespace std;

// 宏
#define Day 7

int main() {
	// 错误: Day是常量, 一旦修改就会报错
	//Day = 1;

	// const修饰的变量
	const int i = 12;
	// 错误, const修饰的变量也成为变量
	//i = 1;

	cout << "一年中有" << i << "个月份" << endl;

	//system("pause");

	return 0;
}

1.5. 标识符和关键字

标识符 (变量, 常量)

  • 命名规则

    • 标识符不能是关键字

    • 只能由字母, 数字, 下划线组成

    • 不能以数字开头

    • 标识符中字母区分大小写

  • 命名规范

    • 见名知意
    • 驼峰原则

关键字

  • C++中预先保留的单词
  • 在定义变量或者常量的时候, 不要使用关键字

2. 数据类型

存在的意义

  • 给变量分配合适的内存空间

2.1. 整型

数据类型占用空间取值范围
short2字节 (byte)-2^15 ~ 2^15-1
int4-2^31 ~ 2^31-1
long4-2^31 ~ 2^31-1
long long8-2^63 ~ 2^63-1

代码

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

int main() {
	// short (-32768 ~ 32767)
	short num1 = 32768; // -32768, 因为越界了
	// int, 没有特殊需要的话, 使用int就行
	int num2 = 32768; // 不会越界
	// long
	long num3 = 1;
	// long long
	long long num4 = 1;

	cout << "num1 = " << num1 << endl;
	cout << "num2 = " << num2 << endl;
	cout << "num3 = " << num3 << endl;
	cout << "num4 = " << num4 << endl;
	system("pause");
	return 0;
}

2.2. sizeof关键字

作用

  • 统计数据类型所占内存大小

语法

  • sizeof(数据类型 或者 变量)

代码

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

int main() {
	cout << "short占用内存空间为: " << sizeof(short) << endl; // 2
	cout << "int占用内存空间为: " << sizeof(int) << endl; // 4
	// int <= long
	cout << "long占用内存空间为: " << sizeof(long) << endl; // 4
	// long <= long long
	cout << "long long占用内存空间为: " << sizeof(long long) << endl; // 8
	system("pause");
	return 0;
}

2.3. 浮点型 (实型)

作用

  • 用于表示小数

分为

  • 单精度float
    • 4byte
  • 双精度double
    • 8byte

代码

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

int main() {
	// float
	float f1 = 3.14f; // 默认会把浮点数当成double, 在浮点数后面加上f就会当成float
	cout << "f1 = " << f1 << endl;
	// double, 没有其他特殊需求, 使用double就行 
	double d1 = 3.14;
	// 默认情况下, 输出一个小数, 只会显示6位有效数字, 如果想要更多, 需要更复杂的配置, 这里就不赘述
	double d2 = 3.123456789; // 3.123456
	cout << "d1 = " << d1 << endl;
		
	// 统计float和double占用内存空间
	cout << "float占用的内存空间为: " << sizeof(float) << endl; // 4

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



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

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

	system("pause");
	return 0;
}

2.4. 字符型

作用

  • 显示单个字符

语法

  • char c = ‘a’;

注意

  • 单引号括起来

  • 单引号内只能是一个字符, 不能是字符串

  • 只占用1个字节

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

代码

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

int main() {
	// 1. 定义char
	char ch = 'a';
	cout << "ch = " << ch << endl;
	// 2. 所占内存大小
	cout << "char占用的内存空间为: " << sizeof(char) << endl; // 1
	// 3.常见错误
	//char ch2 = "b"; // 单引号
	//char ch3 = 'abcdef'; // 单字符

	// 4.ASCII编码
	// a - 97
	// A - 65
	cout << (int)ch << endl; // 97
	
	system("pause");
	return 0;
}

2.5. 转义字符

作用

  • 表示一些不能显示出来的ASCII字符
转义字符含义ASCII码值
\a警报007
\b退格008
\n换行010
\r回车013
\ttab009
\\\092
\’039
\""034

代码

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

int main() {
	// \n
	cout << "HelloWolrd\n";

	// 反斜杠 \\

	cout << "\\" << endl; // \

	// \t 可以整齐的输出数据
	cout << "aaaa\tbbb" << endl; // aaaa    bbb
	cout << "aaa\tbbb" << endl;  // aaa     bbb
	cout << "aa\tbbb" << endl;   // aa      bbb

	system("pause");
	return 0;
}

2.6. 字符串型

作用

  • 用于表示一串字符

两种风格

  • C语言风格
    • char 变量名[] = "字符串值";
  • C++风格
    • string 变量名 = "字符串值";
#define _CRT_SECURE_NO_WARNINGS 1

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

int main() {
	// C语言风格
	// 注意事项1: char 字符串名[]
	// 注意事项2: 等号后面要使用双引号
	char str1[] = "hello wolrd";
	cout << "str1 = " << str1 << endl;

	// C++风格
	// 注意事项: 包含一个头文件#include <string>, 但是版本过高的话, 不使用头文件也不会报错
	string str2 = "hello world";
	cout << "str2 = " << str2 << endl;

	system("pause");
	return 0;
}

2.7. 布尔类型 bool

作用

  • 代表真或假的值

bool类型只有两个值

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

bool类型占用1byte

代码

#define _CRT_SECURE_NO_WARNINGS 1

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

int main() {
	// 1. 定义
	bool flag = true;
	cout << "flag = " << flag << endl; // 1 -- 真
	
	flag = false;
	cout << "flag = " << flag << endl; // 0 -- 假

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

	system("pause");
	return 0;
}

2.8. 数据的输入

作用

  • 用于从键盘获取数据

关键字

  • cin

语法

  • cin >> 变量

示例

#define _CRT_SECURE_NO_WARNINGS 1

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

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

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

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

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

	// 5. 布尔型
	bool flag;
	cout << "请给布尔型变量flag赋值: ";
	cin >> flag;
	cout << "flag = " << flag << endl;
	
	system("pause");
	return 0;
}

3. 运算符

作用

  • 用于执行代码的运算
运算符类型作用
算术运算符四则运算
赋值运算符赋值
比较运算符比较, 并返回一个真值或假值
逻辑运算符返回bool类型的值

3.1. 算术运算符

运算符术语
+
-
*
/
%取余
++自增一, 分为前置和后置
自减一, 分为前置和后置

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

int main() {
	// 加减乘除
	int num1 = 10;
	int num2 = 3;

	cout << "num1 + num2 = " << num1 + num2 << endl; // 13
	cout << "num1 - num2 = " << num1 - num2 << endl; // 7
	cout << "num1 * num2 = " << num1 * num2 << endl; // 30
	cout << "num1 / num2 = " << num1 / num2 << endl; // 3	 两个整数相除, 结果为整数. 除数不能为0, 否则报错

	double d1 = 0.25;
	double d2 = 0.11;
	cout << "d1 / d2 = " << d1 / d2 << endl; // 2.27273	两个小数相除, 运算结果是小数


	// 取余
	cout << "num1 % num2 = " << num1 % num2 << endl; // 1	 两个数取余, 除数不能为0
	//cout << "d1 % d2 = " << d1 % d2 << endl; // 报错: 两个小数是不可以做取余的
	

	// ++
	int num3 = 1;
	cout << "num3++ = " << num3++ << endl; // 1
	cout << "num3 = " << num3 << endl; // 2
	num3 = 1;
	cout << "++num3 = " << ++num3 << endl; // 2
	cout << "num3 = " << num3 << endl; // 2

	// --
	num3 = 1;
	cout << "num3-- = " << num3-- << endl; // 1
	cout << "num3 = " << num3 << endl; // 0
	num3 = 1;
	cout << "--num3 = " << --num3 << endl; // 0
	cout << "num3 = " << num3 << endl; // 0

	system("pause");
	return 0;
}

3.2. 赋值运算符

作用

  • 用于将表达式的值赋给变量

赋值运算符

  • =
  • +=
  • -=
  • *=
  • /=
  • %=

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

int main() {
	// =
	int a = 10;
	a = 100;
	cout << "a = " << a << endl; // 100

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

	// -=
	a = 10;
	a -= 2;
	cout << "a = " << a << endl; // 8

	// *=
	a = 10;
	a *= 2;
	cout << "a = " << a << endl; // 20

	// /=
	a = 10;
	a /= 2;
	cout << "a = " << a << endl; // 5

	// %=
	a = 10;
	a %= 2;
	cout << "a = " << a << endl; // 0

	system("pause");
	return 0;
}

3.3. 比较运算符

作用

  • 用于表达式的比较, 并返回一个真值或假值

比较运算符

比较运算符术语
==等于
!=不等于
>大于
<小于
>=大于等于
<=小于等于

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

int main() {
	// ==
	int a = 10;
	int b = 1;
	cout << "a == b = " << (a == b) << endl; // 0

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

	// >
	cout << "a > b = " << (a > b) << endl; // 1

	// <
	cout << "a < b = " << (a < b) << endl; // 0


	// >=
	cout << "a >= b = " << (a >= b) << endl; // 1

	// <=
	cout << "a <= b = " << (a <= b) << endl; // 0	

	system("pause");
	return 0;
}

3.4. 逻辑运算符

作用

  • 用于根据表达式的值返回真值或假值

逻辑运算符

逻辑运算符术语说明
!!a, 如果a为假, 则!a为真, 否则为假
&&a && b, a和b都为真, 结果为真, 否则为假
||a || b, a和b都为假, 结果为假, 否则为真

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

int main() {
	// !
	// 在C/C++中, 0为假, 非0为真(一般使用1来表示)
	int a = 10;
	cout << "a = " << a << endl;
	cout << "!a = " << !a << endl;
	cout << "!!a = " << !!a << endl;

	cout << endl;

	// &&
	int b = 10;
	int c = 10;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
	cout << "(b && c) = " << (b && c) << endl;

	cout << endl;

	b = 10;
	c = 1;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
	cout << "(b && c) = " << (b && c) << endl;

	cout << endl;

	b = 10;
	c = 0;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
	cout << "(b && c) = " << (b && c) << endl;

	cout << endl;

	// ||
	b = 10;
	c = 1;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
	cout << "(b || c) = " << (b || c) << endl;

	cout << endl;

	b = 0;
	c = 0;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
	cout << "(b || c) = " << (b || c) << endl;

	system("pause");
	return 0;
}

4. 程序流程结构

C/C++支持最基本的三种程序运行结构

  • 顺序结构
  • 选择结构
  • 循环结构

4.1. 选择结构

4.1.1. if语句

作用

  • 执行满足条件的语句

if语句的三种形式

  • 单分支
  • 双分支
  • 多分支

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

int main() {
	// 多分支
	// 用户输入分数, 如果分数大于等于600, 视为考上了一本大学, 如果分数在500-600之间, 则视为考上了二本大学, 如果都没有, 则是未考上, 在屏幕上输出
	
	// 1. 输入
	int score;
	cout << "请输入你的高考成绩: ";
	cin >> score;
	// 2. 打印用户输入的分数
	cout << "你输入的高考成绩为: " << score << endl;
	// 3. 判断分数是否大于等于600
	if (score >= 600) {
		// 4. 如果大于等于则输出
		cout << "恭喜你呀, 你考上了一本大学呀!(狗头)" << endl;
	}
	else if(score >= 500) {
		cout << "不错, 你考上了二本大学!(狗头)" << endl;
	}
	else {
		cout << "你的高考成绩小于500, 未考上本科大学" << endl;
	}

	system("pause");
	return 0;
}

练习案例

  • 三只小猪称体重, 有三只小猪ABC, 请分别输入三只小猪的体重, 输出最重的小猪体重?
#include <iostream>
using namespace std;

int main() {
	// 三只小猪称体重, 有三只小猪ABC, 请分别输入三只小猪的体重, 输出最重的小猪体重?

	int a, b, c;
	cin >> a;
	cin >> b;
	cin >> c;
	int max = a;
	if (b > max) {
		max = b;
		if (c > max) {
			max = c;
		}
	}
	else if (c > max) {
		max = c;
		if (b > max) {
			max = b;
		}
	}
	cout << "最重的美猪体重为" << max << endl;
	system("pause");
	return 0;
}
4.1.2. 三目运算符

作用

  • 简单的判断

语法

  • 表达式1 ? 表达式2 : 表达式3

解释

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

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

int main() {
	// 三目运算符
	
	// 创建三个变量a, b, c, 将a和b比较, 将变量大的值赋给变量c
	int a = 10;
	int b = 20;
	int c = (a > b ? a : b);
	cout << "c = " << c << endl;

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

	system("pause");
	return 0;
}
4.1.3. switch语句

作用

  • 执行多条件分支语句

语法

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

示例

#define _CRT_SECURE_NO_WARNINGS 1

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

int main() {
	// switch
	/*
		给电影打分
			10~9 经典
			8~7 比较好
			6~5 一般
			5以下 烂片
	*/
	// 1. 提示用户给电影评分
	cout << "请你输入一个1~10之间的整数, 给这部电影打分: " << endl;

	// 2. 用户开始进行打分
	int score;
	cin >> score;

	// 3. 根据用户输入的分数来提示用户的最后结果
	// 单一出口变量
	string grade;
	// 输入的不对直接结束程序
	if (score > 10 || score < 1) {
		cout << "你输入的数字不对, 请重新输入" << endl;
		return 0;
	}
	switch (score) {
	case 9:
	case 10:
		grade = "经典";
		break;
	case 7:
	case 8:
		grade = "比较好";
		break;
	case 5:
	case 6:
		grade = "一般";
		break;
	default:
		grade = "烂片";
		break;
	}
	// 输出
	cout << "你给出的评价: 这部电影是" << grade << endl;


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


	system("pause");
	return 0;
}

4.2. 循环结构

4.2.1. while

作用

  • 满足循环条件, 执行循环语句

语法

  • while( 循环条件 ) { 循环语句 }

解释

  • 只要循环条件结果为真, 就执行循环语句

示例

#define _CRT_SECURE_NO_WARNINGS 1

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

int main() {
	// while
	// 在屏幕上打印1~10
	// 在执行循环语句的时候, 程序必须提供跳出循环的出口, 否则会出现死循环
	int i = 1;
	while (i <= 10) {
		cout << i << endl;
		i++;
	}


	system("pause");
	return 0;
}

练习案例

  • 猜数字, 系统随机生成一个1到100之间的随机数, 玩家进行猜测, 如果猜错了, 提示玩家数字过大或者过小, 如果猜对了则恭喜玩家胜利, 并退出游戏
#include <iostream>
using namespace std;
#include <string>
// time系统时间头文件包含
#include <ctime>

int main() {
	// 添加随机数种子, 作用: 利用当前系统时间生成随机数, 防止每次随机数都一样
	srand((unsigned int)time(NULL));
	
	// 1. 系统生成一个1~100之间的随机数
	int num1 = rand() % 100 + 1;
	// 2. 玩家进行猜测
	int num2 = 0;
	cout << "欢迎进入猜数字游戏, ";	
	// 单一出口
	string flag;
	while (1) {
		cout << "请输入一个1~100之间的整数进行猜测: ";
		cin >> num2;
		// 判断
		flag = "恭喜你, 猜对了";
		// 3. 判断玩家的猜测
		if (num1 > num2) {
			// 猜错, 提示猜的结果, 过大或者过小, 并重新返回第2步
			flag = "猜小了";
		}
		else if(num1 < num2) {
			flag = "猜大了";
		}
		else {
			// 猜对, 退出游戏
			break;
		}
		// 输出
		cout << flag << endl;
	}
	// 输出
	cout << flag << endl;

	system("pause");
	return 0;
}
4.2.2. doWhile

作用

  • 满足循环条件, 执行循环语句

语法

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

解释

  • 先执行一次循环语句, 再判断循环条件

示例

#include <iostream>
using namespace std;

int main() {
	// doWhile
	// 在屏幕上输出1到10之间的整数
	int num = 1;
	// doWhile会先执行一次循环语句
	do {
		cout << num << endl;
		num++;
	} while (num <= 10);

	system("pause");
	return 0;
}

练习案例

/*
	水仙花数:
		水仙花数是指一个整数的每一位上的数字的总位数次幂之和等于它本身
		例如: 153 = 1^3 + 5^3 + 3^3
		请利用doWhile语句, 求出所有的三位数中的水仙花数
*/

#include <iostream>
using namespace std;
#include <math.h>

int main() {
	int num = 100;
	// 循环产生所有的三位数
	do {
		// 保留num的值
		int num2 = num;
		// 注意: ciMi和sum初始化的位置
		// 次幂
		int ciMi = 1;
		// 次幂之和
		int sum = 0;
		// 取出num2的每一位数
		do {
			// 取出最后一位
			int digit = num2 % 10;
			// 取出剩余位并重新赋给num2, 以便于下次循环继续使用
			num2 /= 10;
			// 每位数的3次幂, pow()是一个求次幂的库函数, 要引用math.h, 这里使用循环的方式求次幂也可以
			ciMi = pow(digit, 3);
			// 求和
			sum += ciMi;
		} while (num2 > 0);
		// 判断次幂之和与本身是否相等
		if (sum == num) {
			cout << num << endl;
		}
		num++;
	} while (num <= 999);
	system("pause");
	return 0;
}
4.2.3. for

作用

  • 满足循环条件, 执行循环语句

语法

  • for(初始化表达式; 条件表达式; 调整表达式){ 循环语句 }

示例

#include <iostream>
using namespace std;

int main() {
	// for
	// 打印1~10之间的整数
	int num;
	for (num = 1; num <= 10; num++) {
		cout << num << endl;
	}
	system("pause");
	return 0;
}

练习案例

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

#include <iostream>
using namespace std;

int main() {
	// 循环产生1~100之间的数字
	int num;
	for (num = 1; num <= 100; num++) {
		if (num % 7 == 0 || num % 10 == 7 || num / 10 == 7) {
			cout << "敲桌子" << endl;
		}
		else {
			cout << num << endl;
		}
	}
	system("pause");
	return 0;
}
4.2.4. 嵌套循环

作用

  • 在循环体中再嵌套一层循环, 解决一些实际问题

练习案例

/*
	在屏幕上打印以下图形, 提示: 使用嵌套循环
	* * * * * * * * * *
	* * * * * * * * * *
	* * * * * * * * * *
	* * * * * * * * * *
	* * * * * * * * * *
	* * * * * * * * * *
	* * * * * * * * * *
	* * * * * * * * * *
	* * * * * * * * * *
	* * * * * * * * * *
*/

#include <iostream>
using namespace std;

int main() {
	// 嵌套循环
	
	// 行
	int i;
	for (i = 0; i < 10; i++) {
		// 列
		int j;
		for (j = 0; j < 10; j++) {
			// 输出
			cout << "* ";
		}
		// 换行
		cout << endl;
	}

	system("pause");
	return 0;
}

练习案例

/*
	在屏幕上打印9*9乘法口诀表
	1 * 1 = 1
	1 * 2 = 2  2 * 2 = 4
	1 * 3 = 3  2 * 3 = 6  3 * 3 = 9
	1 * 4 = 4  2 * 4 = 8  3 * 4 = 12  4 * 4 = 16
	1 * 5 = 5  2 * 5 = 10  3 * 5 = 15  4 * 5 = 20  5 * 5 = 25
	1 * 6 = 6  2 * 6 = 12  3 * 6 = 18  4 * 6 = 24  5 * 6 = 30  6 * 6 = 36
	1 * 7 = 7  2 * 7 = 14  3 * 7 = 21  4 * 7 = 28  5 * 7 = 35  6 * 7 = 42  7 * 7 = 49
	1 * 8 = 8  2 * 8 = 16  3 * 8 = 24  4 * 8 = 32  5 * 8 = 40  6 * 8 = 48  7 * 8 = 56  8 * 8 = 64
	1 * 9 = 9  2 * 9 = 18  3 * 9 = 27  4 * 9 = 36  5 * 9 = 45  6 * 9 = 54  7 * 9 = 63  8 * 9 = 72  9 * 9 = 81
*/

#include <iostream>
using namespace std;

int main() {
	// 行
	int i;
	for (i = 1; i <= 9; i++) {
		// 列
		int j;
		for (j = 1; j <= i; j++) {
			// 输出
			cout << j << " * " << i << " = " << j * i << "  ";
		}
		// 换行
		cout << endl;
	}

	system("pause");
	return 0;
}

4.3. 跳转语句

4.3.1. break

作用

  • 用于跳出switch语句或者循环结构

示例

#include <iostream>
using namespace std;

int main() {
	// break
	
	// 出现在循环中
	//int i;
	//for (i = 0; i < 10; i++) {
	//	// 如果i等于5, 退出循环, 不再打印
	//	if (i == 5) {
	//		// 退出循环
	//		break;
	//	}
	//	cout << i << endl;
	//}



	// 出现在嵌套循环语句
	int i;
	for (i = 1; i <= 10; i++) {
		// 列
		int j;
		for (j = 1; j <= 10; j++) {
			// 判断
			if (j == 6) {
				// 退出内层循环
				break;
			}
			// 输出
			cout << "* ";
		}
		// 换行
		cout << endl;
	}

	system("pause");
	return 0;
}
4.3.2. continue

作用

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

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

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

	system("pause");
	return 0;
}
4.3.3. goto

作用

  • 可以无条件跳转语句

语法

  • goto 标记;

解释

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

建议

  • 由于功能过于强大, 且没有条件限制, 很容易出现问题, 所以不建议使用, 但是在跳出多层循环的时候还是可以使用的

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

int main() {
	// goto
	cout << "1. xxxx" << endl;
	cout << "2. xxxx" << endl;
	// 从这里
	goto flag;
	cout << "3. xxxx" << endl;
	cout << "4. xxxx" << endl;
	// 跳到这里
	flag:
	cout << "5. xxxx" << endl;

	system("pause");
	return 0;
}

5. 数组

5.1. 概述

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

特点

  • 数组中的每个数据元素都是相同的数据类型
  • 数组是由连续的内存位置组成的
  • 每个元素都有下标, 可以通过下标访问数组中的元素
    • 数组下标从0开始

5.2. 一维数组

5.2.1. 定义

定义的三种方式

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

建议

  • 数组名的命名规则和命名规范与变量名的相同
  • 建议不要将数组名和变量名定义成相同的

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

int main() {
	// 一维数组的定义
	/*
		1. 数据类型 数组名[数组长度];
		2. 数据类型 数组名[数组长度] = { 值1, 值2 .... };
		3. 数据类型 数组名[] = { 值1, 值2 .... };
	*/
	// 1. 数据类型 数组名[数组长度];
	int arr[5];
	// 数组元素个数
	int length = sizeof(arr) / sizeof(arr[0]);
	
	// 初始化数组
	int i;
	for (i = 0; i < length; i++) {
		cin >> arr[i];
	}

	// 访问数组元素
	for (i = 0; i < length; i++) {
		cout << arr[i] << endl;
	}
	
	

	// 2. 数据类型 数组名[数组长度] = { 值1, 值2 .... };
	// 如果在初始化数据的时候, 没有全部填完, 会用0来填补剩余数据
	int arr2[5] = { 1, 2, 3 };
	// 数组元素个数
	int length2 = sizeof(arr2) / sizeof(arr2[0]);

	// 访问数组元素
	int j;
	for (j = 0; j < length2; j++) {
		cout << arr2[j] << endl;
	}


	// 3. 数据类型 数组名[] = { 值1, 值2 .... };
	// 这种定义方式, 数组中必须有值
	// 这样也可以得出一条结论: 定义数组的时候, 必须有初始长度
	int arr3[] = { 1, 2, 3, 4, 5 };
	// 数组元素个数
	int length3 = sizeof(arr3) / sizeof(arr3[0]);

	// 访问数组元素
	int k;
	for (k = 0; k < length3; k++) {
		cout << arr3[k] << endl;
	}

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

作用

  • 可以统计整个数组在内存中的长度
  • 可以获取数组在内存中的首元素地址

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

int main() {
	// 数组名
	/*
		作用:
			1. 可以统计整个数组在内存中的长度
			2. 可以获取数组在内存中的地址
	*/

	// 1. 可以统计整个数组在内存中的长度
	int arr[5] = { 1, 2, 3, 4, 5 };
	cout << "整个数组占用内存空间为: " << sizeof(arr) << endl; // 20(byte)
	cout << "每个元素占用内存空间为: " << sizeof(arr[0]) << endl; // 4(byte)
	cout << "数组中元素个数为: " << sizeof(arr) / sizeof(arr[0]) << endl; // 5


	// 2. 可以获取数组在内存中的地址
	cout << "数组首地址为: " << (int)arr << endl;
	// 数组地址和数组中第一个元素的地址是相同的
	cout << "数组中第一个元素地址为: " << (int)&arr [0]<< endl;
	// 第二个元素和第一个元素相隔4(byte)
	cout << "数组中第二个元素地址为: " << (int)&arr[1] << endl;

	// 数组名是常量, 不可以进行赋值操作
	//arr = 10;


	system("pause");
	return 0;
}

练习案例1

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

#include <iostream>
using namespace std;

int main() {
	int arr[5] = { 300, 350, 200, 400, 250 };
	// 数组元素个数
	int length = sizeof(arr) / sizeof(arr[0]);
	// 最大值
	int max = arr[0];

	// 遍历数组
	int i;
	for (i = 1; i < length; i++) {
		if (arr[i] > max) {
			max = arr[i];
		}
	}
	cout << max << endl;

	system("pause");
	return 0;
}

练习案例2

#include <iostream>
using namespace std;

int main() {
	int arr[5] = { 1, 3, 2, 5, 4,  };
	// 数组元素个数
	int length = sizeof(arr) / sizeof(arr[0]);
	

	// 遍历数组
	int start = 0;
	int end = length - 1;
	// 注意判断条件, start下标要小于end下标
	for (start = 0; start < end; start++, end--) {
		int tmp = arr[start];
		arr[start] = arr[end];
		arr[end] = tmp;

		/*
			tmp = arr[0];
			arr[0] = arr[4];
			arr[4] = tmp;


			tmp = arr[1];
			arr[1] = arr[3];
			arr[3] = tmp;
		*/
	}

	// 遍历输出
	int i;
	for (i = 0; i < length; i++) {
		cout << arr[i] << " ";
	}
	cout << endl;

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

作用

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

步骤

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

image-20241017212330562

示例

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

#include <iostream>
using namespace std;

int main() {
	// 冒泡排序

	// 数组
	int arr[9] = { 4, 2, 8, 0, 5, 7, 1, 3, 9 };
	// 数组元素个数
	int length = sizeof(arr) / sizeof(arr[0]);
	int count = 0;

	// 排序前
	cout << "排序前: " << endl;
	for (int j = 0; j < length; j++) {
		cout << arr[j] << " ";
	}
	cout << endl;

	// 总排序轮数 = 元素个数 - 1
	for (count = 0; count < length - 1; count++) {
		// 内层循环对比次数 = 元素个数 - 当前排序轮数 - 1
		for (int i = 0; i < length - count - 1; i++) {
			// 1. 比较相邻的元素, 如果第一个比第二个大, 就交换它们两个
			if (arr[i] > arr[i + 1]) {
				int tmp = arr[i];
				arr[i] = arr[i + 1];
				arr[i + 1] = tmp;
			}
		}
	}
	// 排序后结果
	cout << "排序后: " << endl;
	for (int j = 0; j < length; j++) {
		cout << arr[j] << " ";
	}
	cout << endl;
	
	system("pause");
	return 0;
}

5.3. 二维数组

二维数组就是在一维数组上, 多加了一个维度, 可以把二维数组中的每一个元素看作是一个一维数组

5.3.1. 定义

定义方式

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

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

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

	// 1. 数据类型 数组名[ 行数 ][ 列数 ];
	int arr1[2][3];
	int length1 = sizeof(arr1) / sizeof(arr1[0]);
	int arr1Length1 = sizeof(arr1[0]) / sizeof(arr1[0][0]);
	// 初始化
	for (int i = 0; i < length1; i++) {
		for (int j = 0; j < arr1Length1; j++) {
			cin >> arr1[i][j];
		}
	}

	// 输出
	for (int i = 0; i < length1; i++) {
		for (int j = 0; j < arr1Length1; j++) {
			cout << arr1[i][j] << " ";
		}
		cout << endl;
	}
	cout << endl;


	// 2. 数据类型 数组名[行数][列数] = { { 数据1, 数据2 }, { 数据3, 数据4 } };
	// 建议使用这种, 更直观, 清晰
	int arr2[2][3] = {
		{1, 2, 3},
		{4, 5}
	};
	int length2 = sizeof(arr2) / sizeof(arr2[0]);
	int arr2Length2 = sizeof(arr2[0]) / sizeof(arr2[0][0]);
	// 输出
	for (int i = 0; i < length2; i++) {
		for (int j = 0; j < arr2Length2; j++) {
			cout << arr2[i][j] << " ";
		}
		cout << endl;
	}
	cout << endl;

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

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

	system("pause");
	return 0;
}
5.3.2. 数组名

作用

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

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

int main() {
	// 二维数组名
	/*
		1. 查看二维数组所占内存空间
		2. 获取二维数组首元素地址
	*/


	// 1. 查看二维数组所占内存空间
	int arr[2][3] = {
		{1, 2, 3},
		{4, 5, 6}
	};
	cout << "二维数组占用内存空间: " << sizeof(arr) << endl; // 24(byte)
	cout << "二维数组第一行占用内存空间: " << sizeof(arr[0]) << endl; // 12(byte)
	cout << "二维数组第一个元素占用内存空间: " << sizeof(arr[0][0]) << endl; // 4(byte)
	// 行数
	int length = sizeof(arr) / sizeof(arr[0]);
	// 列数
	int arrLength = sizeof(arr[0]) / sizeof(arr[0][0]);
	cout << "二维数组行数: " << length << endl; // 2
	cout << "二维数组列数: " << arrLength << endl; // 3


	// 2. 获取二维数组首元素地址
	cout << "二维数组地址为: " << (int)arr << endl;
	cout << "二维数组第一行地址为: " << (int)arr[0] << endl;
	cout << "二维数组第二行地址为: " << (int)arr[1] << endl;

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

	system("pause");
	return 0;
}
5.3.3. 应用案例

考试成绩统计

#define _CRT_SECURE_NO_WARNINGS 1

/*
	考试成绩统计:
		有三名同学, 在一次考试中的成绩分别为以下, 请分别输出三名同学的总成绩
		
				语文	数学	英语
		张三	100		100		100
		李四	90		50		100
		王五	60		70		80
*/

#include <iostream>
using namespace std;

int main() {
	// 定义分数二维数组
	int arr[3][3] = {
		{100, 100, 100},
		{90, 50, 100},
		{60, 70, 80}
	};
	int length = sizeof(arr) / sizeof(arr[0]);
	int arrLength = sizeof(arr[0]) / sizeof(arr[0][0]);
	// 定义姓名一维数组
	string names[3] = { "张三", "李四", "王五" };
	// 遍历二维数组中的一维数组
	for (int i = 0; i < length; i++) {
		// 每个人的总分(每个一维数组中的元素总和)
		int scoreSum = 0;
		// 遍历一维数组中的元素
		for (int j = 0; j < arrLength; j++) {
			scoreSum += arr[i][j];
		}
		// 打印每个人的总分(打印每个一维数组的元素总和)
		cout << names[i] << "的总分为: " << scoreSum << endl;
	}


	system("pause");
	return 0;
}

6. 函数

6.1. 概述

作用

  • 讲一段经常使用的代码封装起来, 减少重复代码
  • 一个较大的程序, 一般分为若干个程序块, 每个模块实现特定的功能

6.2. 函数的定义

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

  • 返回值类型
  • 函数名
  • 参数列表
  • 函数体语句
  • return 表达式

语法

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

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

// 函数的定义

// 加法函数, 实现两个整型相加, 并且将相加的结果进行返回
int add(int num1, int num2) {
	int sum = num1 + num2;
	return sum;
}

int main() {

	system("pause");
	return 0;
}

6.3. 函数的调用

作用

  • 使用定义好的函数

语法

  • 函数名(值);

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

// 函数的定义

// 加法函数, 实现两个整型相加, 并且将相加的结果进行返回
// add函数当中的num1和num2是参数
// 参数是用来接收传进来的值的
int add(int num1, int num2) {
	int sum = num1 + num2;
	return sum;
}

int main() {
	int num1 = 1;
	int num2 = 2;
	// 调用add函数并将函数的返回结果赋给sum
	// main函数当中的num1和num2是值
	// 值是用来传入add函数中的, 传给参数
	int sum = add(num1, num2);
	cout << "sum = " << sum << endl;

	num1 = 100;
	num2 = 200;
	sum = add(num1, num2);
	cout << "sum = " << sum << endl;

	system("pause");
	return 0;
}

6.4. 值传递

  • 所谓值传递, 函数调用时值传给参数
  • 值传递时, 如果参数发生改变, 并不会影响本来的值

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

// 值传递
// 定义函数, 实现两个数字进行交换
// 如果函数不需要返回值, 定义的时候返回值类型可以写void
void swap(int* num1, int* num2) {
	int tmp = *num1;
	*num1 = *num2;
	*num2 = tmp;

	// 返回值不需要的时候, 可以不写return
	//return; 
}

int main() {
	int num1 = 1;
	int num2 = 2;
	cout << "交换之前的num1: " << num1 << endl;
	cout << "交换之前的num2: " << num2 << endl;

	// 当我们做值传递的时候, 函数的参数发生改变, 并不影响值
	// 如果想要完成这个功能的话, 需要使用到指针, 将num1和num2的地址作为值传入到swap函数当中, 将它们分别传给参数, 这样就可以实现了, 这个地方初学的时候不用看懂, 到后面会再讲到
	swap(&num1, &num2);
	cout << "交换之后的num1: " << num1 << endl;
	cout << "交换之后的num2: " << num2 << endl;



	system("pause");
	return 0;
}

6.5. 函数的常见样式

常见的函数样式

  • 无参无返
  • 有参无返
  • 无参有返
  • 有参有返

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

// 函数常见样式
// 无参无返
void function01() {
	cout << "function01函数执行了" << endl;
}

// 有参无返
void function02(int a) {
	cout << "function02函数执行了, 参数a = " << a << endl;
}

// 无参有返
int function03() {
	cout << "function03函数执行了" << endl;
	return 10;
}

// 有参有返
int function04(int a) {
	cout << "function04函数执行了, 参数a = " << a << endl;
	return 20;
}

int main() {
	// 无参无返的函数调用
	function01();

	// 有参无返的函数调用
	function02(1);

	// 无参有返的函数调用
	int num1 = function03();
	cout << "返回值num1 = " << num1 << endl;

	// 有参有返的函数调用
	int num2 = function04(2);
	cout << "返回值num2 = " << num2 << endl;


	system("pause");
	return 0;
}

6.6. 函数的声明

作用

  • 告诉编译器函数名称及如何调用函数, 函数的原型可以单独定义

注意

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

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

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

// 提前告诉编译器函数的存在, 可以利用函数的声明
// 函数的声明
int max(int a, int b);

int main() {
	int num1 = 1;
	int num2 = 2;
	
	// 调用max函数
	cout << "max = " << max(num1, num2) << endl;


	system("pause");
	return 0;
}

// 定义
int max(int a, int b) {
	// 三目运算符
	return (a > b ? a : b);
}

6.7. 函数的分文件编写

作用

  • 让代码结果更加清晰

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

  • 创建后缀名为**.h**的文件
  • 创建后缀名为**.cpp**的源文件
  • 头文件中写函数的声明
  • 源文件中写函数的定义

示例

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

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


// --------------------------------------------------



// swap.cpp
#include "swap.h"

// 函数的定义
void swap(int a, int b) {
	int tmp = a;
	a = b;
	b = tmp;

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



// --------------------------------------------------



// test.cpp(存放main函数的地方)
#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

#include "swap.h"

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

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

int main() {
	int a = 10;
	int b = 20;
	swap(a, b);
	
	system("pause");
	return 0;
}

7. 指针

7.1. 指针的基本概念

指针的作用

  • 可以通过指针间接访问内存

注意

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

7.2. 指针变量的定义和使用

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

int main() {
	// 1. 定义指针
	int a = 10;
	// 指针定义的语法: 数据类型* 指针变量名;
	int* p;
	// 让指针记录变量a的地址
	p = &a;
	cout << "a的地址为: " << &a << endl;
	cout << "指针p为: : " << p << endl;
	
	
	// 2. 使用指针
	// 可以通过解引用的方式来找指针之乡的内存
	// 指针前加上*代表解引用, 找到指针指向的内存中的数据
	cout << "a =  " << a << endl;
	cout << "*p = : " << *p << endl;

	system("pause");
	return 0;
}

7.3. 指针所占内存空间

提问

  • 指针也是一种数据类型, 那么这种数据类型占用多少内存空间呢?

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

int main() {
	// 指针所占内存空间大小
	int a = 10;
	int* p = &a;
	cout << "sizeof(p) = " << sizeof(p) << endl; // 8

	// 在64(32)位操作系统下, 指针是占8(4)个字节空间大小, 不管是什么数据类型
	cout << "sizeof(int*) = " << sizeof(int*) << endl; // 8
	cout << "sizeof(double*) = " << sizeof(double*) << endl; // 8
	cout << "sizeof(char*) = " << sizeof(char*) << endl; // 8
	
	
	system("pause");
	return 0;
}

7.4. 空指针和野指针

空指针

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

用途

  • 初始化指针变量

注意

  • 空指针指向的内存是不可以访问

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

int main() {
	// 空指针
	// 1. 空指针用于给指针变量进行初始化
	int* p = NULL;

	// 2. 空指针是不可以进行访问的
	// 0~255之间的内存编号是系统占用的, 因此不可以访问

	/*
		引发了异常: 写入访问权限冲突。
		p 是 nullptr。
	*/
	//*p = 100;
	//cout << *p << endl;
	
	system("pause");
	return 0;
}

野指针

  • 指针变量是指向非法的内存空间

示例2

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

	/*
		引发了异常: 读取访问权限冲突。
		p2 是 0x1100。
	*/
	cout << *p2 << endl;

7.5. const修饰指针

const修饰指针有三种情况

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

image-20241019192810158

image-20241019194530093

image-20241019194419600

记忆技巧

  • 常量指针(const int* p)

  • 指针常量(int* const p)

  • 名称记忆

    • const看成常量, int*看成指针
    • 顺序读
  • 特点记忆

    • int* p看成一个整体, p看成一个整体
    • const修饰的第一个(也可以说右边的第一个)就是不可以改变的

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

int main() {
	// 1. const修饰指针
	int a = 10;
	int b = 10; 
	
	const int* p = &a;
	// *p = 20; // 错误, 指针指向的值不可以改
	p = &b; // 正确, 指针的指向可以改

	// 2. const修饰常量
	int* const p2 = &a;
	*p2 = 20; // 正确, 指针指向的值可以改
	// p2 = &b; // 错误, 指针的指向不可以改



	// 3. const修饰指针和常量
	const int* const p3 = &a;
	// *p3 = 20; // 错误, 指针指向的值不可以改
	// p3 = &b; // 错误, 指针的指向不可以改



	system("pause");
	return 0;
}

7.6. 指针和数组

作用

  • 利用指针访问数组中元素

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
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;
	cout << "利用指针访问第一个元素: " << *p << endl;
	
	p++; // 让指针向后偏移4个字节
	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. 指针和函数

作用

  • 利用指针做函数参数, 可以修改实参的值
  • 这里就可以解决之前在函数章节讲到的swap函数(进行两个值的互换)

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;


// 定义函数, 实现两个数字进行交换
// 传进来的地址使用指针来接收, 所以参数类型为指针
void swap(int* num1, int* num2) {
	// 指针里面有了地址, 使用的时候要解引用
	int tmp = *num1;
	*num1 = *num2;
	*num2 = tmp;
}

int main() {
	int num1 = 1;
	int num2 = 2;
	cout << "交换之前的num1: " << num1 << endl;
	cout << "交换之前的num2: " << num2 << endl;

	// 地址传递
	// 调用函数时, 将num1和num2的地址传进去
	swap(&num1, &num2);
	cout << "交换之后的num1: " << num1 << endl;
	cout << "交换之后的num2: " << num2 << endl;



	system("pause");
	return 0;
}

7.8. 指针, 数组, 函数

案例描述

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

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

// 封装一个函数, 利用冒泡排序, 实现对整数数组的升序排序
void bubbleSort(int* arr, int length); // 函数声明

int main() {
	// 定义一个数组
	int arr[10] = { 4, 3, 6, 9, 1, 2, 10, 8, 7, 5 };
	// 数组长度
	int length = sizeof(arr) / sizeof(arr[0]);
	// 调用函数
	bubbleSort(arr, length);

	// 打印排序好的数组
	for (int i = 0; i < length; i++) {
		cout << arr[i] << " ";
	}
	cout << endl;

	system("pause");
	return 0;
}

// 函数定义
void bubbleSort(int* arr, int length) {
	// 
	for (int i = 0; i < length - 1; i++) {
		for (int j = 0; j < length - i - 1; j++) {
			// 如果当前数大于右边的数则交换两个数
			if (arr[j] > arr[j + 1]) {
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}

8. 结构体

8.1. 基本概念

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

8.2. 定义和使用

语法

  • struct 结构体名 { 结构体成员列表 };

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

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

示例

#define _CRT_SECURE_NO_WARNINGS 1

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

// 1. 创建学生数据类型: 学生包括(姓名, 年龄, 分数)
// 自定义数据类型, 一些类型集合组成的一个类型
// 定义结构体类型时, 关键字不能省略
struct Student {
	// 成员列表
	
	// 姓名
	string name;
	// 年龄
	int age;
	// 分数
	int score;
} s3; // 顺便创建结构体变量

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

int main() {
	
	// 2.1. struct Student s1
	// 创建变量时, struct关键字可以省略
	struct Student s1;
	// Student s1;
	// 结构体变量利用"."操作符访问成员
	s1.name = "区区一散修";
	s1.age = 20;
	s1.score = 100;
	cout << "姓名: " << s1.name << ", 年龄: " << s1.age << ", 分数: " << s1.score << endl;
	
	// 2.2. struct Student s2 = { ... }
	struct Student s2 = { "区天尊", 30, 150};
	cout << "姓名: " << s2.name << ", 年龄: " << s2.age << ", 分数: " << s2.score << endl;

	// 2.3. 在定义结构体时顺便创建结构体变量
	// 这种方式不建议使用, 见到了知道就可以
	s3.name = "区老魔";
	s3.age = 40;
	s3.score = 200;
	cout << "姓名: " << s3.name << ", 年龄: " << s3.age << ", 分数: " << s3.score << endl;
	
	system("pause");
	return 0;
}

8.3. 结构体数组

作用

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

语法

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

示例

#define _CRT_SECURE_NO_WARNINGS 1

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

// 结构体数组
// 1. 定义结构体
struct Student {
	// 姓名
	string name;
	// 年龄
	int age;
	// 分数
	double score;
};

int main() {
	
	// 2. 创建结构体数组
	struct Student stuArray[3] = {
		{"区区一散修", 20, 100},
		{"区天尊", 30, 150},
		{"区老魔", 40, 200} 
	};

	// 3. 给结构体数组中的元素赋值
	stuArray[0].name = "区区一散修他爸";
	stuArray[0].age = 300;
	stuArray[0].score = 1000;

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

	system("pause");
	return 0;
}

8.4. 结构体指针

作用

  • 通过指针访问结构体中的成员

访问

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

示例

#define _CRT_SECURE_NO_WARNINGS 1

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

// 结构体指针
struct Student {
	// 姓名
	string name;
	// 年龄
	int age;
	// 分数
	double score;
};

int main() {
	// 1. 变量创建学生结构体变量
	struct Student s1 = { "区区一散修", 20, 100 };
	// 2. 通过指针指向结构体b变量
	Student* Sp = &s1;
	// 3. 通过指针访问结构体变量中的数据
	s1.name;
	(*Sp).name; // 这种方式也可以, 但是写的东西有点多, 而且不清晰, 所以建议使用->进行访问
	// 通过结构体指针 访问结构体中的属性, 需要使用'->'
	Sp->name;
	cout << "姓名: " << Sp->name << ", 年龄: " << Sp->age << ", 分数: " << Sp->score << endl;

	system("pause");
	return 0;
}

8.5. 结构体嵌套结构体

作用

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

例如

  • 每个老师辅导一个学员, 一个老师的结构体中, 记录一个学生的结构体

示例

#define _CRT_SECURE_NO_WARNINGS 1

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

// 结构体嵌套结构体

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

// 定义老师结构体
struct Teacher {
	// 教室编号
	string id;
	// 姓名
	string name;
	// 年龄
	int age;
	// 辅导的学生
	struct Student stu1;
};

int main() {
	// 创建老师
	Teacher t;
	t.id = "123456789";
	t.name = "区老师";
	t.age = 50;
	t.stu1.name = "区区一散修";
	t.stu1.age = 20;
	t.stu1.score = 100;
	cout << "老师编号: " << t.id << ", 老师姓名: " << t.name << ", 老师年龄: " << t.age << endl;
	cout << "老师辅导的学生姓名: " << t.stu1.name << ", 学生年龄: " << t.stu1.age << ", 学生分数: " << t.stu1.score << endl;
	

	system("pause");
	return 0;
}

8.6. 结构体做函数参数

作用

  • 将结构体作为参数向函数中传递

传递方式有两种

  • 值传递
  • 地址传递

总结

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

示例

#define _CRT_SECURE_NO_WARNINGS 1

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

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

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

// 2. 地址传递
void printStudent2(Student* s1) {
	s1->age = 200;
	cout << "printStudent2中, 姓名: " << s1->name << ", 年龄: " << s1->age << ", 分数: " << s1->score << endl;
}

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

	// 创建结构体变量
	struct Student s1;
	s1.name = "区区一散修";
	s1.age = 20;
	s1.score = 100;
	
	cout << "main中, 姓名: " << s1.name << ", 年龄: " << s1.age << ", 分数: " << s1.score << endl;

	cout << endl;

	printStudent1(s1);
	cout << "main中, 姓名: " << s1.name << ", 年龄: " << s1.age << ", 分数: " << s1.score << endl;

	cout << endl;

	printStudent2(&s1);
	cout << "main中, 姓名: " << s1.name << ", 年龄: " << s1.age << ", 分数: " << s1.score << endl;
	cout << endl;


	system("pause");
	return 0;
}

8.7. 结构体中const使用场景

作用

  • 用const来防止误操作

示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

// const的使用场景
struct Student {
	// 姓名
	string name;
	// 年龄
	int age;
	// 分数
	int score;
};

// 将函数中的参数改为指针, 可以减少内存空间, 因为指针只占用8个字节的空间, 如果传递的不是指针的话, 就会再次开辟一块内存空间, 浪费空间
void printStudents(const Student* s) {
	//s->age = 250; // 加入const之后, 一旦有修改的操作就会报错, 可以防止我们误操作
	cout << "姓名: " << s->name << ", 年龄: " << s->age << ", 分数: " << s->score << endl;
}

int main() {
	// 创建结构体变量
	Student s = { "区区一散修", 20, 100 };
	// 通过函数打印结构体变量信息
	printStudents(&s);
	cout << "main中那个男人的年龄: " << s.age << endl;

	system("pause");
	return 0;
}

8.8. 结构体案例

8.8.1. 案例1

案例描述

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

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

示例

#include <iostream>
using namespace std;

// 学生的结构体定义
struct Student {
	// 姓名
	string sName;
};

// 老师的结构体定义
struct Teacher {
	// 姓名
	string tName;
	// 学生成员
	Student student[5];
};

// 赋值
void allocateSpace(Teacher* tArray, int length) {
	// 小套路
	string nameSeed = "ABCDE";
	// 给老师赋值
	for (int i = 0; i < length; i++) {
		tArray[i].tName = "Teacher_";
		// 拼接
		tArray[i].tName  += nameSeed[i];
		for (int j = 0; j < 5; j++) {
			// 拼接
			tArray[i].student[j].sName = tArray[i].tName + "_";
			tArray[i].student[j].sName += "Student_";
			tArray[i].student[j].sName += nameSeed[j];
		}
	}
}

// 打印信息
void printInfo(Teacher* tArray, int length) {
	for (int i = 0; i < length; i++) {
		cout << tArray[i].tName << endl;
		for (int j = 0; j < 5; j++) {
			cout << "\t" << tArray[i].student[j].sName << endl;
		}
	}
} 

int main() {
	// 创建老师结构体
	Teacher tArray[3];
	int length = sizeof(tArray) / sizeof(tArray[0]);
	// 调用函数给学生赋值
	allocateSpace(tArray, length);
	// 打印函数
	printInfo(tArray, length);


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

案例描述

设计一个英雄的结构体, 包括成员姓名, 年龄, 性别; 创建结构体数组, 数组中存放5名英雄, 通过冒泡排序的算法, 将数组中的英雄按照年龄进行升序排序, 最终打印排序后的结果

五名英雄信息如下

        {"刘备", 23, "男"},
        {"关羽", 22, "男"},
        {"张飞", 20, "男"},
        {"赵云", 21, "男"},
        {"貂蝉", 19, "女"},

示例

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

// 英雄的结构体
struct Hero {
	// 姓名
	string name;
	// 年龄
	int age;
	// 性别
	string gender;
};

// 冒泡
void bubbleSort(Hero* hArray, int length) {
	for (int i = 0; i < length - 1; i++) {
		for (int j = 0; j < length - i - 1; j++) {
			// 比较年龄
			if (hArray[j].age > hArray[j + 1].age) {
				// 交换结构体数组中的元素, 而不是只交换年龄
				// 注意: tmp应该为Hero类型, 因为结构体数组也是Hero类型
				Hero tmp = hArray[j];
				hArray[j] = hArray[j + 1];
				hArray[j + 1] = tmp;
			}
		}
	}
}
// 打印
void printInfo(Hero* hArray, int length) {
	for (int i = 0; i < length; i++) {
		cout << "姓名: " << hArray[i].name << ", 年龄: " << hArray[i].age << ", 性别: " << hArray[i].gender << endl;
	}
}

int main() {
	// 创建结构体数组
	Hero hArray[5] = {
		{"刘备", 23, "男"},
		{"关羽", 22, "男"},
		{"张飞", 20, "男"},
		{"赵云", 21, "男"},
		{"貂蝉", 19, "女"},
	};
	int length = sizeof(hArray) / sizeof(hArray[0]);
	// 排序前打印
	cout << "排序前 : " << endl;
	printInfo(hArray, length);
	// 冒泡
	bubbleSort(hArray, length);
	// 排序后打印
	cout << "排序后 : " << endl;
	printInfo(hArray, length);


	system("pause");
	return 0;
}

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部