第五章 数组array
5.1 概述
所谓数组,就是一个集合,里面存放了相同类型的数据元素
特点1:数组中每个元素都是相同的数据类型
特点2:数组是由连续的内存位置组成的
5.2 一维数组
5.2.1 一维数组定义方式
一维数组定义的三种方式:
1.数据类型 数组名[数组长度];
2.数据类型 数组名[数组长度] = {值1,值2,...};
3.数据类型 数组名[] = {值1,值2,...};
总结1:数组名的命名规范与变量名命名规范一致,不要和变量重名
总结2:数组中下标是从0开始索引
例1:第一种方式
#include <iostream> using namespace std; int main() { int arr[5]; arr[0] = 0; arr[1] = 1; arr[2] = 2; arr[3] = 3; arr[4] = 4; // 访问数组中元素 cout << arr[0] << endl; cout << arr[1] << endl; cout << arr[2] << endl; cout << arr[3] << endl; cout << arr[4] << endl; system("pause"); return 0; }
0 1 2 3 4 请按任意键继续. . .
例2:第二种方式
#include <iostream> using namespace std; int main() { int arr[5] = { 0,1,2,3,4 }; // 访问数组中元素 cout << arr[0] << endl; cout << arr[1] << endl; cout << arr[2] << endl; cout << arr[3] << endl; cout << arr[4] << endl; system("pause"); return 0; }
输出结果一样
注意:如果初始化数据的时候,没有全部填写完,会用0来填补剩余的数据
int arr[5] = { 0,1 };
例3:第三种方式
#include <iostream> using namespace std; int main() { int arr[] = { 0,1,2,3,4,5,6 }; for (int i = 0; i < 7; i++) { // 访问数组中元素 cout << arr[i] << endl; } system("pause"); return 0; }
0 1 2 3 4 5 6 请按任意键继续. . .
5.2.2 一维数组数组名
一维数组名称的用途
- 可以统计整个数组在内存中的长度
- 可以获取数组在内存中的首地址
#include <iostream> using namespace std; int main() { int arr[] = { 0,1,2,3,4,5,6 }; cout << "整个数组占用的内存空间:"<<sizeof(arr) << endl; cout << "每个元素占用的内存空间:" << sizeof(arr[0]) << endl; cout << "元素个数:" << sizeof(arr) / sizeof(arr[0]) << endl; // 统计元素个数 cout << "数组首地址:" << (int)arr << endl; //(int)强制转化为十进制 cout << "数组中第一个元素地址:" << (int)&arr[0] << endl; cout << "数组中第二个元素地址:" << (int)&arr[1] << endl; system("pause"); return 0; }
整个数组占用的内存空间:28 每个元素占用的内存空间:4 元素个数:7 数组首地址:-1155598808 数组中第一个元素地址:-1155598808 数组中第二个元素地址:-1155598804 请按任意键继续. . .
注意:数组名是常量,不可以进行赋值操作
错误示例:
arr = 100
注意:数组名是常量,不可以赋值
总结1:直接打印数组名,可以查看数组所占内存的首地址
总结2:对数组名进行sizeof,可以获取整个数组占内存空间的大小
练习案例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 max = 0; for (int i = 0; i < 5; i++) { if (arr[i] > max) { max = arr[i]; } } cout << "max=" << max << endl; system("pause"); return 0; }
max=400 请按任意键继续. . .
练习案例2:数组元素逆置
案例描述:请申明一个5个元素的数组,并且将元素逆置
(如原数组元素为:1,3,2,5,4;逆置结果为:4,5,2,3,1)
#include <iostream> using namespace std; int main() { int arr[5] = { 1, 3, 2, 5, 4 }; cout << "逆置前:" << endl; for (int i = 0; i < 5; i++) { cout << arr[i]; } cout << endl; for (int i = 0; i < 5; i++) { 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--; } } cout << "逆置后:" << endl; for (int i = 0; i < 5; i++) { cout << arr[i]; } cout << endl; system("pause"); return 0; }
逆置前: 13254 逆置后: 45231 请按任意键继续. . .
例2
#include <iostream> using namespace std; int main() { int arr[5] = { 1, 3, 2, 5, 4 }; int arr1[5]; int j = 0; for (int i = 0; i < 5; i++) { cout << arr[i]; j = 4 - i; arr1[j] = arr[i]; } cout << endl; for (int j = 0; j < 5; j++) { cout << arr1[j]; } cout << endl; system("pause"); return 0; }
能实现一样的倒置功能
5.2.3 冒泡排序
作用:最常用的排序算法,对数组内元素进行排序
- 比较相邻的元素。如果第一个比第二个打,就交换他们两个。
- 对每一对相邻元素做相同的工作,执行完毕后,找到第一个最大值。
- 重复以上的步骤,每次比较次数-1,知道不需要比较
排序总轮数 = 元素个数 - 1
每轮对比次数 = 元素个数 - 排序轮数 - 1
从第0轮开始
大的数字在最后面冒出来
#include <iostream> using namespace std; int main() { int arr[9] = { 4,2,8,0,5,7,1,3,9 }; cout << "排序前:" << endl; for (int i = 0; i < 9; i++) { cout << arr[i] << " "; } cout << endl; //开始冒泡排序 //总共排序轮数为 元素个数 - 1 for (int i = 0; i < 9 - 1; i++) { //内层循环对比 次数 = 元素个数 - 当前轮数 - 1 for (int j = 0; j < 9 - i - 1; j++) { //如果第一个数字,比第二个数字大,交换两个数字 if (arr[j] > arr[j + 1]) { int temp = arr[j]; //这三行代码实现这两数的交换 arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } //排序后结果 cout << "排序后:" << endl; for (int i = 0; i < 9; i++) { cout << arr[i] << " "; } cout << endl; system("pause"); return 0; }
排序前: 4 2 8 0 5 7 1 3 9 排序后: 0 1 2 3 4 5 7 8 9 请按任意键继续. . .
5.3 二维数组
二维数组就是在一维数组上,多加了一个维度
5.3.1 二维数组的定义方式
二维数组的四种定义方式:
1.数据类型 数组名 [行数] [列数];
2.数据类型 数组名 [行数] [列数] = { {数据1,数据2},{数据3,数据4}};
3.数据类型 数组名 [行数] [列数] = { 数据1,数据2,数据3,数据4};
4.数据类型 数组名 [] [列数] = { 数据1,数据2,数据3,数据4};
例1:第一种定义
#include <iostream> using namespace std; int main() { int arr[2][2]; arr[0][0] = 0; arr[0][1] = 1; arr[1][0] = 2; arr[1][1] = 3; cout << arr[0][0] << endl; cout << arr[0][1] << endl; cout << arr[1][0] << endl; cout << arr[1][1] << endl; system("pause"); return 0; }
0 1 2 3 请按任意键继续. . .
例2:第二种定义
#include <iostream> using namespace std; int main() { int arr[2][2] = { {1,2},{3,4} }; cout << arr[0][0] << endl; cout << arr[0][1] << endl; cout << arr[1][0] << endl; cout << arr[1][1] << endl; system("pause"); return 0; }
例3:for嵌套输出二维数组
#include <iostream> using namespace std; int main() { int arr[2][3] = { {1,2,3},{4,5,6} }; //外层循环打印行数 //内层循环打印列数 for (int i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { cout << arr[i][j] << " "; } cout << endl; } system("pause"); return 0; }
1 2 3 4 5 6 请按任意键继续. . .
5.3.2 二维数组的数组组名
- 查看二维数组所占用内存空间
- 获取二维数组首地址
例1:
#include <iostream> using namespace std; int main() { int arr[2][3] = { {1,2,3},{4,5,6} }; cout << "int类型二维数组占用的内存空间大小:" << sizeof(arr) << endl; double arr1[2][3] = { {1,2,3},{4,5,6} }; cout << "double类型二维数组占用的内存空间大小:" << sizeof(arr1) << endl; system("pause"); return 0; }
int类型二维数组占用的内存空间大小:24 double类型二维数组占用的内存空间大小:48 请按任意键继续. . .
例2
#include <iostream> using namespace std; int main() { int arr[2][3] = { {1,2,3},{4,5,6} }; cout << "二维数组占用的内存空间大小:" << sizeof(arr) << endl; cout << "二维数组第一行占用的内存空间大小:" << sizeof(arr[0]) << endl; cout << "二维数组第一个数据占用的内存空间大小:" << sizeof(arr[0][0]) << endl; cout << "二维数组多少个数据:" << sizeof(arr) / sizeof(arr[0][0]) << endl; cout << "二维数组行数:" << sizeof(arr) / sizeof(arr[0]) << endl; cout << "二维数组列数:" << sizeof(arr[0]) / sizeof(arr[0][0]) << endl; cout << "十六进制二维数组首地址" << arr << endl; cout << "十进制二维数组首地址" << (int)arr << endl; cout << "二维数组第一行首地址" << (int)arr[0] << endl; cout << "二维数组第二行首地址" << (int)arr[1] << endl; //相差12,隔着三个数据 cout << "二维数组第一个元素首地址" << (int)&arr[0][0] << endl; cout << "二维数组第二个元素首地址" << (int)&arr[0][1] << endl; system("pause"); return 0; }
二维数组占用的内存空间大小:24 二维数组第一行占用的内存空间大小:12 二维数组第一个数据占用的内存空间大小:4 二维数组多少个数据:6 二维数组行数:2 二维数组列数:3 十六进制二维数组首地址000000367812F768 十进制二维数组首地址2014508904 二维数组第一行首地址2014508904 二维数组第二行首地址2014508916 二维数组第一个元素首地址2014508904 二维数组第二个元素首地址2014508908 请按任意键继续. . .
总结1:二维数组名就是这个数组的首地址
总结2:对二维数组名进行sizeof时,可以获取整个二维数组占用的内存空间大小
5.3.3 二维数组应用案例
考试成绩统计:
案例描述:有三名同学(张三,李四,王五),在一次考试中的成绩分别如下表,请分别输出三名同学的总成绩
#include <iostream> using namespace std; int main() { int scores[3][3] = { {100,100,100}, {90,50,100}, {60,70,80} }; string names[3] = { "张三", "李四", "王五" }; for (int i = 0; i < 3; i++) { int num = 0; for (int j = 0; j < 3; j++) { num += scores[i][j]; } cout << names[i] << "的总分为:" << num << endl; } system("pause"); return 0; }
张三的总分为:300 李四的总分为:240 王五的总分为:210 请按任意键继续. . .
第六章 函数
6.1 概述
作用:将一段经常使用的代码封装起来,减少重复代码
一个较大的程序,一般分为若干个程序块,每个程序实现特定的功能。
6.2 函数的定义
函数的定义一般主要有5个步骤:
1、返回值类型
2、函数名
3、参数列表
4、函数体语句
5、return表达式
语法:
返回值类型 函数名 (参数列表) { 函数体语句 return表达式 }
- 返回值类型 :一个函数可以返回一个值。在函数定义中
- 函数名:给函数起个名称
- 参数列表:使用该函数时,传入的数据
- 函数体语句:花括号内的代码,函数内需要执行的语句
- return表达式: 和返回值类型挂钩,函数执行完后,返回相应的数据
例1:定义加法函数
int add(int num1, int num2) { int sum = num1 + num2; return sum; }
6.3 函数的调用
功能:使用定义好的函数
语法:函数名 (参数)
例1:调用add函数
#include <iostream> using namespace std; int add(int num1, int num2) //形参 { int sum = num1 + num2; return sum; } int main() { //main函数中调用add函数 int c = add(10, 20); //实参 cout << c << endl; system("pause"); return 0; }
30 请按任意键继续. . .
6.4值传递
- 所谓值传递,就是函数调用时实参将数值传递给了形参
- 值传递时,如果形参发生改变,并不会影响实参
例1:实现两个值交换的函数
#include <iostream> using namespace std; //值传递 //定义函数,实现两个数字进行交换函数 //如果函数不需要返回值,声明可以写void类型 void swap(int num1, int num2) { cout << "交换前:num1=" << num1 << ", num2=" << num2 << endl; int temp = num1; num1 = num2; num2 = temp; cout << "交换后:num1=" << num1 << ", num2=" << num2 << endl; return; } int main() { int a = 10; int b = 20; cout << "交换前:a=" << a << ", b=" << b << endl; swap(a, b); cout << "交换后:a=" << a << ", b=" << b << endl; system("pause"); return 0; }
交换前:a=10, b=20 交换前:num1=10, num2=20 交换后:num1=20, num2=10 交换后:a=10, b=20 请按任意键继续. . .
6.5 函数的常见样式
常见的函数样式有4种:
1.无参无返
2.有参无返
3.无参有返
4.有参有返
例1:第一种,无参无返
#include <iostream> using namespace std; void test01() { cout << "Hello world!" << endl; } int main() { test01(); system("pause"); return 0; }
Hello world! 请按任意键继续. . .
例2:第二种,有参无返
#include <iostream> using namespace std; void test02(int a) { cout << "a=" << a << endl; } int main() { int a; cout << "请输入a:" << endl; cin >> a; test02(a); system("pause"); return 0; }
请输入a: 5 a=5 请按任意键继续. . .
例三:第三种,无参有返
#include <iostream> using namespace std; int test03() { cout << "This is test03." << endl; return 1000; } int main() { int num1 = test03(); cout << "num1=" << num1 << endl; system("pause"); return 0; }
This is test03. num1=1000 请按任意键继续. . .
例四:第四种,有参有返
#include <iostream> using namespace std; int test04(int a) { cout << "This is test04." << endl; return a; } int main() { int num2 = test04(1000); cout << "num2=" << num2 << endl; system("pause"); return 0; }
This is test04. num2=1000 请按任意键继续. . .
6.6 函数的声明
作用:告诉编码器函数名称及如何调用函数。函数的实际主体可以单独定义
- 函数的声明可以多次,但是函数的定义只能有一次
#include <iostream> using namespace std; int max(int a, int b); //函数声明 ,定义的函数就可以写在主函数后面了 int main() { cout << max(10, 20) << endl; system("pause"); return 0; } //函数的声明 //比较函数,实现两个整型数字的比较,返回较大的值 int max(int a, int b) { return a > b ? a : b; }
20 请按任意键继续. . .
6.7 函数的分文件编写
作用:让代码结构更加清晰
函数份文件编写一般有4个步骤
- 创建后缀名.h的头文件
- 创建后缀名cpp的源文件
- 在头文件中写函数的声明
- 在源文件中写函数的定义
例1:实现两个数的交换,这例使用分文件编写
1、 swap.h头文件
#include <iostream> using namespace std; //函数声明 void swap(int num1, int num2);
2、swap.cpp源文件
#include "swap.h" void swap(int num1, int num2) { cout << "交换前:num1=" << num1 << ", num2=" << num2 << endl; int temp = num1; num1 = num2; num2 = temp; cout << "交换后:num1=" << num1 << ", num2=" << num2 << endl; return; }
3、first_temp.cpp源文件(主文件)
#include <iostream> using namespace std; #include "swap.h" int main() { swap(10, 20); system("pause"); return 0; }
第七章 指针
7.1 指针的基本概念
指针的作用:可以通过指针间接访问内存
- 内存编码是从0开始记录的,一般用十六进制数字表示
- 可以利用指针变量保存地址
7.2 指针变量的定义和使用
指针变量定义语法:数据类型 * 变量名
#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、使用指针 //可以通过解引用的方式来找到指针指向的内存 //指针前加 * 代表解引用,找到指针指向的内存数据 *p = 1000; cout << "a=" << a << endl; cout << "*p=" << *p << endl; //不改变地址,只改变了地址存的数据 cout << "a的地址为:" << &a << endl; cout << "指针p为:" << p << endl; system("pause"); return 0; }
a的地址为:0000006FE5EFF9F4 指针p为:0000006FE5EFF9F4 a=1000 *p=1000 a的地址为:0000006FE5EFF9F4 指针p为:0000006FE5EFF9F4 请按任意键继续. . .
总结1: 我们可以通过 & 符号 获取变量的地址
总结2:利用指针可以记录地址
总结3:对指针变量解引用,可以操作指针指向的内存
7.3 指针所占内存空间
提问:指针也是种数据类型,那么这种数据类型占用多少内存空间?
- 在32位操作系统下占用4个字节空间
- 在64位操作系统下占用8个字节空间
#include <iostream> using namespace std; int main() { int a = 10; //int* p; //p = &a; int* p = &a; cout << "sizeof(p) =" << sizeof(p) << endl; cout << "sizeof (int*) =" << sizeof (int*) << endl; cout << "sizeof (double*) =" << sizeof(double*) << endl; cout << "sizeof (char*) =" << sizeof(char*) << endl; system("pause"); return 0; }
sizeof(p) =8 sizeof (int*) =8 sizeof (double*) =8 sizeof (char*) =8 请按任意键继续. . .
7.4 空指针和野指针
空指针
空指针:指针变量指向内存中编号为0的空间
用途:初始化指针变量
注意:空指针指向的内存是不可以访问的
#include <iostream> using namespace std; int main() { //空指针 //1、空指针用于给指针变量进行初始化 int* p = NULL; //2、空指针是不可以进行访问的 //0~255之间的内存编号是系统占用的,因此不可以访问 //*p = 100; //错误 system("pause"); return 0; }
野指针
以下代码会报错
#include <iostream> using namespace std; int main() { //野指针 //在程序中,尽量避免出现野指针 int* p = (int*)0x1100; cout << *p << endl; system("pause"); return 0; }
注意:空指针和野指针都不是我们申请的空间,因此不要访问。
7.5 const修饰指针
const修饰指针有三种情况:
- const修饰指针 —常量指针
- const修饰常量 —指针常量
- const即修饰指针,又修饰常量
第一种:常量指针,相当于int* p是常数
const int* p = &a
特点:指针的指向可以修改,但是指针指向的值不可以修改
*p = 20; //错误 p = &b; //正确
例1:
#include <iostream> using namespace std; int main() { int a = 10; int b = 100; const int* p = &a; cout << "p指向a的地址时:" << endl; cout << "p:" << p << endl; cout << "*p:" << *p << endl; //*p = 20; //错误 p = &b; //正确 cout << "p指向b的地址时:" << endl; cout << "p:" << p << endl; cout << "*p:" << *p << "\n" << endl; cout << "a:" << a << endl; cout << "a的地址:" << &a << endl; cout << "b:" << b << endl; cout << "b的地址:" << &b << endl; system("pause"); return 0; }
p指向a的地址时: p:007AFE44 *p:10 p指向b的地址时: p:007AFE38 *p:100 a:10 a的地址:007AFE44 b:100 b的地址:007AFE38 请按任意键继续. . .
第二种:指针常量,相当于p(地址)是常数
int* const p = &a
特点:指针的指向不可以改,指针指向的值可以改
*p = 20; //正确 p = &b; //错误
例2:
#include <iostream> using namespace std; int main() { int a = 10; int b = 10; int* const p = &a; *p = 20; //正确 //p = &b; //错误 system("pause"); return 0; }
第三种:即修饰指针又修饰常量
const int* const p = &a;
特点:指针的指向和指针指向的值都不可以修改
*p = 20; //错误 p = &b; //错误
7.6 指针和数组
作用:利用指针访问数组中元素
例:利用指针遍历数组
#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; //arr就是数组的首地址 cout << "利用指针来访问第一个元素:" << *p << endl; p++; //向后偏移四个字节 cout << "利用指针来访问第二个元素:" << *p << endl; cout << "利用指针遍历数组:" << endl; int* p2 = arr; for (int i = 0; i < 10; i++) { cout << *p2 << " "; p2++; } cout << endl; system("pause"); return 0; }
第一个元素为:1 利用指针来访问第一个元素:1 利用指针来访问第二个元素:2 利用指针遍历数组: 1 2 3 4 5 6 7 8 9 10 请按任意键继续. . .
7.7 指针和函数
作用:利用指针作函数参数,可以修改实参的值
p是存地址
*p是存数值
#include <iostream> using namespace std; void swap02(int* p1, int* p2) //两个形参为地址 { int temp = *p1; //里面交换地址存储的值 *p1 = *p2; *p2 = temp; } int main() { int a = 10; int b = 20; cout << "传递前:" << endl; cout << "a=" << a << endl; cout << "b=" << b << endl; //地址传递 swap02(&a, &b); cout << "传递后:" << endl; cout << "a=" << a << endl; cout << "b=" << b << endl; system("pause"); return 0; }
传递前: a=10 b=20 传递后: a=20 b=10 请按任意键继续. . .
7.8 指针、数组、函数
案例描述:封装一个函数,利用冒泡法排序,实现对整型数组的升序排序
例如数组:int arr[10] = {4,3,6,9,1,2,10,8,7,5};
#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++) { //如果j>j+1的值,交换数字 if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } } //打印数组 void printArray(int* arr, int len) { for (int i = 0; i < len; i++) { cout << arr[i] << " "; } cout << endl; } int main() { //1、创建一个数组 int arr[10] = { 4,3,6,9,1,2,10,8,7,5 }; int len = sizeof(arr) / sizeof(arr[0]); //2、创建函数,实现冒泡排序 bubbleSort(arr, len); //3、打印排序后的数组 printArray(arr, len); system("pause"); return 0; }
1 2 3 4 5 6 7 8 9 10 请按任意键继续. . .
第八章 结构体
8.1 结构体基本概念
结构体属于用户自定义的数据类型,允许用户存储不同的数据类型
8.2 结构体定义和使用
语法:
struct 结构体名 { 结构体成员列表 }
通过结构体创建变量的方式有三种:
struct 结构体名 变量名
struct 结构体名 变量名 = {成员1值, 成员2值...}
定义结构体时顺便创建变量
#include <iostream> using namespace std; #include <string> //1、创建学生数据类型:学生包括(姓名,年龄,分数) //自定义数据类型,一些类型集合组成的一个类型 //语法:struct 类型名称 {成员列表} struct Student { //成员列表 //姓名 string name; //年龄 int age; //考试分数 int score; }s3; //顺便创建结构体变量 int main() { //2、通过学生类型创建具体学生 // 2.1 struct Student s1; //struct关键字可以省略 //Student s1; struct Student s1; //给s1属性赋值,通过.访问结构体变量中的属性 s1.name = "张三"; s1.age = 18; s1.score = 100; cout << "姓名:" << s1.name << ", 年龄:" << s1.age << ", 分数:" << s1.score << endl; // 2.2 struct Student s2 = {...} struct Student s2 = { "李四", 19, 80 }; cout << "姓名:" << s2.name << ", 年龄:" << s2.age << ", 分数:" << s2.score << endl; // 2.3 在定义结构体时顺便创建结构体的变量 s3.name = "王五"; s3.age = 20; s3.score = 60; cout << "姓名:" << s3.name << ", 年龄:" << s3.age << ", 分数:" << s3.score << endl; system("pause"); return 0; }
姓名:张三, 年龄:18, 分数:100 姓名:李四, 年龄:19, 分数:80 姓名:王五, 年龄:20, 分数:60 请按任意键继续. . .
- 总结1:定义结构体时的关键字是struct,不可省略
- 总结2:创建结构体变量时,关键字struct可以省略
- 总结3:结构体变量利用操作符 ‘’.‘’ 访问成员
8.3 结构体数组
作用:将自定义的结构体放入到数组中方便维护
语法:struct 结构体 数组名[元素个数] = { {}, {}, {} }
#include <iostream> using namespace std; #include <string> //结构体数组 //1、定义结构体 struct Student { //姓名 string name; //年龄 int age; //分数 int score; }; int main() { //2、创建结构体数组 struct Student stuArray[3] = { {"张三", 18, 100}, {"李四", 28, 99}, {"王五",38, 66} }; //3、给结构体数组中的元素赋值 stuArray[2].name = "赵六"; //4、遍历结构体数组 for (int i = 0; i < 3; i++) { cout << "姓名:" << stuArray[i].name << ", 年龄:" << stuArray[i].age << ", 分数:" << stuArray[i].score << endl; } system("pause"); return 0; }
姓名:张三, 年龄:18, 分数:100 姓名:李四, 年龄:28, 分数:99 姓名:赵六, 年龄:38, 分数:66 请按任意键继续. . .
8.4 结构体指针
作用:通过指针访问结构体中的成员
- 利用操作符
->
可以通过结构体指针访问结构体属性
#include <iostream> using namespace std; #include <string> struct Student { string name; //姓名 int age; //年龄 int score; //分数 }; int main() { //1、创建学生结构体变量 Student s = { "张三", 18, 100 }; //2、通过指针指向结构体变量 Student* p = &s; cout << "姓名:" << p->name << ", 年龄:" << p->age << ", 分数:" << p->score << endl; system("pause"); return 0; }
姓名:张三, 年龄:18, 分数:100 请按任意键继续. . .
8.5 结构体嵌套结构体
作用:结构体中的成员可以是另一个个结构体
例如:每个老师辅导一个学员,一个老师的结构体中,记录一个学生的结构体
#include <iostream> using namespace std; #include <string> //学生结构体定义 struct student { //成员列表 string name; //姓名 int age; //年龄 int score; //分数 }; //教师结构体定义 struct teacher { //成员列表 int id; //职工编号 string name; //教师姓名 int age; //教师年龄 struct student stu; //子结构体 学生 }; int main() { struct teacher t1; t1.id = 10000; t1.name = "老王"; t1.age = 40; t1.stu.name = "张三"; t1.stu.age = 18; t1.stu.score = 100; cout << "教师 职工编号: " << t1.id << " 姓名: " << t1.name << " 年龄: " << t1.age << endl; cout << "辅导学员 姓名: " << t1.stu.name << " 年龄:" << t1.stu.age << " 考试分数: " << t1.stu.score << endl; system("pause"); return 0; }
教师 职工编号: 10000 姓名: 老王 年龄: 40 辅导学员 姓名: 张三 年龄:18 考试分数: 100 请按任意键继续. . .
8.6 结构体做函数参数
作用:将结构体作为参数向函数中传递
传递方式有两种:
- 值传递
- 地址传递
#include <iostream> using namespace std; #include <string> struct student { string name; //姓名 int age; //年龄 int score; //分数 }; //值传递 void printStudent(student stu) { stu.age = 28; cout << "子函数中 姓名:" << stu.name << " 年龄: " << stu.age << " 分数:" << stu.score << endl; } //地址传递 void printStudent2(student* stu) { stu->age = 28; cout << "子函数中 姓名:" << stu->name << " 年龄: " << stu->age << " 分数:" << stu->score << endl; } int main() { student stu = { "张三",18,100 }; //值传递 printStudent(stu); cout << "主函数中 姓名:" << stu.name << " 年龄: " << stu.age << " 分数:" << stu.score << endl; cout << endl; //地址传递 printStudent2(&stu); cout << "主函数中 姓名:" << stu.name << " 年龄: " << stu.age << " 分数:" << stu.score << endl; system("pause"); return 0; }
子函数中 姓名:张三 年龄: 28 分数:100 主函数中 姓名:张三 年龄: 18 分数:100 子函数中 姓名:张三 年龄: 28 分数:100 主函数中 姓名:张三 年龄: 28 分数:100 请按任意键继续. . .
总结:如果不想修改主函数中的数据,用值传递,反之用地址传递
8.7 结构体中const使用场景
作用:用const来防止误操作
#include <iostream> using namespace std; #include <string> struct student { string name; //姓名 int age; //年龄 int score; //分数 }; //const使用场景 void printStudent(const student* stu) //加const防止函数体中的误操作 { //stu->age = 100; //不能修改,因为加了const cout << "姓名:" << stu->name << " 年龄:" << stu->age << " 分数:" << stu->score << endl; } int main() { student stu = { "张三",18,100 }; printStudent(&stu); system("pause"); return 0; }
姓名:张三 年龄:18 分数:100 请按任意键继续. . .
8.8 结构体案例
8.8.1 案例1
案例描述:
学校正在做毕设项目,每名老师带领5个学生,总共有3名老师,需求如下:
1、设计学生和老师的结构体,其中在老师的结构体中,有老师姓名和一个存放5名学生的数组作为成员
2、学生的成员有姓名、考试分数,创建数组存放3名老师,通过函数给每个老师及所带的学生赋值
3、最终打印出老师数据以及老师所带的学生数据。
#include <iostream> using namespace std; #include <string> #include <ctime> struct Student { string name; //学生姓名 int score; //分数 }; struct Teacher { string name; //老师姓名 Student sArray[5]; //创建5名学生数组 }; //给老师和学生赋值的函数 void allocateSpace(Teacher tArray[], int len) { string tName = "教师"; string sName = "学生"; string nameSeed = "ABCDE"; //给老师赋值 for (int i = 0; i < len; i++) { tArray[i].name = tName + nameSeed[i]; //老师A,老师B,老师C //给老师带的学生赋值 for (int j = 0; j < 5; j++) { tArray[i].sArray[j].name = sName + nameSeed[j]; //学生A,学生B,学生C.... tArray[i].sArray[j].score = rand() % 61 + 40; //成绩随机生成,40~100 } } } //打印输出信息 void printTeachers(Teacher tArray[], int len) { for (int i = 0; i < len; i++) //遍历老师 { cout << tArray[i].name << endl; //输出老师姓名 for (int j = 0; j < 5; j++) //遍历老师带的学生 { cout << "\t姓名:" << tArray[i].sArray[j].name << " 分数:" << tArray[i].sArray[j].score << endl; } } } int main() { srand((unsigned int)time(NULL)); //随机数种子 分数随机需要这个 Teacher tArray[3]; //创建3名老师数组 int len = sizeof(tArray) / sizeof(tArray[0]); allocateSpace(tArray, len); //创建数据 printTeachers(tArray, len); //打印数据 system("pause"); return 0; }
教师A 姓名:学生A 分数:70 姓名:学生B 分数:87 姓名:学生C 分数:86 姓名:学生D 分数:66 姓名:学生E 分数:48 教师B 姓名:学生A 分数:87 姓名:学生B 分数:51 姓名:学生C 分数:50 姓名:学生D 分数:75 姓名:学生E 分数:74 教师C 姓名:学生A 分数:46 姓名:学生B 分数:61 姓名:学生C 分数:50 姓名:学生D 分数:44 姓名:学生E 分数:74 请按任意键继续. . .
8.8.2 案例2
案例描述:
1、设计一个英雄的结构体,包括成员姓名,年龄,性别;创建结构体数组,数组中存放5名英雄。
2、通过冒泡排序的算法,将数组中的英雄按照年龄进行升序排序,最终打印排序后的结果。
五名英雄信息如下:
{"刘备",23,"男"}, {"关羽",22,"男"}, {"张飞",20,"男"}, {"赵云",21,"男"}, {"貂蝉",19,"女"},
例:
#include <iostream> using namespace std; #include <string> #include <ctime> //英雄结构体 struct hero { string name; //姓名 int age; //年龄 string sex; //性别 }; //冒泡排序,升序 void bubbleSort(hero arr[], int len) { for (int i = 0; i < len - 1; i++) { for (int j = 0; j < len - 1 - i; j++) { if (arr[j].age > arr[j + 1].age) { hero temp = arr[j]; //hero相当于一个类型,想当于int arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } } //打印数组 void printHeros(hero arr[], int len) { for (int i = 0; i < len; i++) { cout << "姓名:" << arr[i].name << " 性别:" << arr[i].sex << " 年龄:" << arr[i].age << endl; } } int main() { //创建数组存放5名英雄 struct hero arr[5] = { {"刘备",23,"男"}, {"关羽",22,"男"}, {"张飞",20,"男"}, {"赵云",21,"男"}, {"貂蝉",19,"女"}, }; //int len = sizeof(arr) / sizeof(hero); //获取数组元素个数 int len = sizeof(arr) / sizeof(arr[0]); //获取数组元素个数 bubbleSort(arr, len); //排序 printHeros(arr, len); //打印 system("pause"); return 0; }
姓名:貂蝉 性别:女 年龄:19 姓名:张飞 性别:男 年龄:20 姓名:赵云 性别:男 年龄:21 姓名:关羽 性别:男 年龄:22 姓名:刘备 性别:男 年龄:23 请按任意键继续. . .
8.8.3 案例3:通讯录管理系统
#include <iostream> using namespace std; #include <string> # define MAX 1000 //设计联系人结构体 struct Person { //姓名 string m_Name; //性别 int m_Sex; //年龄 int m_Age; //电话 string m_Phone; //住址 string m_Addr; }; //设计通讯录结构体 struct Addressbooks { //通讯录中保存的联系人数组 struct Person personArray[MAX]; //子结构体,结构体嵌套 //通讯录中当前记录联系人个数 int m_Size; }; //1、添加联系人 void addPerson(Addressbooks* abs) //形参为结构体指针 { //判断通讯录是否已满,如果满了就不再添加 if (abs->m_Size == MAX) { cout << "通讯录已满,无法添加!" << endl; return; } else { //添加具体联系人 //姓名 string name; cout << "请输入姓名:" << endl; cin >> name; abs->personArray[abs->m_Size].m_Name = name; //性别 cout << "请输入性别:" << endl; cout << "1---男" << endl; cout << "2---女" << endl; int sex = 0; while (true) { cin >> sex; if (sex == 1 || sex == 2) { abs->personArray[abs->m_Size].m_Sex = sex; break; } cout << "输入有误,请重新输入:" << endl; } //年龄 cout << "请输入年龄:" << endl; int age = 0; cin >> age; abs->personArray[abs->m_Size].m_Age = age; //电话 cout << "请输入联系电话:" << endl; string phone; cin >> phone; abs->personArray[abs->m_Size].m_Phone = phone; //住址 cout << "请输入家庭地址:" << endl; string address; cin >> address; abs->personArray[abs->m_Size].m_Addr = address; //更新通讯录人数 abs->m_Size++; cout << "添加成功!" << endl; system("pause"); //请按任意键继续 system("cls"); //清屏操作 } } //2、显示所有的联系人 void showPerson(Addressbooks * abs) { //判断通讯录中人数是否为0,如果为0,提示为空;不为零,则显示信息 if (abs->m_Size == 0) { cout << "当前记录为空!" << endl; } else { for (int i = 0; i < abs->m_Size; i++) { cout << "姓名:" << abs->personArray[i].m_Name << "\t"; cout << "性别:" << (abs->personArray[i].m_Sex == 1 ? "男":"女")<<"\t"; cout << "年龄:" << abs->personArray[i].m_Age << "\t"; cout << "电话:" << abs->personArray[i].m_Phone << "\t"; cout << "住址:" << abs->personArray[i].m_Addr << endl; } } system("pause"); //按任意键继续 system("cls"); //清屏 } //3、删除联系人:(1)封装检测联系人是否存在 (2)封装删除联系人函数 (3)检测删除联系人功能 //(1)检测联系人是否存在,存在返回位置 //参数一:通讯录 参数二:对比姓名 int isExist(Addressbooks* abs, string name) { //找到用户输入的姓名了 for (int i = 0; i < abs->m_Size; i++) { if (abs->personArray[i].m_Name == name) { return i; //找到返回数组中下标 } } //没有找到,返回-1 return -1; } //(2)删除指定联系人 void deletePerson(Addressbooks* abs) { cout << "请输入你要删除的联系人:" << endl; string name; cin >> name; //ret==-1 or ret != -1 int ret = isExist(abs, name); if (ret != -1) { //查找到人,进行删除操作 for (int i = ret; i < abs->m_Size; i++) { //数据前移 abs->personArray[i] = abs->personArray[i + 1]; } abs->m_Size--; //更新人员总数 cout << "删除成功!" << endl; } else { cout << "查无此人!" << endl; } system("pause"); system("cls"); } //4、查找联系人信息:(1)封装查找联系人函数 (2)测试查找指定联系人 void findPerson(Addressbooks* abs) { cout << "请输入你要查找的联系人:" << endl; string name; cin >> name; //判断指定的联系人是否在在通讯录中 int ret = isExist(abs, name); if (ret != -1) //找到联系人 { cout << "姓名:" << abs->personArray[ret].m_Name << "\t"; cout << "性别:" << (abs->personArray[ret].m_Sex == 1 ? "男" : "女") << "\t"; //cout << "性别:" << abs->personArray[ret].m_Sex << "\t"; cout << "年龄:" << abs->personArray[ret].m_Age << "\t"; cout << "电话:" << abs->personArray[ret].m_Phone << "\t"; cout << "家庭住址:" << abs->personArray[ret].m_Addr << endl; } else { cout << "查无此人!" << endl; } system("pause"); system("cls"); } //5、修改联系人信息 void modifyPerson(Addressbooks* abs) { cout << "请输入你要修改的联系人:" << endl; string name; cin >> name; int ret = isExist(abs, name); if (ret != -1) { //姓名 string name; cout << "请输入姓名:" << endl; cin >> name; abs->personArray[ret].m_Name = name; //性别 cout << "请输入性别:" << endl; cout << "1---男" << endl; cout << "2---女" << endl; int sex = 0; while (true) { cin >> sex; if (sex == 1 || sex == 2) { abs->personArray[ret].m_Sex = sex; break; } cout << "输入有误,请重新输入:" << endl; } //年龄 cout << "请输入年龄:" << endl; int age = 0; cin >> age; abs->personArray[ret].m_Age = age; //电话 cout << "请输入电话:" << endl; string phone; cin >> phone; abs->personArray[ret].m_Phone = phone; //住址 cout << "请输入家庭住址:" << endl; string address; cin >> address; abs->personArray[ret].m_Addr = address; cout << "信息修改成功!" << endl; } else { cout << "查无此人!" << endl; } system("pause"); system("cls"); } //6、清空联系人:只需把通讯录中联系人数量置0,实现逻辑上的清空 void cleanPerson(Addressbooks* abs) { abs->m_Size = 0; //把通讯录中联系人数量置0,实现逻辑上的清空 cout << "通讯录已清空" << endl; system("pause"); system("cls"); } //菜单界面 void showMenu() { cout << "***********************" << endl; cout << "**** 1、添加联系人 ****" << endl; cout << "**** 2、显示联系人 ****" << endl; cout << "**** 3、删除联系人 ****" << endl; cout << "**** 4、查找联系人 ****" << endl; cout << "**** 5、修改联系人 ****" << endl; cout << "**** 6、清空联系人 ****" << endl; cout << "**** 0、退出通讯录 ****" << endl; cout << "***********************" << endl; } int main() { //创建通讯录结构体变量 Addressbooks abs; //初始化通讯录中当前人员个数 abs.m_Size = 0; //初始化0个人 int select = 0; //初始化选择 while (true) { //1、菜单调用 showMenu(); cin >> select; switch (select) { case 1: //1、添加联系人 addPerson(&abs); //利用地址传递,可以修饰实参 break; case 2: //2、显示联系人 showPerson(&abs); break; case 3: //3、删除联系人 //{ // cout << "请输入与删除联系人姓名:" << endl; // string name; // cin >> name;; // if (isExist(&abs, name) == -1) // { // cout << "查无此人!" << endl; // } // else // { // cout << "找到此人!" << endl; // } //} deletePerson(&abs); break; case 4: //4、查找联系人 findPerson(&abs); break; case 5: //5、修改联系人 modifyPerson(&abs); break; case 6: //6、清空联系人 cleanPerson(&abs); break; case 0: //0、退出通讯录 cout << "欢迎下次使用!" << endl; system("pause"); return 0; break; } } system("pause"); return 0; }