十二、指針和引用(二) 1、指針和數組的關係 1)思考 假設你要設計一種編程語言,你要如何實現數組呢?思考之前請先牢記:數組在記憶體中是連續的,維度由低到高(大部分操作系統下)。 2)彙編分析數組如何實現 //C++代碼 #include <iostream> int main() { int a ...
十二、指針和引用(二)
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%,設計角色的屬性面板,能夠顯示角色的屬性和技能,角色屬性根據需求自己發揮。
#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;
}
}