模塊化思想——C++函數的魅力(一)


或許有一天c++系列能全部更新完,但是這裏纔是我寫c++筆記的起點,本人也是邊學邊寫,理解方面肯定會有很多問題存在,會盡量慢慢琢磨修改,有問題的地方也希望大家批評指出。
參考書目《C++ primer plus》
《C++語言程序設計 鄭莉》
《C++語言描述,數據結構與算法》

  • 綜述:函數是模塊劃分的基本單位,在面向過程程序設計中,函數是某一過程的抽象,在面向對象程序設計中,函數是某一功能的抽象,函數編寫好後只關心函數的功能而不關心函數的內容,有利於分工合作和開發效率

函數的定義和使用

  • 函數是一個子程序,是程序塊,main函數是程序執行的開始點,函數之間可相互調用。
  • 可結合程序的機器級表示學習函數調用的底層知識

函數的定義

return_value fun_name(parameter){
	body
}

😈 形式參數表(parameter)
複製構造函數&析構函數
什麼是表?不是形容人的,而是用逗號分開的序列

  • 形參是主調函數和被調函數的聯繫,
  • 命令行參數:main函數的形參,作爲操作系統啓動程序時初始化
  • 形參被稱爲傀儡,在沒有調用時就是一個符號,只有調用後才能由主調函數將實際參數賦予形參
    😈 函數的返回值和返回值類型
    1 結束當前函數的執行
    2 函數的返回值由return語句給出
    3 也可以不帶返回值,函數僅僅實現一種操作

函數的調用

函數名(實參表)
😈 函數的原型(函數聲明)
返回值 函數名(形參表);
函數聲明不會產生任何代碼,只是將函數的有關信息告訴編譯器
編譯器根據函數原型對函數調用進行檢查,判斷是否符合要求。

  • 實參和形參相對應
  • 函數作爲參數進行調用
    ⭐實例:將二進制轉化爲十進制
#include<iostream>
double power(double x, int n);
using namespace std;
int main() {
	cout << "Please enter an 8 bit binary number:";
	int dem = 0;
	for (int i = 7; i >=0; i--) {
		char bit;
		cin >> bit;
		if(bit=='1')
		dem +=  power(2, i);
	}
	cout << "Decimal value is " << dem << endl;
	return 0;
}
double power(double x, int n) {
	double result = 1;
	for (int i = 1; i <= n; i++) {
		result *= x;
	}
	return result;
}

在這裏插入圖片描述

針對本程序的一些解釋

  • 爲什麼選擇輸入char類型,插入類型一次只讀入一個字符,如果我們按int類型輸入相應位,就需要用換行或空格的方式告訴程序此次輸入結束,當我們使用char類型,輸入一串位串後,輸入流裏就存在這些數字,一次只讀取一個數字,即使輸入很多,也會按從左往右的順序按位讀取(與輸入流有關的知識會專門寫博客講解)
  • 注意到在結果相加之前有個判斷語句if(bit=='1'),如果我們直接使用dem+=bit*power(2,i);會出現錯誤,這裏bit會按照int類型解釋,就會將其ASCII碼作爲bit的值。
    ⭐實例:將一個數翻轉
bool judge(int x) {
	int m = 0;
	int n = x;
	while (x > 0) {
		m = m * 10 + x % 10;
		x /= 10;
	}
	return m == n;
}

⭐實例:隨機數:投骰子的隨機遊戲

  • 隨機函數:int rand(void)產生僞隨機數,按照一個既定的序列產生數字,rand函數需要一個稱爲種子的初始值,不同的種子隨機數序列不同,不設置種子其默認值爲1,調用函數void srand (unsigned int seed)爲其設置種子。
  • 產生隨機數需要頭文件#include<cstdlib>
    程序設計的過程
    審題分析→設計算法→寫程序

嵌套調用

遞歸調用

  • 將問題進行分簡,出現的新問題是原有問題簡化的子集
  • 只有有限的階乘纔有意義
  • 遞歸的過程
    1 遞推:將問題分解爲子問題,從未知向已知推進,達到已知的條件
    2 迴歸:根據遞歸過程逐一求值迴歸
    ⭐實例:用遞歸法計算從n個人中選擇k個人組成一個委員會的不同組合數
    從n個人裏面選k個人=從n-1個人裏面選k-1個人+從n-1個人裏面選k個人
    經典實例:漢諾塔問題

函數的參數傳遞

  • 形參:函數未被調用時,形參不具有實際空間和實際的值,函數調用時將實參和形參結合
    😈 形實結合(可結合計算機系統系列過程部分講解)
    ⭐值傳遞
    當函數調用時,爲形參分配內存空間,並用實參初始化形參,單向傳遞。形參的值變化對實參不起作用
    ⭐引用傳遞
    引用是一種特殊類型的變量,被認爲是另一個變量的別名

int i,j;
int &ri=i;

  • 聲明引用時,必須對其進行初始化,使它指向一個已存在的對象
  • 一旦引用被初始化,就不能指向其他對象
    引用一旦誕生,就確定了一個對象,且一生只爲一個對象
    ⭐實例:交換數值
#include<iostream>
using namespace std;
void swap(int &x, int & y);
int main() {
	int x = 10, y = 5;
	int &rx = x;
	int &ry = y;//也可以不定義引用,直接在函數原型和定義中說明引用類型,可直接轉換爲引用
	swap(rx, ry);
	cout << x << " " << y;
	return 0;
}
void swap(int &x, int &y) { //參數爲引用類型
	int temp;
	temp = x;
	x = y;
	y = temp;
	return;
}

內聯函數

函數調用可提高開發效率,分塊解決問題,但是函數調用降低程序執行效率(尤其是遞歸函數),對於一些內容簡單的函數,調用函數的成本比使用函數內容的成本高得多

  • 內聯函數:內聯函數不是執行時調用,而是在編譯時直接嵌入對應的調用處,節省了參數傳遞,控制轉移等開銷(但是對於現在的編譯器,有了優化系統,沒有設置inline的函數也可能被編譯爲內聯,過於冗雜的函數可能被編譯器優化爲一般函數)
  • 通俗來講,與其每次爲了見小鬼去全國各地看他的演唱會,不如直接把他拐到家裏,省了路費和精力消耗。
  • inline return_type fun_name(parameter){body}
  • 以空間換時間短小精幹
  • 引用不是對象,引用並沒有在程序中佔據內存空間,故沒有地址的說法.

含可變參數的函數

  • 可變長度的形參表
  • 當實參類型都相同時,可以使用initializer_list
    initializer_list<string>ls;

帶默認參數值的函數

int add(int x=10,int y=6){
	return x+y;
}
int main(){
	int z=add(5);
	int p=add(2,6);
	return;
}
  • 有實參則用實參,無實參則用默認值
  • 有默認參數的形參在後邊,賦值所用實參先賦給列表前面
    在這裏插入圖片描述
  • 如果有函數原型,在函數原型中提供了默認值,在函數定義中不能有默認值,如果沒有函數原型,在定義中確定默認值

先寫到這裏吧,隨後根據primer plus上的內容再進行補充

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章