十二、指针和引用(二)

这篇具有很好参考价值的文章主要介绍了十二、指针和引用(二)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

十二、指针和引用(二)

1、指针和数组的关系

1)思考

​ 假设你要设计一种编程语言,你要如何实现数组呢?思考之前请先牢记:数组在内存中是连续的,维度由低到高(大部分操作系统下)。

2)汇编分析数组如何实现

//C++代码
#include <iostream>

int main()
{
    int a[5]{};
    int* ptrA{ &a[0] };
    *ptrA = 5;    //通过指针设置数组的值
     
    a[0] = 5;     //通过数组下标设置数组的值
    a[1] = 5;
}

//上述代码汇编分析
	int a[5]{};
    int* ptrA{ &a[0] };
00A51840  mov         eax,4                     //eax=4
00A51845  imul        ecx,eax,0                 //imul为乘法,即ecx=eax*0=0
00A51848  lea         edx,[ebp+ecx-1Ch]         //edx=ebp+ecx-1Ch=ebp-1Ch
00A5184C  mov         dword ptr [ebp-28h],edx   //ptr表示指针,即[ebp-28h]=ebp-1Ch, []中的表示地址
    *ptrA = 5;                                   
00A5184F  mov         eax,dword ptr [ebp-28h]    //eax=[ebp-28h] 即eax=ebp-1Ch
00A51852  mov         dword ptr [eax],5         //[eax]=5,即[ebp-1Ch]=5,即a[0]=5

    a[0] = 5;
00A51858  mov         eax,4                    //eax=4
00A5185D  imul        ecx,eax,0                //ecx=eax*0=0
00A51860  mov         dword ptr [ebp+eax-1Ch],5    //[ebp+eax-1Ch]=5,即[ebp-1Ch]=5
    a[1] = 5;
00A51868  mov         eax,4                    //eax=4
00A5186D  shl         eax,0                    //shl为左位移,即eax<<0,即eax=eax*2^0即eax=eax*1=4
00A51870  mov         dword ptr a[ebp+eax-1Ch],5   //[a[4]]=5
}

总结数组实现:使用数组第一个元素的起始地址,加上访问第N个元素*偏移量(即类型的大小)来达到访问数组中的每一个元素 。数组a的地址本质上和a[0]的地址相等。

//数组a的地址本质上和a[0]的地址相等。
#include <iostream>

int main()
{
    int a[5]{};
    int* ptrA{ &a[0] };
    *ptrA = 5;    //通过指针设置数组的值
    
    std::cout << "数组a的地址为:" << a << std::endl;
    std::cout << "a[0]的地址为: " << &a[0] << std::endl;
}
//注:因数组a的地址和a[0]的地址一样,所以ptrA和a在本质上一样,所以在定义指针数组时,可以直接写为int* ptrA {a}; ptrA[1]=1002;
注:本质上来说,数组名就是一个指针。但是sizeof()函数处理数组时,还是当作数组类型处理,所以通过sizeof()查看内存占用大小是和指针是不同的

十二、指针和引用(二)

3)结论:指针可以当数组用

​ 数组的底层实现是利用了指针,因此,我们甚至可以大胆的说,起始C/C++里根本不存在什么数组,所谓的数组不过是利用指针玩的小把戏而已。

​ 从原理上来讲,指针和数组是同一个方法的不同表达,而数组名本身就是一个指针,数组元素只是这个指针按照一定的偏移量后,对应的内存区域里的内容。

​ 因此我们尝试一下按照数组的使用方式来使用一下指针,看看会发生什么事情。

#include <iostream>
int main()
{
	int a[5]{};
	int* ptrA{ a };
	*ptrA = 5;
	a[0] = 5;
	a[1] = 50001;
	a[2] = 5; 

	std::cout << a << std::endl;     //010FF9F8
	std::cout << &a[0] << std::endl;  //010ff9F8
	std::cout << ptrA[1] << std::endl; //50001
	std::cout << a[1] << std::endl;  //50001

	std::cout << sizeof(a) << std::endl;     //20
	std::cout << sizeof(ptrA) << std::endl;  //4

}

4)多维数组思考

​ 数组的本质是连续的内存区域,所以我们可以大胆设想,所谓的多维数组起始不存在,多维只是我们人类为了方便我们自己的理解创造出来的逻辑方法。

!

注:数组指针+1表示1*数据类型的大小,逻辑是几,则每次+1步跳跳几

5)数组在内存中的表现形式

​ 不管是int a[2][5]还是int a[5][2]在内存中的本质都是一样的,都是一块连续的内存空间,并且占用的地址也都一样。

十二、指针和引用(二)

#include <iostream>

int main()
{
	int test[2][5]
	{
		{1001,1002,1003,1004,1005},
		{2001,2002,2003,2004,2005}    //多维数组在内存中的人为逻辑排序
	};
	//1001, 1002, 1003, 1004, 1005,2001,2002,2003,2004,2005   内存中多维数组的真实排序

	int* ptrTest{ (int*)test };  //可以进行强制类型转化,因为test本质是一个地址,里面保存中test[0][0]的地址
	//输入test数组最后一个元素
	std::cout << "通过数组下标获取test最后一个元素:" << test[1][4] << std::endl;
	std::cout << "通过指针获取test最后一个元素:    " << ptrTest[9] << std::endl;
}

//test是一个数组指针

十二、指针和引用(二)

6)数组指针和指针数组

①指针数组:指针数组本质上来讲是一个数组,数组的内容是指针,如int* ptrA[5];

②数组指针:数组指针本质上来讲是一个指针,只是这个指针用来处理数组问题

//数组指针定义
int (*ptrB)[5];
//数组指针使用
#include <iostream>
int main()
{
	int test[2][5]
	{
		{1001,1002,1003,1004,1005},
		{2001,2002,2003,2004,2005}
	};

	int* ptestA[5];  //指针数组,本质上是一个数组,即将数组中存放5个地址

	int(*pTestA)[5]{ test }; //数组指针(本质上是一个指针),表示每一行按照5个元素断开,即该指针处理每一行5个数据的数组
	std::cout << test[1][4] << std::endl;        //2005
	std::cout << pTestA[0][1] << std::endl;      //1002
	std::cout << sizeof(pTestA) << std::endl;      //4, 数组指针是一个指针,指针大小为4

	std::cout << pTestA << std::endl;
	pTestA = pTestA + 1;               //指针加1,表示加对应数组类型的大小,即+1*数据类型大小*数组指针元素个数,即1*4*5=20
	std::cout << pTestA << std::endl;
}

十二、指针和引用(二)

2、动态内存分配

1)项目设计

​ 麟江湖副本系统 :玩家进入麟江湖副本系统后,地图上会随机刷新一批怪物,数量不等,从100-10000个都有可能,我们如何应对这种不确定数量对象的问题?

2)C语言中的动态内存分配malloc

//C语言中的动态内存分配malloc语法
void* malloc(size_t size);  //malloc将为用户分为size_t字节个内存,并且返回内存分配的地址,如果分配失败,那么返回0

//示例
int* pa=(int*)malloc(4);  //pa是分配好的内存的地址,4是要分配的内存的大小,如果内存分配失败,那么pa=0

注:size_t是一个通过typedef自定义的数据类型,相当于无符号整数。可通过邮件函数-转到定义查看
	typedef unsigned int     size_t;

malloc的简单使用:

//malloc的简单使用
#include <iostream>
int main()
{
	unsigned x;
	std::cout << "请输入要申请的内存大小:";
	std::cin >> x;
	//malloc(x*4); //放什么类型的变量,就*什么类型的变量大小,如int类型*4。可直接使用seizeof(int)计算
	int* p = (int*)malloc(sizeof(int) * x);   //void*  是空类型的指针,即没有任何类型,无法将其赋值给int*类型的指针,因此需要强制类型转化

	//内存不一定分配成功
	if (p == nullptr)  //nullptr就相当于0,但是推荐使用nullptr,C语言中只能使用0
	{
		std::cout << "内存分配失败!!!" << std::endl;
	}
	else      //内存分配成功后,再执行相关操作
	{
		p[0] = 952;
		p[1] = 953;
		p[2] = p[0] * p[1];
		std::cout<<"p[0]:" << p[0] << " p[1]:" << p[1] << " p[2]:" << p[2] << std::endl;
	}

}

十二、指针和引用(二)

3)C语言中的动态内存分配callloc

//动态内存分配函数callloc语法
void* calloc(size_t count,size_t size);  //calloc将为用户分配count乘size_t字节个内存,并且返回内存分配的地址,如果分配失败,那么返回0

//calloc示例
int* pa=(int*)calloc(1,4); //pa是分配好的内存地址,1是要分配的元素个数,4是要分配的每个元素个数的大小

注:calloc运行效率比malloc的低,但是比较方便,会将分配好的内存空间设置为0,且不需要手动计算分配的内存空间的大小。calloc会默认将分配好的内存区域设置为0.
//动态内存分配callloc示例
#include <iostream>
int main()
{
	unsigned x;
	std::cout << "请输入要申请的内存大小:";
	std::cin >> x;
	//calloc直接说明需要申请的内存个数,及每个内存的大小
	int* p = (int*)calloc(x, sizeof(int));
	//calloc会将自动分配的内存空间的值设置为:0
	std::cout << "calloc会将自动分配的内存空间的值设置为:" << p[0] << std::endl;
	if (p == nullptr)
	{
		std::cout << "内存分配失败!!!";
	}
	else 
	{
		p[0] = 952;
		p[1] = 953;
		p[2] = p[0] * p[1];
		std::cout << "p[0]:" << p[0] << " p[1]:" << p[1] << " p[2]:" << p[2] << std::endl;
	}
}

十二、指针和引用(二)

3)C语言中的动态内存分配realloc

//动态内存分配realloc语法
void* realloc(void* _Blocak,size_t _szie); //realloc将为用户重新分配内存,_Block是用户已经分配好的内存,Size是要求重新分配的大小,函数返回重新分配后的内存

//示例
int* pa=(int*)malloc(4);
pa=(int*)realloc(pa,8);  //pa是重新分配后的内存地址,8是重新分配后的大小。若分配失败,pa=0

注:重新分配内存空间后,原先的值还在,不丢失。内存地址有可能变化,有可能不变
#include <iostream>
int main()
{
	unsigned x;
	std::cout << "请输入要分配的内存空间大小:";
	std::cin >> x;
	int* p = (int*)malloc(x * sizeof(int));
	if (p == nullptr)
	{
		std::cout << "分配内存失败";
	}
	else
	{
		p[0] = 123;
		p[1] = 456;
		p[2] = p[0] * p[1];
		std::cout << "p[0]:" << p[0] << " p[1]:" << p[1] << " p[2]:" << p[2] << std::endl;
	}
	std::cout << "请输入要重新分配的内存空间大小:";
	std::cin >> x;
	p = (int*)realloc(p, x);  //注:重新分配内存空间后,原先的值还在。
	std::cout << "p[0]:" << p[0] << " p[1]:" << p[1] << " p[2]:" << p[2] << std::endl;
	free(p); p = 0;    //释放内存空间并同时清0,
}

十二、指针和引用(二)

4)C语言中的动态内存分配free

//释放内存空间free语法
void free(void* _Blocak);

//示例
int* pa=(int*)malloc(4);
free(pa);         //pa表示所占用的内存被释放,释放内存不可能失败
pa=0;             //释放以后要将指针清零,防止出现悬挂指针

5)C++的动态内存分配

C++内存分配是基于C语言的内存分配实现的

//C++的动态内存分配语法
数据类型* 指针变量名称=new 数据类型;
数据类型* 指针变量名称=new 数据类型[数量];

//示例
int* pa = new int;
int* pa = new int[5];          //分配一段能够存放5个int变量类型的内存空间

注:分配内存失败,pa返回0
//C++的动态内存分配语法
#include <iostream>
int main()
{
	unsigned x;
	std::cout << "请输入要分配的内存空间大小:";
	std::cin >> x;
	int* pa = new int[x];   //分配存放x个int类型大小的数据
	if (pa == nullptr)
	{
		std::cout << "分配内存失败";
	}
	else
	{
		pa[0] = 123;
		pa[1] = 456;
		pa[2] = 789;
		std::cout << "pa[0]:" << pa[0] << std::endl;
		std::cout << "pa[1]:" << pa[1] << std::endl;
		std::cout << "pa[2]:" << pa[2] << std::endl;
	}
	
}
//反汇编
       if (void* const block = malloc(size))
006227F4  mov         eax,dword ptr [size]  
006227F7  push        eax  
006227F8  call        _malloc (0621069h)  
006227FD  add         esp,4  
00622800  mov         dword ptr [ebp-4],eax  
00622803  cmp         dword ptr [ebp-4],0  
00622807  je          operator new+1Eh (062280Eh) 
           
 注:通过查看反汇编,可知new底层是通过malloc实现的

十二、指针和引用(二)

6)C++内存释放free

//C++内存释放free语法
delete 指针;      //释放用new分配的内存
delete[] 指针;    //释放用new 数据类型[]分配的内存

注:new和delete要成对出现
#include <iostream>
int main()
{	
	unsigned x;
	std::cout << "请输入要分配的内存空间:";
	std::cin >> x;
	int* p = new int[x];
	int* mp = new int;
	std::cout << p << std::endl;;
	std::cout << p[0]<<std::endl;

	delete mp;     //释放内存,如果只分配了一个,不需要加[]
	delete[] p;   //释放内存,如果分配了多个内存空间,需要加[],
}

十二、指针和引用(二)

3、动态内存分配的风险

1)悬挂指针问题(野指针)

注:指针申请并释放后,仍然去使用这一块内存空间,有时候会出错,有时候不会出错。

//通过malloc申请的内存,释放以后,继续使用不会报错
#include <iostream>
int main()
{
	int* p = (int*)malloc(10 * sizeof(int));
	int* pold = p;
	p[0] = 255;
	free(p);
	p[0] = 500;    //虽然p已经释放了,但是还是去用,
	//free(pold); //重复释放会出错
	std::cout << p[2] << std::endl;;    //-572665370
}

十二、指针和引用(二)

//通过new申请的内存,delete释放以后,继续使用会报错
#include <iostream>
int main()
{
	int* p = new int[10];
	p[0] = 255;
	delete[] p;
	p[0] = 500;    //虽然p已经释放了,但是还是去用,
	//deblete[] p; //重复释放会出错
	std::cout << p[2] << std::endl;;    
}

十二、指针和引用(二)

//将new申请的内存,再赋值给其他变量,释放以后,继续使用不报错
#include <iostream>
int main()
{
	int* p = new int[10];
	int* pa = p;
	p[0] = 255;
	delete[] p;
	pa[2] = 500;    //虽然p已经释放了,但是还是去用不会报错,但是输出会报错
	//deblete[] p; //重复释放会出错
}

十二、指针和引用(二)

注:指针重复释放一定会出错,且不可以

//指针重复释放一定会出错
#include <iostream>
int main()
{
	int* p = new int[10];
	int* pa = p;
	delete[] p;
	//delete[] pa; //指针重复释放一定会出错
}

2)内存碎片问题

​ 频繁的申请和释放小块内存会造成内存碎片,虽然原则上还有内存可以使用,但是实际上由于剩余内存碎片化的存在,使得我们无法分配新的内存,当然,现在也不必太担心这样的情况,因为new和delete背后的算法会尽力规避这个分线,并且现在我们的虚拟内存也足够大,但是如果是嵌入式开发或者要求较高的开发,就要注意这个问题,我们也可以自己来控制我们的内存分配,但这是比较高阶的操作。

3)内存分配的思考

​ 原则上来说malloc分配的内存可以用delete释放(new的底层是malloc),new分配的内存可以使用free释放,但是实际使用时不允许两者混用,malloc分配的内存一定要用free释放、new分配的内存一定使用delete释放。

4)复制内存memcpy

//复制内存memcpy语法
void* memcpy(void* _Dst,const void* _Src,size_t _size);  //memcpy可以将_Src区域的内存复制到_Dst区域,复制的长度为_Size,赋值的单位为字节

//示例
int a[5]{1001,1002,1003,1004,1005};
int *p = new int[5];
memcpy(p,a,5*sizeof(int));
//复制内存,将数组中的数据,复制到指针数组中
#include <iostream>

int main()
{	
	int a[5]{ 1001,1002,1003,1004,1005 };
	int* p = new int[5];
	/*
	法一:
	for (int i = 0; i < 5; i++)
	{
			p[i] = a[i];
	}
	*/
	法二
	memcpy(p, a, 5 * sizeof(int));      //单位为字节
	for (int j = 0; j < 5; j++)
	{	
		std::cout << p[j]<<std::endl;
	}
}

十二、指针和引用(二)

4)设置内存memset

//设置内存memset语法
void* memset(void* _Dst,int val,size_t _Size);  //memset可以将指定内存区域每一个字节的值都设置为val,_Size表示要设置的长度(单位:字节)

//示例
int* p=new int[100];
memset(p,0,100*sizeof(int));

注:因每次只能填充一个字节,所以val的范围为0至-1,即0x0至0xff,一般都设置为0或者-1
#include <iostream>

int main()
{
	int* p = new int[100];
	memset(p, 0, 100 * sizeof(int));      //设置内存,[地址,设置的值,设置的大小],不管设置的大小为多少,只能一个字节一个字节初始化
	//memset(p, 0xff, 100 * sizeof(int));     //初始化内存为ffffff
	std::cout << p[0] << std::endl;;
}

十二、指针和引用(二)

4、引用类型

作用:提高代码效率,引用类型必须初始化

//引用语法
数据类型& 变量名称{引用对象的名称};  //引用是创建一个变量的引用名称

//示例
int a{500};
int& la{a};    //以后对la的操作就相当于对a的操作,修改la就相当于修改了a

注:引用类型一定要进行初始化,并且一旦引用后,引用后的值无法修改
//引用使用
#include <iostream>
int main()
{
	int a{ 5250 };
	//引用谁就等于谁,即将a起了另外一个名字,将a的值复制给la,包括地址。一个变量可以有多个引用
	int& la{ a };
	int& la1{ a };
	int& la2{ a };
	int& la3{ a };

	//常量的引用
	const int b{ 3000 };
	const int& lb{ b };
	std::cout << lb << std::endl;  //3000

	std::cout << &a << std::endl;     //00cBEFF8
	a++;
	std::cout << la << std::endl;   //a++就相当于la++
	std::cout << &la1 << std::endl;   //00cBEFF8
	std::cout << &la2 << std::endl;
	std::cout << &la3 << std::endl;
}

十二、指针和引用(二)

5、指针练习

​ 暗网杀手排名系统:暗网是一个不为人知的网络世界,在暗网中有10位臭名昭著的杀手,如果按照臭名值来排名,分别是:

​ 正序排列:105,98,73,58,32,31,25,22,3,1

​ 倒序排列:1,3,2,25,31,32,58,73,98,105

​ 现在我们要给一位新来的杀手插入到这个排名系统中去要求设计一个算法,要求用户输入一个值代表新杀手的臭名值,然后不管是正序排列,还是倒序排列,这个算法都能够正确的将新杀手的臭名值正确的排序到现有排序中去!并且打印出来比如:用户输入97则输出:

105,98,97,73,58,32,31,25,22,3,1或者是1,3,22,25,31,32,58,73,98,105

!

#include <iostream>

int main()
{
	//int a[10]{ 105,98,73,58,32,31,25,22,3,1 };
	int a[10]{ 1,3,22,25,31,32,58,73,98,105 };
	int acount = sizeof(a) / sizeof(int);       //计算数组a的元素个数
	int* anew = new int[acount + 1];         //新的数组

	int killer;
	std::cout << "请输入新杀手的臭名值:";
	std::cin>> killer;

	int getIndex{ acount };       //插入的索引位置
	
	if (a[0] > a[1])
	{
		for (int i = 1; i < acount; i++)
		{
			if (killer > a[i])
			{
				getIndex = i;
				break;
			}
		}
	}
	if (a[0] < a[1])
	{
		for (int i = 1; i < acount; i++)
		{
			if (killer < a[i])
			{
				getIndex = i;
				break;
			}
		}
	}
	memcpy(anew, a, getIndex * sizeof(int));  //拷贝插入位置之前的数据
	memcpy(anew + getIndex + 1, a + getIndex, (acount - getIndex)*sizeof(int));  //拷贝插入位置之后的数据
	anew[getIndex] = killer;
	for (int i = 0; i <= acount; i++)
	{
		std::cout << anew[i] << std::endl;
	}
	//std::cout << getIndex << std::endl; 
}

十二、指针和引用(二)

//上述代码优化(实现效果一致)
#include <iostream>

int main()
{
	//int a[10]{ 105,98,73,58,32,31,25,22,3,1 };
	int a[10]{ 1,3,22,25,31,32,58,73,98,105 };
	int acount = sizeof(a) / sizeof(int);       //计算数组a的元素个数
	int* anew = new int[acount + 1];         //新的数组

	int killer;
	std::cout << "请输入新杀手的臭名值:";
	std::cin >> killer;

	int getIndex{ acount };       //插入的索引位置

	bool bcase = a[0] > a[1];           //代码优化

	for (int i = 0; i < acount; i++)
	{
		if (bcase ^ (killer < a[i]))
		{
			getIndex = i;
			break;
		}

	}
	memcpy(anew, a, getIndex * sizeof(int));  //拷贝插入位置之前的数据
	memcpy(anew + getIndex + 1, a + getIndex, (acount - getIndex) * sizeof(int));  //拷贝插入位置之后的数据
	anew[getIndex] = killer;
	for (int i = 0; i <= acount; i++)
	{
		std::cout << anew[i] << std::endl;
	}
	//std::cout << getIndex << std::endl; 
}


/*
for(int i=0;i<acount;i++)
{
	if(a[0]>a[1])
    {
        if(x>a[i])
        {
            getIndex = i;
            break;
        }
    }
    else
    {
        if(x<a[i])
        {
            getIndex=i;
            break;
        }
    }
}
*/
12、理解数组和指针

1)数组和指针

由于数组是利用指针来实现的,因此数组和指针有很多共通的功能,比如指针可以按照数组的方式来访问数据;

数组可以使用sizeof求占用内存大小,这个过程是由编译器实现的,实际运行过程中并不存在!

int a[5];
int c = sizeof(a);
006E17D8 mov dword ptr [c],14h

2)引用的本质

引用的本质其实就是一种被阉割了的指针,虽然我们取值引用变量得到的是原值的内存地址,但是引用变量也是占用内存的。

3)引用的分析

十二、指针和引用(二)

4)堆和栈

​ 堆的本质其实就是空闲内存,C++中把堆称为自由储存区,只要是你的程序加载后,没有占用的空闲内存,都是自由存储区,我们用new或者malloc申请一块新的内存区域,都是由操作系统从堆上操作。

​ 栈是程序在编译时就已经确定了大小的一段内存区域,主要是用于临时变量的存储,栈的效率要高于堆,但是容量有限。

13、技能系统(一)

1)技能系统

​ 需求:本次重新设计麟江湖的技能系统,技能是在游戏设计之处已经设计好的,游戏设计了十一种技能,属性如下:

技能 消耗内力 消耗怒气值 攻击力 冷却
普通工具 0 0 10+基础攻击 0
大力金刚指 10 0 50+基础攻击 1
云龙三观 10 0 60+基础攻击 1
一阳指 30 0 2*基础攻击 3
迎风破浪 30 0 300 3
八卦掌 50 0 5*基础攻击 4
六合八荒 50 0 500 4
仙人指路 100 0 10*基础攻击 6
横扫千军 100 0 50+2*基础攻击 6
气吞山河 0 100 500+5*基础攻击 0
秋风到法 0 100 200+10*基础攻击 0

2)项目设计

​ 设计需求:每个角色随着等级不同,最少拥有一个技能,即普通攻击;最多拥有5个技能,技能拥有等级,技能等级每提升1级,角色的最终伤害提升15%,设计角色的属性面板,能够显示角色的属性和技能,角色属性根据需求自己发挥。文章来源地址https://www.toymoban.com/news/detail-746810.html

#include <iostream>

struct Skill                //定义技能结构体
{
	char Name[48]; //技能名称
	int Mpp; //内力消耗
	int Spp; //怒气
	int Act; //攻击力
	int ActB; //翻倍攻击
	int CoolDown; //冷却时间
};

struct USkill        //定义用户当前的技能
{
	Skill* skill{};
	int lv;
	int cooldown;
	bool buse{};
};

typedef struct Role
{
	char Name[48];
	int HP;
	int MaxHp;
	int MP;
	int MaxMp;
	int Sp;     //怒气值
	int MaxSp;
	int Act;    //普通攻击力
	USkill skills[5];   //每个角色最多5技能
}*PROLE;

int main()
{
	Skill AllSkills[11]
	{
		{"普通攻击",0,0,10,1,0},
		{"大力金刚指",10,0,50,1,1},
		{"云龙三观",10,0,60,1,1},
		{"一阳指",30,0,0,2,3},
		{"迎风破浪",30,0,300,0,3},
		{"八卦掌",50,0,0,5,4},
		{"六合八荒",50,0,500,0,4},
		{"仙人指路",100,0,0,10,6},
		{"横扫千军",100,0,50,2,6},
		{"气吞山河",0,100,500,5,0},
		{"秋分刀法",0,100,200,0,0}
	};

	PROLE User = new Role
	{
		"郝英俊",
		1000,1000,1000,1000,0,100,100,
		{
			{&AllSkills[0],0,0,true},
			{&AllSkills[1],0,0,true},
			{&AllSkills[2],0,0,false},
			{&AllSkills[3],0,0,false},
			{&AllSkills[10],0,0,true}
		}
	};

	PROLE Monster = new Role
	{
		"凹凸曼",
		1000,1000,1000,1000,0,100,100,
		{
			{&AllSkills[0],0,0,true},
			{&AllSkills[1],0,0,true},
			{&AllSkills[2],0,0,true},
			{&AllSkills[4],0,0,true},
			{&AllSkills[10],0,0,true}
		}
	};

	std::cout << "角色姓名:"<<User->Name << std::endl;
	std::cout << "生命:" << User->HP << "/" << User->MaxHp << std::endl;
	std::cout << "内力:" << User->MP << "/" << User->MaxMp << std::endl;
	std::cout << "怒气:" << User->Sp << "/" << User->MaxSp << std::endl;
	std::cout << "基本攻击:" << User->Act << std::endl;

	for (auto skill : User->skills)
	{
		if (skill.buse)
			std::cout
			<<"技能名称 ["<<skill.skill->Name<<"]"
			<< "消耗MP " << skill.skill->Mpp
			<< "消耗SP " << skill.skill->Spp
			<< "附加攻击 " << skill.skill->Act
			<< "翻倍攻击 " << skill.skill->ActB
			<< "冷却 " << skill.skill->CoolDown
			<< "技能等级 " << skill.lv
			<< std::endl;

	}
}

到了这里,关于十二、指针和引用(二)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C语言指针操作(五)通过指针引用多维数组

    多维数组的地址,通过指针引用多维数组详解。 通过指针引用一维数组可以参考这篇文章: C语言指针操作(三)通过指针引用数组 目录 一、多维数组的地址 1.1引入 1.2地址举例说明 1.3地址类型详解 1.4实例说明 二、指向多维数组元素的指针变量 2.1指向数组元素的指针变量

    2024年02月03日
    浏览(48)
  • 8.3 【C语言】通过指针引用数组

    所谓数组元素的指针就是数组元素的地址。 可以用一个指针变量指向一个数组元素。例如: int a[10]={1,3,5,7,9,11,13,15,17,19}; int *p; p=a[0]; 引用数组元素可以用下标法,也可以用指针法,即通过指向数组元素的指针找到所需的元素。 在指针已指向一个数组元素时,可以对指针进

    2024年02月12日
    浏览(45)
  • C++ — 指针和数组的关系?

    在本文中,您将了解数组与指针之间的关系,并在程序中有效地使用它们。 指针是保存地址的变量。指针不仅可以存储单个变量的地址,还可以存储数组单元的地址。 看以下示例:         假设指针需要指向数组的第四个元素,即在上述情况下的第四个数组元素的保存地

    2024年02月07日
    浏览(44)
  • 【C语言】指针的入门篇2,深入理解指针和数组的关系

    欢迎来CILMY23的博客喔,本期系列为【C语言】指针的入门篇2,深入理解指针和数组的关系,图文讲解指针和数组关系的知识,带大家理解指针和数组的关系,以及指针+数组的用法,感谢观看,支持的可以给个赞哇。 前言 在上一篇博客中,我们了解了指针就是地址,并且把地

    2024年02月20日
    浏览(51)
  • 【C语言初阶】指针的运算or数组与指针的关系你了解吗?

    🎬 鸽芷咕 :个人主页  🔥 个人专栏 :《快速入门C语言》《C语言初阶篇》 ⛺️生活的理想,就是为了理想的生活!    🌈 hello! 各位宝子们大家好啊,前面给大大家介绍了指针的基础知识。那么这一章就来给大家介绍下一部分内容!    ⛳️ 指针的运算 以及 数组与指

    2024年02月16日
    浏览(38)
  • C语言指针(适合C语言进阶者):一道题带你深入理解数组与指针的关系

    🎈个人主页:JAMES别扣了 💕在校大学生一枚。对IT有着极其浓厚的兴趣 ✨系列专栏目前为C语言初阶、后续会更新c语言的学习方法以及c题目分享. 😍希望我的文章对大家有着不一样的帮助,欢迎大家关注我,我也会回关,大家一起交流一起互动,感谢大家的多多支持哈! 🎉

    2024年04月16日
    浏览(54)
  • C# 使用SIMD向量类型加速浮点数组求和运算(4):用引用代替指针, 摆脱unsafe关键字,兼谈Unsafe类的使用

    作者: zyl910 目录 一、引言 二、办法说明 2.1 历史 2.2 局部引用变量与引用所指的值(类似指针的 地址运算符 、间接运算符 * ) 2.3 重新分配局部引用变量(类似指针直接赋值) 2.4 引用地址调整(类似指针加减法) 2.5 引用地址比较(类似指针比较) 2.6 重新解释(类似C++的

    2024年02月15日
    浏览(43)
  • 指针的指针 ok, 引用的引用 no ---- 理解引用折叠

           我们都知道,在C/C++中,出现指针的指针,也就是二级指针的场景是合法的,甚至可以是更多级的指针,都是ok的;但是如果出现了引用的引用,那绝对是非法操作,任何一款C/C++的编译器都很乐意为您检测出此类非法操作。既然会讨论这个问题,说明 引用的引用 这样

    2024年02月07日
    浏览(34)
  • 离散数学(十二):关系的幂运算与关系的性质

    1)幂运算的定义  2)幂运算的求法   幂运算有两种求法,基于矩阵的方法和基于关系图的方法。我们之前学过关系的表示方法有三种:集合、矩阵、关系图。那么同样,这些方式也可以运用于关系的计算中。 需要的注意的是,基于关系图的运算是具有物理意义的,以R2为例

    2024年02月08日
    浏览(44)
  • 【C++】C++ 引用详解 ⑦ ( 指针的引用 )

    指针的引用 效果 等同于 二级指针 , 因此这里先介绍 二级指针 ; 使用 二级指针 作为参数 , 可以实现如下功能 : 动态内存管理 : 借助二级指针 , 可以在函数中分配或释放内存 ; 如 : 创建一个动态数组或调整现有数组的大小 , 在函数中需要一个指向指针的指针作为参数 , 以便修

    2024年02月11日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包