1. 程式人生 > >北京大學MOOC C++學習筆記(一)

北京大學MOOC C++學習筆記(一)

引用:

  • 定義引用時一定要將其初始化成引用某個變數。
  • 初始化後,它就一直引用該變數,不會再引用別的變量了。
  • 引用只能引用變數,不能引用常量和表示式。
double a = 4, b = 5;
double & r1 = a;
double & r2 = r1; // r2 也引用 a
r2 = 10;
cout << a << endl; //  輸出 10
r1 = b; // r1 並沒有引用b   等價於a = b;
cout << a << endl; // 輸出 5
  • 引用作為函式的返回值 
int n = 4;
int & SetValue() {  return n; }
int main()
{
SetValue() = 40;
cout << n;
return 0;
} // 輸出: 40
  • 常引用 :定義引用時,前面加const關鍵字,即為“常引用”
int n;
const int & r = n;
r 的型別是 const int &
  • 不能通過常引用去修改其引用的內容:
int n = 100;
const int & r = n;
r = 200; // 編譯錯
n = 300; // ok
  • 常引用和非常引用的轉換:

const T & 和T & 是不同的型別!!! T & 型別的引用或T型別的變數可以用來初始化const T & 型別的引用。 const T 型別的常變數和const T & 型別的引用則不能用來初始化T &型別的引用,除非進行強制型別轉換。

“const”關鍵字的用法:

  • 定義常量

const int MAX_VAL = 23 ; const string SCHOOL_NAME = "Peking University" ;

  • 定義常量指標

1 不可通過常量指標修改其指向的內容 int n,m; const int * p = & n; * p = 5; // 編譯出錯 n = 4; //ok p = &m; //ok,  常量指標的指向可以變化

2 不能把常量指標賦值給非常量指標,反過來可以 const int * p1; int * p2; p1 = p2; //ok p2 = p1; //error p2 = (int * ) p1; //ok, 強制型別轉換

3 函式引數為常量指標時,可避免函式內部不小心改變引數指標所指地方的內容 void MyPrintf( const char * p ) { strcpy( p,"this"); // 編譯出錯 printf("%s",p); //ok }

  • 定義常引用

不能通過常引用修改其引用的變數 int n; const int & r = n; r = 5; //error n = 4; //ok

動態記憶體分配:

  • 用new 運算子實現動態記憶體分配
  • 第一種用法,分配一個變數:

P = new T; T是任意型別名,P是型別為T * 的指標。 動態分配出一片大小為 sizeof(T)位元組的記憶體空間,並且將該記憶體空間的起始地址賦值給P。比如: int * pn; pn = new int; * pn = 5;

  • 第二種用法,分配一個數組:

P = new T[N]; T :任意型別名 P :型別為T * 的指標 N :要分配的陣列元素的個數,可以是整型表示式 動態分配出一片大小為 sizeof(T)*N位元組的記憶體空間,並且將該記憶體空間的起始地址賦值給P。

  動態分配陣列示例:

int * pn;
int i = 5;
pn = new int[i * 20];
pn[0] = 20;
pn[100] = 30; //編譯沒問題。執行時導致陣列越界
  • 用delete運算子釋放動態分配的記憶體

用“new”動態分配的記憶體空間,一定要用“delete”運算子進行釋放 delete 指標;//該指標必須指向new出來的空間 int * p = new int; * p = 5; delete p; delete p;  //導致異常,一片空間不能被delete多次

用“delete”釋放動態分配的陣列,要加“[]” delete [ ] 指標;//該指標必須指向new出來的陣列 int * p = new int[20]; p[0] = 1; delete [ ] p;

行內函數、函式過載、函式預設引數:

  • 行內函數:
  1. 函式呼叫是有時間開銷的。如果函式本身只有幾條語句,執行非常快,而且函式被反覆執行很多次,相比之下呼叫函式所產生的這個開銷就會顯得比較大。
  2. 為了減少函式呼叫的開銷,引入了行內函數機制。編譯器處理對行內函數的呼叫語句時,是將整個函式的程式碼插入到呼叫語句處,而不會產生呼叫函式的語句。
inline int Max(int a,int b)
{
if( a > b) return a;
return b; 
}

函式過載:

一個或多個函式,名字相同,然而引數個數或引數型別不相同,這叫做函式的過載。

以下三個函式是過載關係:

int Max(double f1,double f2) { }

int Max(int n1,int n2) { }

int Max(int n1,int n2,int n3) { }

函式過載使得函式命名變得簡單。

編譯器根據呼叫語句的中的實參的個數和型別判斷應該呼叫哪個函式。

(1) int Max(double f1,double f2) { }

(2) int Max(int n1,int n2) { }

(3) int Max(int n1,int n2,int n3) { }

Max(3.4,2.5); // 呼叫 (1)

Max(2,4); // 呼叫 (2)

Max(1,2,3); // 呼叫 (3)

Max(3,2.4); //error,

  • 函式的預設引數:

C++中,定義函式的時候可以讓最右邊的連續若干個引數有預設值,那麼呼叫函式的時候,若相應位置不寫參 數,引數就是預設值。 void func( int x1, int x2 = 2, int x3 = 3) { } func(10 ) ; // 等效於 func(10,2,3) func(10,8) ; // 等效於 func(10,8,3) func(10, , 8) ;  // 不行,

函式引數可預設的目的在於提高程式的可擴充性。

即如果某個寫好的函式要新增新的引數,而原先那些呼叫該函式的語句,未必需要使用新增的引數,那麼為了避免對原先那些函式呼叫語句的修改,就可以使用預設引數。