![](https://img-blog.csdnimg.cn/588421ad7ef94a7f8264bcd025493e45.png)
一、初识C++
0. Visual Studio 使用
1.1 Hello World!
#include <iostream>
using namespace std;
int main()
{
cout << "Hello World!" << endl;
system("pause");
return 0;
}
1.2 注释
// 这是单行注释
/*
这是多行注释
可以注释多行
*/
1.3 变量
1.4 常量
- 记录程序中不能修改的数据
- #define 宏常量
- 通常在文件上方定义,没有分号结尾
-
#define 宏常量名称 宏常量值
- const 修饰的变量
- 在变量定义前加const,修饰该变量为常量
-
const 变量类型 变量名 = 变量值;
// 4.1 #define 宏常量
#define DAY 7
int main() {
// DAY = 14; // 错误:DAY是常量,一旦修改就会报错
cout << "一周共有" << DAY << "天" << endl;
// 4.2 const 修饰变量
const int MONTH = 12;
// MONTH = 14; // 错误:const修饰的变量也成为常量
cout << "一周共有" << MONTH << "个月份" << endl;
system("pause");
return 0;
}
1.5 关键字(标识符)
asm | do | if | return | typedef |
auto | double | inline | short | typeid |
bool | dynamic_cast | int | signed | typename |
break | else | long | sizeof | union |
case | enum | mutable | static | unsigned |
catch | explict | namespace | static_cast | using |
chat | export | new | struct | virtual |
class | extern | operator | switch | void |
const | false | private | template | volatile |
const_cast | float | protected | this | wchar_t |
continue | for | public | throw | while |
default | friend | register | true | |
delete | goto | reinterpret_cast | try | |
1.6 标识符命名规则
- 标识符不能是关键字
- 标识符只能由字母、数字、下划线组成
- 第一个字符必须为字母或下划线
- 标识符中的字母区分大小写
- 见名知意
二、数据类型
- 创建变量时必须指出相应的数据类型,否则无法给变量分配内存
- 数据类型存在意义:给变量分配合适的内存空间
2.1 整型
数据类型 | 占用空间 | 取值范围 |
---|
short | 2 bytes | -2^15 ~ 2^15-1 (-32768 ~ 32767) |
int | 4 bytes | -2^31 ~ 2^31-1 |
long | Windows 4 bytes, Linux 4 bytes / 8 bytes | -2^31 ~ 2^31-1 |
long long | 8 bytes | -2^63 ~ 2^63-1 |
- 占用空间:short < int <= long <= long long
short num = 32768;
cout << num << endl; // -32768
2.2 sizeof关键字
- 统计数据类型所占内存大小
- sizeof( 数据类型 / 变量 )
short num1 = 10;
cout << "short占用内存空间为:" << sizeof(short) << endl; //2
cout << "num1占用内存空间为:" << sizeof(num1) << endl; // 2
short num2 = 32768;
cout << sizeof(num2) << endl; // 2
2.3 实型(浮点型)
数据类型 | 占用空间 | 有效数字范围 |
---|
float | 4字节 | 7位有效数字 |
double | 8字节 | 15-16位有效数字 |
float f1 = 3.14f; // 没有f默认双精度
double d1 = 3.14;
float f2 = 3.1415926;
cout << f2 << endl; // 3.14159 默认显示六位有效数字
cout << "float占用内存空间为:" << sizeof(float) << endl; // 4
cout << "double占用内存空间为:" << sizeof(double) << endl; // 8
// 科学计数法 e关键字
float f3 = 3e2; // 3 * 10^2;
float f4 = 3e-2; // 3 * (0.1)^2;
cout << f3 << endl; // 300
cout << f4 << endl; // 0.03
2.4 字符型
- 表示单个字符,写在单引号内
- C和C++中字符型变量只占用1个字节内存
- 字符型变量并不存储字符本身,而是存对应的ASCII码放入存储单位
- ASKII码
- 非打印控制符0-31,打印字符(键盘上能找到)31-126
- 常见ASKII码:a-97, A-65
char ch = 'a';
cout << ch << endl; // a
cout << "char占用内存空间为:" << sizeof(char) << endl; // 1
char ch2 = "b"; // 错误:不能用双引号
char ch2 = 'abcdef'; // 错误:单引号内只能有一个字符
// 输出ASKII码值
cout << (int)ch << endl; // 97
2.5 转义字符
cout << "Hello World!\n"; // Hello World!
cout << "\\" << endl; // '\'
cout << "aaa\tHelloWorld" << endl; // aaa HelloWorld
// HelloWorld前空格数加字符一共是8个字符
转义字符 | 含义 | ASKII码 |
---|
\a | 警报 | 007 |
\b | 退格BS | 008 |
\f | 换页FF | 012 |
\n | 换行 | 010 |
\r | 回车 | 013 |
\t | 水平制表 | 009 |
\v | 垂直制表 | 011 |
\\ | 代表一个反斜线字符 “\” | 092 |
\' | 代表一个单引号字符 | 039 |
\" | 代表一个双引号字符 | 034 |
\? | 代表一个问号 | 063 |
\0 | 数字0 | 000 |
\ddd | 8进制转义字符,d范围0-7 | 3位8进制 |
\xhh | 16进制转义字符,h范围0-9 a-f A-F | 3位16进制 |
2.6 字符串型
- C风格字符串:char 变量名[] = “字符串值”;
- C++风格字符串:string 变量名 = “字符串值”;
- 需要包含头文件 #include <string>
// C风格
char str[] = "Hello World!";
cout << str << endl;
// C++风格 需要包含头文件 #include <string>
string str2 = "Hello World!";
cout << str2 << endl;
2.7 布尔类型 bool
- 只有两种值
- true 真(本质是1或非0)
- false 假(本质是0)
bool flag = true; // true代表1
cout << flag << endl; // 1
flag = false;
cout << flag << endl; // 0
cout << "bool占用内存空间为:" << sizeof(bool) << endl; // 1
2.8 数据的输入
int a = 0;
cout << "请给整型变量a赋值:" << endl;
cin >> a;
cout << "整型变量a = " << a << endl;
bool flag = false;
cout << "请给bool类型flag赋值:" << endl;
cin >> flag; // 输入非0数字结果都是1,输入true无效
cout << "flag = " << flag << endl;
三、运算符
运算符类型 | 作用 |
---|
算术运算符 | 处理四则运算 |
赋值运算符 | 将表达式的值赋给变量 |
比较运算符 | 比较表达式并返回一个真值或假值 |
逻辑运算符 | 根据表达式的值返回真值或假值 |
3.1 算术运算符
运算符 | 术语 | 示例 | 结果 |
---|
+ | 加 | 10 + 5 | 15 |
- | 减 | 10 - 5 | 5 |
* | 乘 | 10 * 5 | 50 |
/ | 除 | 10 / 5 | 2 |
+ | 正号 | +5 | 5 |
- | 负号 | -5 | -5 |
% | 取模 | 10 % 3 | 1 |
a++ | 后置递增 | a = 2, b = a++ | a = 3, b = 2 |
++a | 前置递增 | a = 2, b = ++a | a = 3, b = 3 |
a-- | 后置递减 | a = 2, b = a-- | a = 1, b = 2 |
--a | 前置递减 | a = 2, b = --a | a = 1, b = 1 |
1) 加减乘除正负
- 两个整数相除结果依然是整数,小数部分去除
- 两个小数可以相除 结果可以为小数
- 除数不能为0
cout << 10 / 3 << endl; // 3
cout << 10 / 20 << endl; // 0
cout << 0.5 / 0.2 << endl; // 2.5
cout << 10 / 0 << endl; // 错误,除数不能为0
2) 取模
cout << 10 % 3 << endl; // 1
cout << 10 % 20 << endl; // 10
cout << 0.5 % 0.2 << endl; // 错误,被除数和除数都应为整数
cout << 10 % 0 << endl; // 错误,除数不能为0
3) 递增递减运算
- 前置:先加减,后表达式运算
- 后置:先表达式运算,后加减
int a = 10;
int b1 = ++a * 10;
cout << b1 << endl; // a = 11, b = 110
a = 10;
int b2 = a++ * 10;
cout << b2 << endl; // a = 11, b = 100
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 |
3.3 比较运算符
运算符 | 术语 | 示例 | 结果 |
---|
== | 相等 | 4 == 3 | 0 |
!= | 不等 | 4 != 3 | 1 |
< | 小于 | 4 < 3 | 0 |
> | 大于 | 4 > 3 | 1 |
<= | 小于等于 | 4 <= 3 | 0 |
>= | 大于等于 | 4 >= 3 | 1 |
int a = 10;
int b = 20;
cout << (a == b) << endl; // 0
cout << (a != b) << endl; // 1
3.4 逻辑运算符
运算符 | 术语 | 示例 | 结果 |
---|
! | 非 | !a | a假!a真,a真!a假 |
&& | 与 | a&&b | 同真为真 其余为假 |
|| | 或 | a||b | 同假为假 其余为真 |
int a = 10;
int b = 10;
cout << !a << endl; // 0
cout << !!a << endl; // 1
cout << (a && b) << endl; // 0
cout << (a || b) << endl; // 1
四、程序流程结构
- 顺序结构:程序按顺序执行,不发生跳转
- 选择结构:依据条件是否满足,有选择的执行相应的功能
- 循环结构:一句条件是否满足,循环多次执行某段代码
4.1 选择结构
1) if语句
int score = 0;
cout << "请输入分数:" << endl;
cin >> score;
// 单行if
if (score >= 60) {
cout << "及格" << endl;
}
// 多行if
if (score >= 60) {
cout << "及格" << endl;
} else {
cout << "不及格" << endl;
}
// 多条if语句
if (score > 90) {
cout << "优秀" << endl;
} else if (score >= 60) {
cout << "及格" << endl;
} else {
cout << "不及格" << endl;
}
// 嵌套if
if (score > 90) {
if (score == 100) {
cout << "满分" << endl;
} else {
cout << "优秀" << endl;
}
} else if (score >= 60) {
cout << "及格" << endl;
} else {
cout << "不及格" << endl;
}
2) 三目运算符
- 表达式1 ? 表达式2 : 表达式3;
- 表达式1成立则执行表达式2,不成立则执行表达式3
int a = 10;
int b = 20;
int c = 0;
c = (a > b ? a : b); // c = 20
(a > b ? a : b) = 100; // a = 10, b = 100
3) switch语句
switch (表达式)
{
case 结果1: 执行语句;break;
case 结果1: 执行语句;break;
...
default 执行语句;break;
}
int score = 0;
cin >> score;
switch (score) {
case 10:
cout << "优秀" << endl;
break;
case 9:
cout << "及格" << endl;
break;
case 8:
cout << "良好" << endl;
break;
default:
cout << "一般" << endl;
break;
- if vs switch
- switch判断是只能整型或字符型,不可以是一个区间
- switch结构清晰,执行效率高
4.2 循环结构
1) while循环语句
- 只要满足循环条件,就会执行循环语句
- 循环条件为1是死循环
// 循环打印 0~9
int num = 0;
while (num < 10) {
cout << num << endl;
num++;
}
// 添加随机数种子
srand((unsigned int) time(NULL));
// 生成随机数
int num = rand() % 100 + 1; // rand()%100 生成0~99之间的随机数
int val = 0;
while (1) {
cout << "请猜数:" << endl;
cin >> val;
if (val > num) {
cout << "猜测过大" << endl;
} else if (val < num) {
cout << "猜测过小" << endl;
} else {
cout << "猜对了" << endl;
break;
}
}
2) do-while 循环
- do(循环代码) while(循环条件);
- 先执行一遍语句后进行条件判断
// 输出 0~9
int num = 0;
do {
cout << num << endl;
num++;
} while (num < 10);
int num = 0;
do {
cout << num << endl;
num++;
} while (num); // 死循环
while (num) { // 不会输出
cout << num << endl;
num++;
}
// 水仙花数:各个数位三次方之和等于数字本身
int num = 100;
int a, b, c = 0;
do {
a = num / 100; // 百位
b = num / 10 % 10; // 十位
c = num % 10; // 个位
if (a * a * a + b * b * b + c * c * c == num) {
cout << num << endl;
}
num++;
} while (num < 1000);
3) for循环
- for(起始表达式; 条件表达式; 末尾循环体) { 循环语句;}
for (int i = 0; i < 10; i++) {
cout << i << endl;
}
for (int i = 1; i <= 100; i++) {
if (i % 10 == 7 || i / 10 == 7 || i % 7 == 0) { // 个位有7、十位有7、7的倍数
cout << "敲桌子" << endl;
} else
cout << i << endl;
}
// 打印9*9乘法表
for (int i = 1; i < 10; i++) {
for (int j = 1; j <= i; j++) {
cout << i << " * " << j << " = " << i * j << ' ';
}
cout << endl;
}
4.3 跳转语句
1) break
- 跳出选择结构或循环结构
- switch语句中,终止case并跳出swich
- 循环语句中,跳出当前循环语句
- 嵌套循环中,跳出最近内层循环结构
for (int i = 0; i < 10; i++) {
if (i == 5) break; // i = 5就退出循环
}
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
if (j == i + 1) break; // 结束j的循环 继续i的循环
cout << "* ";
}
cout << endl;
}
2) continue语句
- 在循环语句中,跳过本次循环中余下未执行语句,执行下一次循环
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) continue; // 奇数输出,偶数不输出
cout << i << endl;
}
3) goto语句
- 可以无条件跳转语句,如果标记存在,执行到goto语句时就会跳转到标记的位置
cout << "pharse 1" << endl;
cout << "pharse 2" << endl;
goto FLAG;
cout << "pharse 3" << endl;
cout << "pharse 4" << endl;
FLAG:
cout << "pharse 5" << endl; // 只打印 1 2 5
五、数组
5.1 概述
- 数组中每个数组元素都是相同的数据类型
- 数组是由连续的内存空间组成的
5.2 一维数组
1) 一维数组的三种定义方式
- 数据类型 数组名[数组长度];
- 数据类型 数组名[数组长度] = {值1, 值2, ...};
- 数据类型 数组名[] = {值1, 值2, ...};
// 方式1:数据类型 数组名 [数组长度];
int arr[5];
arr[0] = 10;
arr[1] = 20;
arr[2] = 30;
arr[3] = 40;
arr[4] = 50;
// 方式2
// 初始化时没有全部填写完,会用0填补余下数据
int arr2[5] = { 10, 20, 30, 40, 50 };
int arr3[5] = { 10,20,30 };
cout << arr2[4] << endl; // 50
cout << arr3[4] << endl; // 0
// 方式3
int arr4[] = { 90,80,70,60,50 };
// 访问数组元素
cout << arr[0] << endl; // 10
// 遍历
for (int i = 0; i <= 4; i++) {
cout << arr[i] << endl;
}
2) 一维数组名
- 统计整个数组在内存中的长度 sizeof(数组名)
- 获取数组在内存中的首地址
int arr[] = { 90,80,70,60,50 };
// 通过数组名统计整个数组占用内存大小
cout << "整个数组占用内存空间:" << sizeof(arr) << endl; // 20
cout << "每个元素占用内存空间:" << sizeof(arr[1]) << endl; // 4
cout << "数组中元素个数:" << sizeof(arr)/sizeof(arr[1]) << endl; // 5
// 通过数组名查看数组首地址
cout << "数组的首地址为:" << (int)arr << endl; // 663747800
cout << "数组首元素的地址为:" << (int)&arr[0] << endl; // 663747800
cout << "数组第二个元素的地址为:" << (int)&arr[1] << endl; // 663747804
// 数组名是常量,不可以进行赋值操作
arr = 10; // 错误
// 五只小猪称体重
int pig[5];
int max = 0;
int index = 0;
for (int i = 0; i < 5; i++) {
cout << "请输入第" << i+1 << "只小猪的体重" << endl;
cin >> pig[i];
if (pig[i] > max) {
max = pig[i];
index = i+1;
}
}
cout << "第" << index << "只小猪最重,体重为:" << max << endl;
// 数组倒置
int arr[] = { 1,2,3,4,5 };
int start = 0;
int end = sizeof(arr) / sizeof(arr[0]) - 1;
while (start != end) {
int temp = arr[start];
arr[start] = arr[end];
arr[end] = temp;
start++;
end--;
}
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]);i++) {
cout << arr[i] << endl;
}
// 冒泡排序
int arr[] = { 2,4,0,5,7,1,3,9,8 };
int length = sizeof(arr) / sizeof arr[0];
for (int i = 0; i < length-1; i++) { // 总排序轮数 = 元素个数 - 1
for (int j = 0; j < length - i-1; j++) { // 内层循环次数 = 元素个数 - i - 1
if (arr[j] > arr[j+1]) {
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
5.3 二维数组
1) 定义方式
// 方式1:数据类型 数组名[行数][列数]; 数组名[行数][列数] = ...;
int arr1[2][3];
arr1[0][0] = 1;
arr1[0][1] = 2;
// 方式2:数据类型 数组名[行数][列数] = { {数据1, 数据2,数据3 ...}, {数据3, 数据4,数据5 ...} ... };
int arr2[2][3] =
{
{1,2,3},
{4,5,6}
};
// 方式3:数据类型 数组名[行数][列数] = {数据1, 数据2,数据3 ... };
int arr3[2][3] = { 1,2,3,4,5,6 };
// 方式4:数据类型 数组名[][列数] = {数据1, 数据2,数据3 ... };
int arr4[][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;
}
2) 二维数组名
int arr[2][3] = {
{1,2,3},
{4,5,6}
};
cout << "数组arr占用的内存空间为:" << sizeof(arr) << endl; // 24 4字节*6个字符
cout << "数组arr第一行占用的内存空间为:" << sizeof(arr[0]) << endl; // 12
cout << "数组arr第一个元素占用的内存空间为:" << sizeof(arr[0][0]) << endl; // 4
cout << "数组arr行数:" << sizeof(arr) / sizeof(arr[0]) << endl;
cout << "数组arr列数:" << sizeof(arr[0]) / sizeof(arr[0][0]) << endl;
cout << "二维数组的首地址为:" << (int)arr << endl; // 558890152
cout << "二维数组第1行的首地址为:" << (int)arr[0] << endl; // 558890152
cout << "二维数组第1个元素的首地址为:" << (int)&arr[0][0] << endl; // 558890152
cout << "二维数组第2行的首地址为:" << (int)arr[1] << endl; // 558890164 与第一行差12
六、函数
6.1 概述
6.2 函数的定义
返回值类型 函数名(参数列表){
函数体语句;
return 表达式;
}
6.3 函数的调用
int add(int num1, int num2) { // num1和num2并没有实际的值,形参
int sum = num1 + num2;
return sum;
}
int main() {
int a = 10;
int b = 20;
int c = add(a, b); // a和b为实际参数,实参
cout << c << endl;
}
6.4 值传递
// 如果函数不需要返回值,声明时候可以写void,可以不写return
void swap(int num1, int num2) {
int temp = num1;
num1 = num2;
num2 = temp;
}
int main() {
int a = 10;
int b = 20;
swap(a, b); // a = 10, b = 20
}
6.5 函数的常见样式
void test01() {
cout << "无参无返" << endl;
}
void test02(int a) {
cout << "有参无返,参数为a" << endl;
}
int test03() {
cout << "无参有返" << endl;
return 10;
}
int test04(int a) {
cout << "有参有返" << endl;
return 100 + a;
}
int main() {
test01();
test02(10);
int a = test03(); // a = 10
int b = test04(100); // b = 200;
}
6.6 函数的声明
- 没有函数声明的话,函数写在main函数后调用时会报错
- 提前告诉编译器函数的存在,可以利用函数的声明
- 函数声明可以有多次,但函数定义只能有一次
// 函数声明
int max(int a, int b);
int main() {
int a = 10;
int b = 20;
cout << max(a, b) << endl;
}
// 函数定义
int max(int a, int b) {
return a > b ? a : b;
}
6.7 函数的分文件编写
- 步骤:
- 创建后缀名为.h的头文件
- 创建后缀名为.cpp的源文件
- 在头文件中写函数的声明,外加 #include<iostream> 和 using namespace std;
- 在源文件中写函数的定义,外加一句 #inlude “头文件名.h"
- 在调用项目中引用 #include “头文件名.h”
七、指针
7.1 指针的基本概念
- 通过指针保存一个地址,间接访问内存
- 内存编号是从0开始记录的,一般用16进制数字表示
- 可以利用指针变量保存地址
7.2 指针变量的定义和使用
- 指针定义:数据类型* 指针变量名;
- 指针记录a的地址
- 指针前加*代表解引用,找到指针指向的内存
// 1 定义指针: 数据类型* 指针变量名
int a = 10;
int* p;
// 指针记录a的地址
p = &a;
cout << "指针p为:" << p << endl; // 000000A53A4FFAF4
cout << "a的地址为:" << &a << endl; // 000000A53A4FFAF4
// 2 使用指针: 指针前加*代表解引用,找到指针指向的内存
*p = 1000;
cout << *p << endl; // 1000
cout << a << endl; // 1000
7.3 指针占用内存空间
- 在32位操作系统下:占用4个字节空间
- 在64位操作系统下:占用8个字节空间
int a = 10;
int* p = &a;
cout << sizeof(p) << endl; // 8
cout << sizeof(int*) << endl; // 8
cout << sizeof(float*) << endl; // 8
cout << sizeof(double*) << endl; // 8
cout << sizeof(char*) << endl; // 8
7.4 空指针和野指针
- 空指针:指针变量指向内存中编号为0的内存空间
- 用于 初始化指针变量
- 空指针指向的内存是不可以访问的
- 0~255之间的内存编号是被系统占用的,不可以访问
int* p = NULL;
// *p = 100; // 产生异常:nullptr
//cout << *p << endl; // 对*p的操作都会引发空指针异常
int* p = (int*)0x1100; // 让p随便指向一个非法内存空间
//cout << *p << endl; // 产生异常:读取访问权限冲突
7.5 const修饰指针
1) 修饰指针:常量指针
- const int * p = &a;
- 指针指向可以修改,指针指向的值不可以改
int a = 10;
int b = 10;
// 常量指针
const int* p = &a;
p = &b; // 正确:指针指向可以改
*p = 20; // 错误:指针指向的值不可以改
a = 20;
cout << *p << endl; // 20
cout << a << endl; // 20
2) 修饰常量:指针常量
- int * const p = &a;
- 指针指向不可以修改,指针指向的值可以修改
// 指针常量
int* const p = &a;
*p = 20; // 正确,指向的值可以改
p = &b; // 错误,指针指向不可以修改
3) 既修饰指针,又修饰常量
const int* const p = &a;
*p = 20; // 错误
p = &b; // 错误
7.6 指针和数组
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
cout << "第一个元素为:" << arr[0] << endl;
int* p = arr; // arr就是数组的首地址
cout << "利用指针访问第1个元素:" << *p << endl;
p++; // 让指针向后偏移四个字节
cout << "利用指针访问第2个元素:" << *p << endl;
// 利用指针遍历数组
int* p2 = arr;
for (int i = 0;i < 10; i++) {
cout << *p2 << endl;
p2++;
}
7.7 指针和函数
// 值传递
void swap01(int a, int b) {
int temp = a;
a = b;
b = temp;
}
// 地址传递
void swap02(int* p1, int* p2) {
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
int main() {
int a = 10;
int b = 20;
swap01(a, b); // 值传递:形参a, b值交换,实参并未发生改变
cout << "a = " << a << ", b = " << b << endl;
swap02(&a, &b);
cout << "a = " << a << ", b = " << b << endl; // 地址传递会改变实参
}
7.8 指针、数组、函数
#include<iostream>
using namespace std;
void bubbleSort(int* arr, int len) {
for (int i = 0; i < len - 1; i++) {
for (int j = 0; j < len - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = temp;
}
}
}
}
void printArray(int* arr, int len) {
for (int i = 0; i < len; i++) {
cout << arr[i] << endl;
}
}
int main() {
int arr[] = { 3,6,4,5,1 };
int len = sizeof(arr) / sizeof(arr[0]);
bubbleSort(arr, len);
printArray(arr, len);
}
八、结构体
8.1 结构体的基本概念
- 结构体属于用户自定义的数据类型,允许用户存储不同的数据类型
8.2 结构体的定义和使用
- struct 结构体名 {结构体成员列表};
- 变量创建方式
- struct 结构体名 变量名
- struct 结构体名 变量名 = {成员1值, 成员2值 ...}
- 定义结构体是顺便创建变量
#include<iostream>
using namespace std;
#include<string>
// 1. 创建学生数据类型 (自定义数据类型)
struct Student {
// 成员列表
string name;
int age;
double score;
}s3;
// 2. 通过学生类型创建具体学生
int main() {
// 结构体对象变量创建时,struct关键字可以省略,结构体定义时不可省略
// 2.1 struct Student s1
struct Student s1;
s1.name = "Alice";
s1.age = 18;
s1.score = 100;
cout << "name = " << s1.name << ", age = " << s1.age << ", score = " << s1.score << endl;
// 2.2 struct Student s2 = {...}
struct Student s2 = { "Bob", 17, 97 };
cout << "name = " << s2.name << ", age = " << s2.age << ", score = " << s2.score << endl;
// 2.3 定义结构体时顺便创建结构体变量
s3.name = "Cindy";
s3.age = 20;
s3.score = 60;
cout << "name = " << s3.name << ", age = " << s3.age << ", score = " << s3.score << endl;
}
8.3 结构体数组
- 将自定义的结构体放到数组中方便维护
- struct 结构体名 数组名[元素个数] = {{}, {}, ...};
// 1. 定义结构体
struct Student {
string name;
int age;
double score;
};
int main() {
// 初始化结构体数组
struct Student stuArray[3] = {
{"Alice", 18,100},
{ "Bob", 17, 97 },
{ "Cindy", 20, 60 }
};
// 修改数组值
stuArray[2].score = 99;
// 结构体数组遍历输出
for (int i = 0; i < 3; i++) {
cout << "name = " << stuArray[i].name
<< ", age = " << stuArray[i].age
<< ", score = " << stuArray[i].score << endl;
}
}
8.4 结构体指针
// 创建学生结构体变量
struct Student s = { "Alice", 18,100 };
// 通过指针指向结构体变量
Student* p = &s;
// 通过指针访问结构体变量中的数据
cout << "name = " << p->name
<< ", age = " << p->age
<< ", score = " << p->score << endl;
8.5 结构体嵌套结构体
struct Student {
string name;
int age;
double score;
};
struct Teacher {
int id;
string name;
int age;
struct Student stu;
};
int main() {
Teacher t;
t.id = 1001;
t.name = "Potter";
t.age = 30;
t.stu.name = "Ron";
t.stu.score = 60;
cout << "Teacher's name: " << t.name << ", Teacher's student's name: " << t.stu.name << endl;
}
8.6 结构体做函数参数
// 值传递
void printStu1(struct Student s) {
s.age = 100; // 值传递不会修改主函数中实参值
cout << "printStu1_Name: " << s.name
<< ", age: " << s.age
<< ", score: " << s.score << endl;
}
// 地址传递
void printStu2(struct Student* p) {
p->age = 200; // 地址传递会修改主函数中实参值
cout << "printStu2_Name: " << p->name
<< ", age: " << p->age
<< ", score: " << p->score << endl;
}
int main() {
struct Student s;
s.name = "Alice";
s.age = 18;
s.score = 100;
cout << "main(): name = " << s.name << ", age = " << s.age << ", score = " << s.score << endl;
printStu1(s);
printStu2(&s);
}
8.7 结构体中const使用场景
- const防止误操作
- 将函数形参改为指针可以减少内存空间,而且不会复制出新副本
void printStu(const Student* p) {
//p->age = 200; // 不允许进行写操作
cout << "printStu2_Name: " << p->name
<< ", age: " << p->age
<< ", score: " << p->score << endl;
}
int main() {
struct Student s = { "Alice",18,100 };
printStu(&s);
}
8.8 练习案例
#include<iostream>
using namespace std;
#include<string>
#include<ctime>
struct Student {
string sName;
int score;
};
struct Teacher {
string tName;
struct Student stuArray[5];
};
void allocateSpace(struct Teacher tArray[], int len) {
string nameSeed = "ABCDE";
// 循环为每名老师赋值
for (int i = 0; i < len; i++) {
tArray[i].tName = "Teacher_";
tArray[i].tName += nameSeed[i];
// 循环为每名学生赋值
for (int j = 0; j < 5; j++) {
tArray[i].stuArray[j].sName = "Student_";
tArray[i].stuArray[j].sName += nameSeed[j];
// 随机数生成学生分数
int random = rand() % 61 + 40;
tArray[i].stuArray[j].score = random;
}
}
}
void printInfo(struct Teacher tArray[], int len) {
for (int i = 0; i < len; i++) {
cout << "教师姓名:" << tArray[i].tName << endl;
for (int j = 0; j < 5; j++) {
cout << "\t学生姓名:" << tArray[i].stuArray[j].sName
<< ",考试分数:" << tArray[i].stuArray[j].score << endl;
}
}
}
void main() {
// 随机数种子
srand((unsigned int)time(NULL));
struct Teacher tArray[3];
int len = sizeof(tArray) / sizeof(tArray[0]);
allocateSpace(tArray, len);
printInfo(tArray, len);
}
#include <iostream>
using namespace std;
#include <string>
struct Hero {
string name;
int age;
string gender;
};
void ageSort(struct Hero hero[], int len) {
for (int i = 0; i < len - 1; i++) {
for (int j = 0; j < len - i - 1;j++) {
if (hero[j].age > hero[j + 1].age) {
Hero tempHero = hero[j];
hero[j] = hero[j + 1];
hero[j + 1] = tempHero;
}
}
}
}
void printList(Hero hero[], int len) {
for (int i = 0; i < len; i++) {
cout << "HeroName: " << hero[i].name
<< ", HeroAge: " << hero[i].age
<< ", HeroGender: " << hero[i].gender << endl;
}
}
int main() {
struct Hero heroList[5] = {
{"LiuBei", 23, "M"},
{"GuanYu", 22, "F"},
{"ZhangFei",20,"M"},
{"XiaoQiao",21,"F"},
{"DiaoChan",19,"F"}
};
int len = sizeof(heroList) / sizeof(heroList[1]);
ageSort(heroList, len);
printList(heroList, len);
system("pause");
return 0;
}