黑马程序员C++基础笔记:Tiny级别的基础编程经典有趣小项目,熟悉C语言可以看看这篇博文

最近开始学C++了,很多企业对于算法工程师的要求中,“掌握C++、Python、Java编程语言中至少一种”是招聘条件之一,另外考虑到自己后期要学习算法与数据结构,而很多经典的算法与数据结构教材是C/C++语言描述的,因此很有必要学习一下C++。

除此之外,C++这门编程语言也很偏向于系统底层,在工作场景中实际上会经常用到,技多不压身,尽管自己从事的研究方向机器视觉主要使用Python,但学习C++对于未来成为一名算法工程师而言也是很有帮助的。

尽管之前有一些C基础,但还是有必要去听一下C++基础,自己编写一些代码,让大脑尽快熟悉编程的感觉,以便后续的课程能够更好地进行下去。

C++基础部分,我是跳着看黑马程序员的教程,有些编码部分没有看视频自己直接在VS上编程,从6.22看到7.1,通讯录的作业还没有做,后面打算单独发一篇博文。

目录

零、代码模板

一、if-else选择结构:三只小猪称体重

二、while/do...while循环与for循环的应用

2.1 猜数字(随机数种子、while循环并限制循环次数)

2.2 水仙花数(do...while循环、for循环)

2.3 输出10*10的星图(使用for嵌套循环)

2.4 实现乘法口诀表(使用附加条件的for嵌套循环)

三、break 和 continue 的区别

四、数组经典案例

4.1 数组表示及数组名的用途

4.2 五只小猪称体重(找到数组中最大的值)

4.3 数组逆序(数组交换位置,头尾交换法)

4.4 冒泡排序(重点算法)

4.5 二维数组

五、函数

5.1 函数的定义和调用

5.2 函数的值传递

5.3 函数的常见样式

5.4 函数的声明&函数的分文件编写

六、指针

6.1 指针定义及使用、占用内存空间、空指针与野指针

6.2 const修饰指针

6.2.1 常量指针

6.2.2 指针常量

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

6.3 利用指针实现访问数组元素

6.4 指针与函数

 6.5 指针、数组、函数的综合应用

七、结构体

7.1 结构体的定义和使用

7.2 结构体数组

7.3 结构体指针

7.4 结构体嵌套结构体

7.5 结构体做函数参数

7.6 结构体做函数参数及结构体const使用场景

7.7 结构体案例

7.7.1 毕设项目学生和老师(有些难度,可重复复习)

7.7.2 数组中的英雄按年龄进行升序排序


零、代码模板

在进行C++程序编写前,需要倒入一些标准库,下面是C++的模板,每次写C++程序之前都可以将这个模板粘贴进去,避免重复劳动。

#include<iostream>	
using namespace std;

int main()
{
	//此处编写核心程序部分

	system("pause");

	return 0;
}

一、if-else选择结构:三只小猪称体重

需求描述:有三只小猪A,B,C,现在由用户输入这三只小猪的体重,编写程序比较三只小猪的体重,并输出体重最终的小猪名称:

#include<iostream>	
using namespace std;

int main()
{	
	//创建三只小猪体重变量
	int w1, w2, w3;
	
	//提示用户输入
	cout << "请输入小猪A的体重:" << endl;
	cin >> w1;

	cout << "请输入小猪B的体重:" << endl;
	cin >> w2;

	cout << "请输入小猪C的体重:" << endl;
	cin >> w3;

	if (w1 > w2){
		if (w1 > w3) {
			cout << "小猪A最重";
		}
		else {
			cout << "小猪B最重";
		}
	}
	else {
		if (w2 > w3) {
			cout << "小猪B最重";
		}
		else {
			cout << "小猪C最重";
		}
	}
	system("pause");
	return 0;
}

二、while/do...while循环与for循环的应用

2.1 猜数字(随机数种子、while循环并限制循环次数)

需求描述:系统随机生成一个1到100之间的数字,玩家进行猜测,如果猜错,提示玩家数字过大或者过小,如果猜错次数超过5次,那么退出游戏;如果猜对恭喜玩家胜利,也退出游戏。

代码如下所示:

#include<iostream>	
using namespace std;
//time系统时间头文件包含
#include<ctime>

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

	//1、系统生成随机数
	int num = rand() % 100 + 1; //表示生成0 + 1 ~ 99 + 1 的随机数
	//cout << num << endl;

	//2、玩家进行猜测
	int user_input = 0 ;
	//限制猜测次数
	int limited_time = 5;
	int user_time = 0;
	
	while (1){
		
		cout << "请你猜一下这个数是多少:" << endl;
		cin >> user_input;

		//3、判断结构
		
			if (user_time < limited_time - 1) {
				if (user_input > num) {
					cout << "您猜大了,请输入一个小一些的数" << endl;
				}
				else if (user_input < num) {
					cout << "您猜小了,请输入一个小一些的数" << endl;
				}
				else {
					cout << "您猜对了,这个数就是:" << num << endl;
					cout << "太棒了,您只用了" << user_time << "次就猜对了!" << endl;
					break;
				}
				++user_time;
				cout << "您已经猜测了" << user_time << "次,请再接再厉!" << endl;
			}
			else {
				cout << "您猜错的次数已经超过5次,游戏结束!" << endl;
			}
		}

	system("pause");
	return 0;
}

 猜对情况下程序的输出,玩这个游戏很简单,使用二分法即可,100以内的数最多猜测6次就可以猜出:

请你猜一下这个数是多少:
50
您猜大了,请输入一个小一些的数
您已经猜测了1次,请再接再厉!
请你猜一下这个数是多少:
25
您猜大了,请输入一个小一些的数
您已经猜测了2次,请再接再厉!
请你猜一下这个数是多少:
13
您猜对了,这个数就是:13
太棒了,您只用了2次就猜对了!
请按任意键继续. . .

猜错情况下程序的输出:

请你猜一下这个数是多少:
1
您猜小了,请输入一个小一些的数
您已经猜测了1次,请再接再厉!
请你猜一下这个数是多少:
2
您猜小了,请输入一个小一些的数
您已经猜测了2次,请再接再厉!
请你猜一下这个数是多少:
3
您猜小了,请输入一个小一些的数
您已经猜测了3次,请再接再厉!
请你猜一下这个数是多少:
4
您猜小了,请输入一个小一些的数
您已经猜测了4次,请再接再厉!
请你猜一下这个数是多少:
5
您猜小了,请输入一个小一些的数
您已经猜测了5次,请再接再厉!
请你猜一下这个数是多少:
6
您猜测的次数已经超过5次,游戏结束!
请按任意键继续. . .

2.2 水仙花数(do...while循环、for循环)

需求描述:水仙花数是指一个3位数,它的每个位上的数字的3次幂之和等于它本身,例如:

1^3+5^3+3^3=153

请利用do..while语句,求出所有3位数中的水仙花数。

#include<iostream>	
using namespace std;

int main()
{	
	int a = 100;

	do {
		int Digit, Decimal, Hundred;
		Digit = a % 10; //取个位
		Decimal = a / 10 % 10; //取十位
		Hundred = a / 100 % 10; //取百位

		if ((Hundred * Hundred * Hundred + Decimal * Decimal * Decimal + Digit * Digit * Digit) == a) {
			cout << a<< endl;
		}a++;
	} while (a < 1000);
	
	system("pause");
	return 0;
}

 也可使用for循环:

#include <iostream>
using namespace std;

int main()
{
	for (int a = 100; a < 1000; a++)
	{
		int Digit, Decimal, Hundred;
		Digit = a % 10; //取个位
		Decimal = a / 10 % 10; //取十位
		Hundred = a / 100 % 10; //取百位

		if ((Hundred * Hundred * Hundred + Decimal * Decimal * Decimal + Digit * Digit * Digit) == a) {
			cout << a << endl;
		}
	}

	system("pause");
	return 0;
}

输出结果如下:

153
370
371
407

2.3 输出10*10的星图(使用for嵌套循环)

外层执行一次,内层执行一周。

#include <iostream>

int main()
{
	for (int j = 1; j < 11; j++) {
		for (int i = 1; i < 11; i++)
		{
			printf("* ");
		}
		printf("\n");
	}
	
	system("pause");
	return 0;
}

输出结果:

* * * * * * * * * *
* * * * * * * * * *
* * * * * * * * * *
* * * * * * * * * *
* * * * * * * * * *
* * * * * * * * * *
* * * * * * * * * *
* * * * * * * * * *
* * * * * * * * * *
* * * * * * * * * *

2.4 实现乘法口诀表(使用附加条件的for嵌套循环)

 代码如下:

#include <iostream>
using namespace std;

int main()
{
	for (int j = 1; j < 10; j++) {
		for (int i = 1; i <= j ; i++)
		{
			cout << i << "×" << j << "="  << i * j << "\t";
		}
		cout << endl;
	}
	
	system("pause");
	return 0;
}

输出结果如下:

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

三、break 和 continue 的区别

#include <iostream>
using namespace std;

int main()
{
	for (int j = 1; j <= 100; j++) {
		if (j % 2 == 0) {
			break;
			//continue;
		}
		cout << j << endl;
	}
	
	system("pause");
	return 0;
}

如果是break,那么只会输出1;如果是continue,则会输出所有的奇数,在这里continue具有跳过的功能——continue并没有使整个循环终止,而break会跳出循环。

四、数组经典案例

4.1 数组表示及数组名的用途

#include <iostream>
using namespace std;

int main()
{
	int arr[] = { 90,80,70,60 };
	for (int i = 0; i < 4; i++) {
		cout << arr[i] << endl;
	}
	//数组名用途
	//1、可以通过数组名统计数组占用内存的大小
	
	cout << "整个数组占用的内存空间是:" << sizeof(arr) << endl;
	cout << "每个数组元素占用的内存空间是:" << sizeof(arr[0]) << endl;
	cout << "数组中的元素个数是:" << sizeof(arr)/ sizeof(arr[0]) << endl;

	//2、可以通过数组名查看数组首地址;根据元素地址,可以证明数组占用的是连续的内存空间爱你
	cout << "数组首地址为:" << int(arr) << endl;
	cout << "数组第一个元素地址为:" << (int)&arr[0] << endl;
	cout << "数组第二个元素地址为:" << (int)&arr[1] << endl;

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

	system("pause");
	return 0;
}

输出结果如下:

90
80
70
60
整个数组占用的内存空间是:16
每个数组元素占用的内存空间是:4
数组中的元素个数是:4
数组首地址为:653260296
数组第一个元素地址为:653260296
数组第二个元素地址为:653260300

4.2 五只小猪称体重(找到数组中最大的值)

需求描述:在一个数组中记录了五只小猪的体重,如int arr[]={300,350,200,400,250},找出并打印最终的小猪体重。输出:400.

#include <iostream>
using namespace std;

int main()
{
	int temp = 0;
	int arr[] = { 300,350,200,400,250 };
	for (int i = 0; i < 5; i++) {
		if(arr[i]>temp){
			temp = arr[i];
		}
	}
	cout << temp << endl;

	system("pause");
	return 0;
}

4.3 数组逆序(数组交换位置,头尾交换法)

输入:{1,2,3,4,5}

输出:{5,4,3,2,1}

#include <iostream>
using namespace std;

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

	//定义start 和end 是为了便于表示数组中的元素

	int start = 0;
	int end = sizeof(arr) / sizeof(arr[0]) - 1;

	while (start < end) 
	{
		temp = arr[start];
		arr[start] = arr[end];
		arr[end] = temp;
		start++;
		end--;
	}
	for (int i = 0; i < 5; i++) 
	{
		cout << arr[i] << endl;
	}

	system("pause");
	return 0;
}

4.4 冒泡排序(重点算法)

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

因此冒泡排序的核心思想是每一轮比较找出这次比较的最大值。

#include <iostream>
using namespace std;

int main()
{
	//利用冒泡排序实现升序序列
	//排序的总轮数=元素个数-1
	//每轮对比的次数 = 元素个数 - 排序轮数 

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

	cout << "排序前:";
	for (int i = 0; i < 9; i++)
	{
		cout << arr[i] << "\t";
	}
	cout << endl ;

	for (int i = 0; i < 9 - 1; i++) {

		for (int j = 0; j < 9 - i - 1; j++) 
		{
			if (arr[j] > arr[j + 1]) 
			{
				temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
	}
	cout << "排序后:";
	for (int i = 0; i < 9; i++) 
	{
		cout << arr[i] << "\t";
	}
	cout << endl;

	system("pause");
	return 0;
}

4.5 二维数组

实现二维数组的打印,以及各行、各列、各元素地址和占用内存的打印输出。

#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;
	}
	cout << "二维数组占用内存为:" << sizeof(arr) << endl;
	cout << "二维数组第一行占用内存为:" << sizeof(arr[0]) << endl;
	cout << "二维数组第一行第一个元素占用内存为:" << sizeof(arr[0][0]) << endl;

	cout << "二维数组行数为:" << sizeof(arr)/ sizeof(arr[0]) << endl;
	cout << "二维数组列数为:" << sizeof(arr[0])/ sizeof(arr[0][0]) << endl;

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

	system("pause");
	return 0;
}

输出结果如下:

1 2 3
4 5 6
二维数组占用内存为:24
二维数组第一行占用内存为:12
二维数组第一行第一个元素占用内存为:4
二维数组行数为:2
二维数组列数为:3
二维数组首地址为:1249376792
二维数组第一行首地址为:1249376792
二维数组第二行首地址为:1249376804
二维数组第一行第一个元素首地址为:1249376792

五、函数

5.1 函数的定义和调用

#include <iostream>
using namespace std;

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

int main()
{
	int a = 10;
	int b = 10;
	//调用add函数
	int sum = add(a, b);
	cout << "sum=" << sum << endl;

	a = 100;
	b = 100;
	sum = add(a, b);
	cout << "sum=" << sum << endl;

	system("pause");
	return 0;
}

5.2 函数的值传递

  • 所谓值传递,就是函数调用时实参将数值传入给形参
  • 值传递时,如果形参发生任何改变,并不会影响形参
#include <iostream>
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;返回值不需要的时候,可以不写return
}

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

	cout << "a=" << a << endl;
	cout << "b=" << b << endl;
	
	//当我们做值传递的时候,函数的形参发生改变,并不会影响实参,经过函数,a的值会给num1,b的值会给num2.
	swap(a, b);

	//交换后a和b的实际值,发现a,b还是原来的a,b
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;

	system("pause");
	return 0;
}

输出结果:

a=10
b=20
交换前:
num1=10
num2=20
交换后:
num1=20
num2=10
a=10
b=20

5.3 函数的常见样式

一共四种常见样式:无参无返、有参无返、无参有返、有参有返

#include <iostream>
using namespace std;

//1、无参无返
void test01()
{
	cout << "this is test 01 " << endl;
}

//2、有参无返
void test02(int a)
{
	cout << "this is test 02 a=" << a << endl;
}

//3、无参有返
int test03()
{
	cout << "this is test 03 " << endl;
	return 1000;
}

//4、有参有返
int test04(int a)
{
	cout << "this is test 04 " << endl;
	return a;
}

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

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

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

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

	system("pause");
	return 0;
}

输出结果如下:

this is test 01
this is test 02 a=100
this is test 03
num1=1000
this is test 04
num2=10000

5.4 函数的声明&函数的分文件编写

声明的作用:提前告诉编译器函数名称以及如何调用函数,知晓函数的存在,函数的实际主体可以单独定义。注意:函数的声明可以多次,但是函数的定义只能有一次。

分文件编写的作用:让代码的结构更清晰。

分文件编写的步骤:

1.创建后缀名为.h的头文件,在头文件中写函数声明。

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

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

 2.创建.cpp后缀名的源文件,在源文件中写函数定义。

//swap.cpp
#include <iostream>
#include "swap.h"

using namespace std;

void swap(int a, int b)
{
	int temp = a;
	a = b;
	b = temp;

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

3.在新文件中引用该函数

#include <iostream>
#include "swap.h"

using namespace std;

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

	swap(a, b);

	system("pause");
	return 0;
}

六、指针

指针就是一个地址/指针就是记录地址的一个特殊变量/可以通过指针来保存一个地址。

指针的妙用:

  • &a是一个常量值,不能进行++或--,但是用p就可以指向多个地址。
  • 例如数字,用p++就可以遍历数组中的多个元素,因为数组元素的地址是连续的。

6.1 指针定义及使用、占用内存空间、空指针与野指针

#include <iostream>
using namespace std;

int main()
{
	//1、定义指针:数据类型 * 指针变量名
	int a = 10;
	int* p;
	//让指针记录变量a的地址
	p = &a;
	//等价于int *p = &a;

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

	//2、使用指针
	//可以通过解引用的方式找到指针指向的内存,指针前加 * 代表解引用,找到指针指向的内存的数据
	//通过*p 找到a这段内存,并且通过*p修改内存,找到a的地址,执行读和写的操作,可修改可访问
	*p = 1000;
	cout << "a=  " << a << endl;
	cout << "*p=  " << *p << endl;

	//3、指针所占内存空间:32位x86占用4个字节空间,64位x64占用8个字节空间
	cout << "sizeof(int*)=" << sizeof(int*) << endl;
	cout << "sizeof(float*)=" << sizeof(float*) << endl;
	cout << "sizeof(double*)=" << sizeof(double*) << endl;
	cout << "sizeof(char*)=" << sizeof(char*) << endl;

	//4、空指针:用于给变量指针进行初始化
	int* p1 = NULL;
	//空指针是不可以进行访问的,0~255之间的内存编号是系统占用的,因此不可以访问
	//*p1 = 100;

	//5、野指针:指针变量指向非法的内存空间(出现读取访问权限冲突错误),在程序中,尽量避免出现
	//int* p2 = (int*)0x1100;
	//cout << *p2 << endl;

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

	system("pause");
	return 0;
}

6.2 const修饰指针

6.2.1 常量指针

特点:指针的指向可以修改,但是指向的值不可修改。

#include <iostream>
using namespace std;

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

	system("pause");
	return 0;
}

6.2.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;
}

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

#include <iostream>
using namespace std;

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

	system("pause");
	return 0;
}

6.3 利用指针实现访问数组元素

#include <iostream>
using namespace std;

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

	int * p = arr;

	cout << "第一个元素:" << arr[0] << endl;
	cout << "指针访问第一个元素:" <<*p << endl;

	for (int i = 0; i < 9; i++) {
		cout << *p << endl;
		p++; //让指针向后偏移四个字节
	}

	system("pause");
	return 0;
}

6.4 指针与函数

使用指针表示函数的特点:变量是地址时可以间接改变实参,因为参数的传递方法可以传递地址。

#include <iostream>
using namespace std;

//值传递
void swap1(int a, int b)
{
	int temp = a;
	a = b;
	b = temp;
}

//地址传递
void swap2(int *p1, int *p2)
{
	int temp = *p1;
	*p1 = *p2;
	*p2 = temp;
}

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

	swap1(a, b);//值传递不会改变实参,a=10  b=20
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;

	swap2(&a, &b);//地址传递会改变实参,a=20  b=10
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;

	system("pause");
	return 0;
}

 6.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++) 
		{
			int temp = 0;
			if (arr[j] > arr[j + 1]) 
			{
				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] << endl;
	}
}


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

	//数组长度
	int len = sizeof(arr) / sizeof(arr[0]);

	//创建函数
	BubbleSort(arr, len);

	//打印排序后数组
	printArray(arr, len);

	system("pause");
	return 0;
}

七、结构体

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

7.1 结构体的定义和使用

创建结构体的语法:

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

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

  • struct 结构体名 变量名
  • struct 结构体名 变量名 = {成员1值,成员2值...}
  • 定义结构体时顺便创建变量
#include <iostream>
using namespace std;

//1、创建学生数据类型,自定义数据类型就是一些类型的集合组成的一个类型

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


int main()
{
	//2、通过学生类型创建具体学生

	//2.1 struct Student s1
	Student s1; //C++中结构体创建时struct可省略
	s1.name = "张三"; //结构体用.访问成员
	s1.age = 18;
	s1.score = 100;

	cout << "姓名:" << s1.name << " 年龄:" << s1.age << " 分数:" << s1.score << endl;


	//2.2 struct Student s2 = {成员1值,成员2值...}
	struct Student s2 = { "李四",19,80 };
	cout << "姓名:" << s2.name << " 年龄:" << s2.age << " 分数:" << s2.score << endl;
		
	//2.3 定义结构体时顺便创建结构体变量(12行创建了s3)
	s3.name = "王五";
	s3.age = 20;
	s3.score = 90;
	cout << "姓名:" << s3.name << " 年龄:" << s3.age << " 分数:" << s3.score << endl;

	system("pause");
	return 0;
}

7.2 结构体数组

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

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

#include <iostream>
using namespace std;

//1、创建学生数据类型,自定义数据类型就是一些类型的集合组成的一个类型

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


int main()
{
//2、创建结构体数组
	struct Student stuArray[3] =
	{
		{"张三", 18, 80},
		{"李四", 19, 90},
		{"王五", 20, 100},
	};

//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;
}

7.3 结构体指针

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

#include <iostream>
using namespace std;

//1、创建学生数据类型,自定义数据类型就是一些类型的集合组成的一个类型

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

int main()
{
	struct Student stu = { "张三", 18, 80 };
	struct Student * p = & stu;
	p->score = 90;  //指针通过->操作符可以访问成员
	cout << "姓名:" << p->name << " 年龄:" << p->age << " 分数:" << p->score << endl;

	system("pause");
	return 0;
}

7.4 结构体嵌套结构体

#include <iostream>
using namespace std;

//学生结构体定义
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 = "Mr.Wang";
	t1.age = 40;

	t1.stu.name = "Zhang San";
	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;
}

7.5 结构体做函数参数

需求描述:将学生信息传入到一个参数中,打印学生身上所有信息。

#include <iostream>
using namespace std;

//学生结构体定义
struct student
{
	//成员列表
	string name;
	int age;
	int score;
};
//值传递
void printStudent1(struct student s)
{
	cout << "子函数中打印 姓名:" << s.name << " 年龄:" << s.age << " 考试分数:" << s.score << endl;
}
//地址传递
void printStudent2(struct student *p)
{
	cout << "子函数2中打印 姓名:" << p->name << " 年龄:" << p->age << " 考试分数:" << p->score << endl;
}

int main()
{
	struct student s = { "张三",20,85 };
	cout << "main函数中打印 姓名:" <<s.name << " 年龄:" << s.age << " 考试分数:" << s.score << endl;
	printStudent1(s); //值传递
	printStudent2(&s);//地址传递

	system("pause");
	return 0;
}

7.6 结构体做函数参数及结构体const使用场景

一共有两种方式:值传递和地址传递,如果不想修改主函数中的数据,用值传递;反之用地址传递。以下程序输出结果分别为:20,100,200,200.

加入const之后,一旦有修改的操作就会报错,可以防止误操作。

#include <iostream>
using namespace std;

//学生结构体定义
struct student
{
	//成员列表
	string name;
	int age;
	int score;
};
//值传递,修饰形参,实参不会发生改变,值传递拷贝的数据量太大了
void printStudent1(struct student s)
{
	s.age = 100;
	cout << "子函数中打印 姓名:" << s.name << " 年龄:" << s.age << " 考试分数:" << s.score << endl;
}
//地址传递,修饰形参,实参会发生改变,将函数中的形参改为指针可以减少内存空间,而且不会复制新的副本
void printStudent2(const struct student *p)
{
	p->age = 200; //加入const之后不可修改
	cout << "子函数2中打印 姓名:" << p->name << " 年龄:" << p->age << " 考试分数:" << p->score << endl;
}

int main()
{
	struct student s = { "张三",20,85 };
	cout << "实参传递前main函数中打印 姓名:" <<s.name << " 年龄:" << s.age << " 考试分数:" << s.score << endl;
	printStudent1(s); //值传递
	printStudent2(&s);//地址传递
	cout << "子函数2实参传递后main函数中打印 姓名:" << s.name << " 年龄:" << s.age << " 考试分数:" << s.score << endl;

	system("pause");
	return 0;
}

7.7 结构体案例

7.7.1 毕设项目学生和老师(有些难度,可重复复习)

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

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

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

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

解决方案代码如下:

#include <iostream>
using namespace std;

//学生结构体定义
struct Student
{
	string sName;
	int score;
};

//教师结构体定义
struct Teacher
{
	string tName;
	Student sArray[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].sArray[j].sName = "Student_";
			tArray[i].sArray[j].sName += nameSeed[j];

			int random = rand() % 61 + 40; // 40 ~100
			tArray[i].sArray[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].sArray[j].sName <<
				" 考试分数 " << tArray[i].sArray[j].score<<endl;
		}
	}
}

int main()
{
	//随机数种子
	srand((unsigned int)time(NULL));
	
	//创建3名老师的数组
	struct Teacher tArray[3];

	//通过函数给3名老师的信息赋值,并给老师带的学生信息赋值
	int len = sizeof(tArray) / sizeof(tArray[0]);
	allocateSpace(tArray, len);

	//打印所有老师及所带的学生信息
	printInfo(tArray, len);

	system("pause");
	return 0;
}

 小结:在创建函数之前,可以先在主函数中考虑实现什么样的功能,再考虑写什么样的子函数。

7.7.2 数组中的英雄按年龄进行升序排序

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

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

五名英雄信息如下:

{"欣南",20,"火"},
{"东杉",24,"木"},
{"北淼",23,"水"},
{"坤中",18,"土"},
{"西昭",22,"金"},

代码如下:

#include <iostream>
using namespace std;

//学生结构体定义
struct Hero
{
	string name;
	int age;
	string sex;
};

void BubbleSort(Hero Array[],int len)
{
	for (int i = 0 ; i < len - 1 ;  i++)
	{
		for (int j = 0; j < len - i - 1; j++)
		{
			Hero temp;
			if (Array[j].age > Array[j + 1].age)
			{
				temp = Array[j];
				Array[j] = Array[j+1];
				Array[j+1] = temp;
			}
		}
	}
}

void printHero(Hero Array[], int len)
{
	for (int i = 0; i < len; i++)
	{
		cout << Array[i].name<< Array[i].age<< Array[i].sex << endl;
	}
}


int main()
{
	Hero Array[5] =
	{
		{"欣南",20,"火"},
		{"东杉",24,"木"},
		{"北淼",23,"水"},
		{"坤中",18,"土"},
		{"西昭",22,"金"},
	};
	int len = sizeof(Array) / sizeof(Array[0]);

	BubbleSort(Array, len);
	printHero(Array, len);

	system("pause");
	return 0;
}

耶,最终实现了冒泡排序功能!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值