《C++PrimerPlus 6th Edition》第7章 函數 要點記錄

《C++PrimerPlus 6th Edition》第7章 函數 要點記錄

  1. 要使用函數,必須完成如下工作:①提供函數原型;②提供函數定義;③調用函數

  2. C++對於返回值的類型有一定限制:不能是數組,但可以是其他任何類型——整數、浮點數、指針、甚至結構和對象(雖然C++函數不能直接返回數組,但可以將數組作爲結構或對象的組成部分來返回)

  3. 函數原型:比如:double add(double a, double b);
    需要函數原型的原因:①原型描述了函數到編譯器的接口,也就是說,它將函數返回值的類型(如果有的話)以及參數的類型和數量告訴編譯器;②如果不定義函數原型,編譯器就需要在文件中查找被調用函數,這往往效率不高,因爲編譯器在搜索文件的剩餘部分時必須停止對main()的編譯;③更嚴重地是,函數甚至可能並不在文件中;④C++允許將一個程序放在多個文件中,單獨編譯這些文件,然後再將它們組合起來,這種情況下,編譯器在編譯main()時,可能無權訪問函數代碼
    避免使用函數原型的唯一方法是,在首次使用前定義它,但這並不總是可行的。C++的編程風格是將main()放在最前面,因爲它通常提供了程序的整體結構

  4. 函數原型不要求提供變量名,即使提供變量名也不要求原型中的變量名與定義中的變量名相同

  5. C++原型與ANSI C原型的比較:①ANSI C中的原型是可選的,但在C++中原型必不可少; ②對於void say_hi();在C++中,括號爲空與在括號中使用void是等效的——意味着函數沒有參數;但在ANSI C中,括號爲空意味着不指出參數——這意味着將在後面定義參數列表;③C++中,不指定參數列表時應使用省略號void say_bye(...);,這通常僅當與接受可變參數的C函數(如printf())交互時才需要這樣做

  6. 原型的功能:原型確保:①編譯器正確處理函數的返回值;②編譯器檢查使用的參數數目是否正確;③編譯器檢查使用的參數類型是否正確

  7. 自動類型轉換並不能避免所有可能的錯誤。當較大的類型被自動轉換爲較小的類型時,有些編譯器將發出警告,指出這可能丟失數據

  8. 僅當有意義時,原型化纔會導致類型轉換。比如,原型不會將整數轉換爲結構或指針

  9. 在編譯階段進行的原型化被稱爲靜態類型檢查(static type checking),它可捕獲許多在運行階段非常難以捕獲的錯誤

  10. C++標準使用參數(argument)來表示實參,使用參量(parameter)來表示形參

  11. 對於類似排列組合等以乘除爲主的迭代計算,爲了避免超越存儲範圍,可以將乘除運算交替進行

  12. 有些C++實現不支持long double類型,如果這樣則使用double或另想辦法

  13. 在C++中,當且僅當用於函數頭或函數原型中,int* arrint arr[]的含義纔是相同的,它們都意味着arr是一個int指針。然而,數組表示法(int arr[])提醒用戶,arr不僅指向int,還指向數組中的第一個int

  14. 傳遞常規變量時——按值傳遞;傳遞數組時——引用傳遞。實際上這種區別並不違反C++按值傳遞的方法,對於傳遞數組,實際上傳遞的是數組的首元素地址,也是一個值,此值傳遞給了一個指針,只不過通過這個值可以對相應元素進行修改

  15. 字符串與其他數組作爲實參傳遞給函數時的區別:①對於非字符串類型的數組,必須額外提供一個參數指出數組長度,而字符串可以通過'\0'來識別串尾,無需額外提供這種參數

  16. 如果傳入函數的數組需要填充或修改,則不用const修飾;如果只是讀取數組的內容而不修改,則可使用const實現對數組的保護,如顯示數組:void show(const double str[], int n);填充數組:int fill(double str[], int limit);

  17. 可以把非常量指針的值賦給常量指針const type*,但反過來不行:因爲如果可以反過來,意味着被賦予值的非常量指針可以對變量值進行修改,這樣const也就沒意義了。如果一定要這麼做,使用運算符const_cast

  18. 關於常量指針的幾個微妙問題
    pt的聲明並不意味着它指向的值實際上就是一個變量,而只是意味着對pt而言,這個值是常量。可以直接通過age變量來修改age的值,但不能使用pt指針來修改它

    int age = 39;
    const int* pt = &age;
    *pt = 20; //INVALID
    age = 20; //VALID
    

    進入兩級間接關係時,與一級間接關係一樣將const和非const混合的指針賦值方式將不再安全。如果允許這麼做,那麼就會有以下代碼:

    const int** pp2;
    int* p1;
    const int n = 13;
    pp2 = &p1; //not allowed, but suppose it were
    *pp2 = &n; //valid 
    *p1 = 10; // valid, but changes const n
    

    僅當只有一層間接關係時,纔可以將非const地址或指針賦給const指針

  19. 儘可能使用const的理由:①可以避免由於無意間修改數據而導致的編程錯誤;②使用const使得函數能夠處理const和非const實參,否則將只能接受非const數據

  20. 對於void show_array(const double ar[], int n);,這裏的數組元素是基本類型,但如果是指針或指向指針的指針,則不能使用const

  21. 函數與二維數組:以下表示二維數組的都等價:int sum(int (*ar2)[4],int size);int sum(int ar2[][4],int size); 由於其中的ar2相當於指向指針的指針,故沒有使用const

  22. 變量pstr的作用域爲buildstr函數內,因此該函數結束時,pstr(而不是字符串)使用的內存將會被釋放,但由於函數返回了pstr的值,因此程序仍可以通過main()中的指針ps來訪問新建的字符串。

    char* buildstr(char c,  int n){
       char* pstr = new char[n+1];
       pstr[n] = '\0';
       while(n-->0){
       	pstr[n] = c;
       }
       return pstr;
    }
    
  23. 函數與結構:與數組名就是數組的數組的第一個元素不同的是,結構名只是結構的名稱,要獲得結構的地址,必須使用地址運算符&

  24. string作爲傳遞給函數的實參時,是按值傳遞;模板array也是如此

  25. 模板array並非只能存儲基本數據類型,它還可以存儲類對象

  26. 函數指針使用流程:①獲取函數的地址;②聲明一個函數指針;③使用函數指針來調用函數

  27. 注意:對於函數指針pf,如double (*pf)(int);,以下兩種使用方法都可以:①double x =(*pf)(5);double x =pf(5);

  28. 可以使用auto或typedef對類型名字進行簡化,這裏我給出本章習題10的代碼,基本就是函數指針的典型用法了,可以自行體會

#include<iostream>
#include<cstdlib>
using namespace std;

typedef double (*calc_fun)(double,double);

double add(double,double);
double sub(double,double);
double multiply(double,double);
double divide(double,double);
double calculate(double,double,calc_fun);

int main(){
	calc_fun pf[4]{add, sub, multiply, divide};
	double x,y;
	cout<<"Please enter x and y (q to quit): ";
	const char* calc_means[4]{"A+B= ","A-B= ","A*B= ","A/B= "};
	while(cin>>x>>y){
		for(int i=0; i<4; ++i){
			cout<<calc_means[i];
			cout<<(*pf[i])(x,y)<<endl;
		}
		cout<<"Next Round enter x and y (q to quit): ";
	}
	cout<<"Done\n";
	return 0;
} 

double add(double a, double b){
	return a+b;
}

double sub(double a, double b){
	return a-b;
}

double multiply(double a, double b){
	return a*b;
}
double divide(double a, double b){
	if(b == 0.0){
		cout<<"Cannot devide By Zero!\n";
		exit(-1);
	}
	return a / b;
}	
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章