十八、函數(一)

来源:https://www.cnblogs.com/piaolaipiaoqu/archive/2023/11/28/17863473.html
-Advertisement-
Play Games

十八、函數(一) 1、函數概述 1)函數帶來的好處 ①代碼模塊化,便於閱讀維護 ②代碼模塊化以後,能夠實現分工合作 ③減少重覆代碼,降低工作流 2)函數的語法 //函數的語法 返回類型 函數名稱(參數,參數,參數,參數) //參數的語法包括:參數類型 參數名稱 { 函數的功能區; return 返回 ...


十八、函數(一)

1、函數概述

1)函數帶來的好處

①代碼模塊化,便於閱讀維護

②代碼模塊化以後,能夠實現分工合作

③減少重覆代碼,降低工作流

2)函數的語法

//函數的語法
返回類型 函數名稱(參數,參數,參數,參數)  //參數的語法包括:參數類型 參數名稱
{
    函數的功能區;
    return 返回值;
}

//函數的聲明示範一
int Add(int a,int b)
{
    return a+b;
}
使用:
int a=Add(100,200);   //a=300

//函數的聲明示範二
void PrintLog(char *str)
{
    std::cout<<"日誌:"<<str;
}
使用:
Printlog("你好世界!");
//函數的聲明示例
// 函數一.cpp : 此文件包含 "main" 函數。程式執行將在此處開始並結束。
//

#include <iostream>

int Add(int a, int b)   //函數的聲明
{
    return a + b;       ////返回的是什麼類型的值,就用什麼類型接受
}
//不需要返回值的函數,使用的返回類型為void
void PrintEnding(const char* str,int x)
{
    std::cout << str << x << std::endl;
}

int main()
{
   int x{ Add(100, 100) };  //函數的使用
   PrintEnding("生命值:",x);
   x =Add(200,300);
   PrintEnding("內力值:",x);
}

註:每個函數都必須有return函數返回值,main()函數編譯器會自動在函數結尾預設加一個return

//用函數實現游戲麟江湖排行榜設計修
//GetDataCount函數統計有幾個角色的信息
int GetDataCount(string str)
{
	int icount{};
	for (int i = 0; i < str.length(); i++)
	{
		if (str[i] == ';')
		{
			icount++;
			i += 3;
		}
	}
	return icount/2;
}

//獲取字元串中的數據
string GetDataStr(string str, int istart)
{
	string strReturn{};
	int iend{};
	istart = str.find("id=", istart);
	if (istart == std::string::npos) return strReturn;
	iend = str.find(";", istart + 3);
	strReturn = str.substr(istart + 3, iend - istart - 3);
	return strReturn;
	
}
2、函數參數之指針參數

函數分為三部分:包括函數的頭部、函數體、函數的尾部(一個函數有可能有很多尾部)、

函數頭中的變數只申請了記憶體空間、但是沒有賦值,沒有初始化

函數尾是為了返回值

//直接將實參傳遞給形參
#include <iostream>

int Add(int x, int y)  //形參
{
	x *= 100;
	y *= 100;
	return x + y;
}

int main()
{
	int x = 2, y = 1;
	int c = Add(x,y);  //實參
	std::cout << "c=" << c << "   x=" << x << "   y=" << y << std::endl;
}
//通過此種方式無法得到x和y變化後的結果

//向函數中傳入指針參數(將函數中的值讀取去出來,獲得回傳值)
#include <iostream>

int Add(int* x, int* y)  //形參
{
	(*x) *= 100;       //x和y次數是一個指針
	(*y) *= 100;
	return (*x) + (*y);
}

int main()
{
	int x = 2, y = 1;
	int c = Add(&x, &y);  //實參傳入x和y的記憶體地址
	std::cout << "c=" << c << "   x=" << x << "   y=" << y << std::endl;
}
//通過結果發現c的值沒有發生變化,但是x和y的值發生了變化。成為函數中最終計算的x和y的結果

2)指針參數的常見應用

​ 函數頭部中的形參在定義時,會分配整個結構體內部成員變數總和的記憶體空間,會存在記憶體空間開銷過剩的問題;但是如果函數頭部中傳入的參數為指針參數,那麼只需要分配指針大小的函數空間,即4位元組.

//不使用指針參數,給函數傳值
#include <iostream>

struct Role
{
	int Hp;
	int Mp;
};

int Exp(Role role)
{
	return role.Hp + role.Mp;
}

int main()
{
	Role role{ 500,1000 };
	int totle =Exp(role);  //看起來函數在調用時傳入了一個參數,但是實際上傳入了兩個參數
	std::cout << "角色戰鬥力為:" << totle << std::endl;
}

//通過指針參數,給函數傳值
#include <iostream>

struct Role
{
	int Hp;
	int Mp;
};

int Exp(Role* role)
{
	return role->Hp + role->Mp;     //不再使用.取實體,而是通過->偏移符號通過地址傳值
}

int main()
{
	Role role{ 500,1000 };
	int totle = Exp(&role);  //取地址
	std::cout << "角色戰鬥力為:" << totle << std::endl;
}
//通過此方式可大大提升效率

3)指針參數之常量指針用法

回顧:常量指針,表示指針指向的內容是一個常量,指針指向的內容不可以發生變化,即值可以讀,但不可以寫,防止修改數據

//初始化一個玩家和怪物,定義一個函數,返回一個bool值,當值為true的時候,說明角色死亡
#include <iostream>

struct Role
{
	int Hp;
	int Mp;
	int damage;
};

bool Exp(const Role* Acter, Role* beActer)  //攻擊者者和被攻擊者,攻擊者的屬性不能夠修改
{
	beActer->Hp -= Acter->damage;  //被攻擊者血量=被攻擊者血量-攻擊者傷害值
	return beActer->Hp <= 0;
}

int main()
{
	Role user{ 500,1000,1200 };
	Role monster{ 1500,1000,1000 };

	if (Exp(&monster, &user)) 
			std::cout << "角色死亡!" << std::endl;
	else 
		if (Exp(&user ,&monster))
			std::cout << "怪物死亡" << std::endl;
}
3、函數參數之數組參數

1)數組本質上就是一個指針,傳入數組參數時,要傳入數組的長度。提高如下兩種數組參數的定義方法

//傳入數組參數時,必須要傳入數組的長度
//數組參數方法一
Void Sort(int ary[],unsigned count)   //推薦
{
    for(int i=1;i<count;i++)
}
int main()
{
    int a[5]{ 2302,5212,3653,9480,5200 };
	Sort(a, 5);
}

//數組參數方法一
Void Sort(int* ary,unsigned count)   //推薦
{
    for(int i=1;i<count;i++)
}
int main()
{
    int a[5]{ 2302,5212,3653,9480,5200 };
	Sort(a, 5);
}
//將數組進行排序案例
#include <iostream>

void Sort(int ary[],unsigned count)   
{
		for (int i = 1; i < count; i++)
		{
			if (ary[i] > ary[i - 1])
			{
				int tmp = ary[i];
				ary[i] = ary[i - 1];
				ary[i - 1] = tmp;
			}
		}
}

int main()
{
	int a[5]{ 2302,5212,3653,9480,5200 };
	Sort(a, 5);
	for (auto x : a)std::cout << x << std::endl;
}

2)多維數組的傳參

//多維數組的傳參,無法寫成指針的形式
Void Sort(int ary[][2],unsigned count)   //推薦
{
    f
}
int main()
{
    int a[3][2]{{1,2},{3,4},{5,6}};
	Sort(a, 3);  //傳入數組的長度
}
4、函數參數之引用參數
//引用回顧
int a=5;
int &b = a;      //引用就相當於被閹割了的指針
則b++就相當於a++

1)引用也可以使用const進行限定只能讀,不能寫

#include <iostream>

struct Role
{
	int Hp;
	int Mp;
	int damage;
};

bool Exp(const Role& Acter, Role& beActer)  //引用,相當於Role& Acter = user;Role& beActer=monster
{
	beActer.Hp -= Acter.damage;  
	return beActer.Hp <= 0;
}

int main()
{
	Role user{ 5000,1000,12000 };
	Role monster{ 1500,1000,1000 };
	if (Exp(user, monster))std::cout << "怪物死亡,獲得經驗值XXX" << std::endl;
}

2)引用和指針的區別

引用要想使用,必須先得初始化;而指針可以先傳入一個空指針,先不進行初始化

//此種方式錯誤,引用必須初始化
bool Act(Role& Acter,Role& beAct)
{
    return true;
}
Act(nullptr,nullptr);

//指針可以不進行初始化
bool Act(Role* Acter,Role* beAct)
{
    return true;
}
Act(nullptr,nullptr);

3)指針類型的引用

//指針類型的引用
#include <iostream>

struct Role
{
	char name[0x20];
	int Hp;
	int Mp;
	int damage;
};

bool Exp(const Role& Acter, Role*& beActer)  //Role*指針類型的引用
{
	beActer->Hp -= Acter.damage;
	bool End = beActer->Hp < 0;
	beActer = (Role*)&Acter;  //通過指針類型的引用,可以修改參數的指向,此處將被攻擊者修改為攻擊者
	return End;
}

int main()
{
	Role user{ "奧特曼",5000,1000,12000 };
	Role monster{ "小怪獸",1500,1000,1000 };
	Role* pRole = &monster;
	if (Exp(user, pRole))std::cout << pRole->name<<"     怪物死亡,獲得經驗值XXX" << std::endl;
}

可以使用如下寫法

//指針類型的引用的其他寫法
#include <iostream>

typedef struct Role
{
	char name[0x20];
	int Hp;
	int Mp;
	int damage;
}*PROLE;     //Role類型的指針PROLE  

bool Exp(const Role& Acter, PROLE& beActer)  //Role類型指針PROLE的引用
{
	beActer->Hp -= Acter.damage;
	bool End = beActer->Hp < 0;
	beActer = (Role*)&Acter;  //通過指針類型的引用,可以修改參數的指向,此處將被攻擊者修改為攻擊者
	return End;
}

int main()
{
	Role user{ "奧特曼",5000,1000,12000 };
	Role monster{ "小怪獸",1500,1000,1000 };
	PROLE pRole = &monster;  ////Role類型指針PROLE
	if (Exp(user, pRole))std::cout << pRole->name<<"     怪物死亡,獲得經驗值XXX" << std::endl;
}
5、函數參數之預設實參

1)預設參數引入

//傳入一組數,對其進行排序
#include <iostream>

void Swap(int &a,int &b)  //定義函數專門用來交換兩個數
{
	int tmp = a;
	a = b;
	b = tmp;
}

void Sort(int ary[], unsigned count,bool BigSort)  //定義函數用來排序
{
	for(int i=1;i<count;i++)
	{ 
		bool bcase = BigSort ? ary[i] > ary[i - 1]:ary[i - 1] > ary[i];
		if (bcase)Swap(ary[i], ary[i - 1]);
	}
}

int main()
{
	int a[5]{ 2302,5212,3653,9480,5200 };
	Sort(a, 5,false);  //true表示從大到小排序,false表示從小到大排序
	for (auto x : a)std::cout << x << std::endl;
}

2)預設參數使用

​ 在函數調用時,若不傳遞值,則使用函數聲明時設置的預設參數。預設參數只可以放置在最後,不可以放置在最前面或中間;若有多個預設參數,需要依次寫在最後面

//預設參數使用
#include <iostream>

void Swap(int &a,int &b)
{
	int tmp = a;
	a = b;
	b = tmp;
}

void Sort(int ary[], unsigned count,bool BigSort=true)  //定義函數預設值參數
{
	for(int i=1;i<count;i++)
	{ 
		bool bcase = BigSort ? ary[i] > ary[i - 1]:ary[i - 1] > ary[i];
		if (bcase)Swap(ary[i], ary[i - 1]);
	}
}

int main()
{
	int a[5]{ 2302,5212,3653,9480,5200 };
	Sort(a, 5); //函數調用時,若不傳入參數,預設使用函數聲明時形參的預設值
	for (auto x : a)std::cout << x << std::endl;
}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 簡介 nodemon用來監視node.js應用程式中的任何更改並自動重啟服務,非常適合用在開發環境中。以前,我們開發一個node後端服務時,每次更改文件,均需重啟一下,服務才能生效。這使我們的開發效率降低了很多。nodemon的出現,可以隨時監聽文件的變更,自動重啟服務,我們開發時只需關註代碼即可, ...
  • 最近,相信大家一定被這麼個動效給刷屏了: 以至於,基於這個效果的二次創作層出不窮,眼花繚亂。 基於跨視窗通信的彈彈球: 基於跨視窗通信的 Flippy Bird: 我也嘗試製作了一個跨 Tab 視窗的 CSS 動畫聯動,效果如下: 代碼不多,核心代碼 200 行,感興趣的可以戳這裡:Github - ...
  • 專欄分享:vue2源碼專欄,vue3源碼專欄,vue router源碼專欄,玩具項目專欄,硬核💪推薦🙌 歡迎各位ITer關註點贊收藏🌸🌸🌸 Vue3中響應數據核心是 reactive , reactive 的實現是由 proxy 加 effect 組合,上一章節我們利用 proxy 實現了 ...
  • 自增自減運算符 1、基本使用 內置提供 ++、--運算符 是用於將變數本身進行加1或者減1操作 // 1、基本使用 var i = 10; i++;//等價於語句 i+=1 console.log(i);//11 var m = 10; m--; console.log(m) 2、前置與後置的區別 ...
  • 一、定義 定義一個語言的文法,並且建立一個解釋器來解釋該語言中的句子,這裡的“語言”是指使用規定格式和語法的代碼。解釋器模式是一種行為型模式。 二、描述 解釋器模式是一種使用頻率相對較低但學習難度較大的設計模式,它主要用於描述如何使用面向對象語言構成一個簡單的語言解釋器,包含以下四個角色: 1、Ab ...
  • 推薦一本日本網友Kenji Hiranabe寫的《線性代數的藝術》。這本書是基於MIT大牛Gilbert Strang教授的《每個人的線性代數》製作的。 雖然《線性代數的藝術》這本書僅僅只有12頁的內容,就把線性代數的重點全畫完了,清晰明瞭。 《線性代數的藝術》PDF版本:https://pan.q ...
  • 懶載入是Spring框架中的一個重要特性,它允許我們將bean的實例化推遲到第一次使用時。懶載入的主要用途是提高應用程式的啟動性能,減少不必要的資源消耗。 一、懶載入的用途 在大型的應用程式中,有些bean可能只在特定的條件下才會被使用到。如果在應用程式啟動時就實例化所有的bean,會導致啟動時間變 ...
  • 一、參考 https://ericniebler.com/2020/11/08/structured-concurrency/ 二、總結 1. 結構化併發是什麼-概述 是什麼:一種確保子操作在父操作之前完成的方式,類似函數在調用函數之前完成。 最典型的結構化併發:C++20的協程 意義:它通過使非同步 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...