默認的傳值,即在函數被調用的時候,給形參申請一個空間,再將實參的值傳遞給形參,對形參的任何改變不會影響實參數的值:
#includeusing namespace std; #define ok 0 int add(int x) { cout << "調用前的形式參數所在地址,如果和實參地址一樣說明新申請了內存空間" << &x << endl; cout << "變化前的形式參數值" << x << endl; x++; cout << "變化後的形式參數值" << x << endl; cout << "調用後的形式參數所在地址" << &x << endl; return ok; } int main() { int a = 1; cout << "調用前的實在參數所在地址,如果和形參地址一樣說明新申請了內存空間" << &a << endl; cout << "調用前的實在參數值" << a << endl; add(a); cout << "調用後的實在參數值" << a << endl; cout << "調用後的實在參數所在地址" << &a << endl; return ok; }
輸出結果如下:
可以看到形參實參的地址不一樣,說明新申請了內存空間,大小剛好為int數據的4個字節。
注:x是在函數內部定義的變量因而其作用范圍是局部的(僅在該函數范圍內能被調用)0,生命周期是動態的(調用該函數時候創建,函數調用完成後就消除。)
所謂傳址又叫做傳指針,即在函數被調用的時候,給形參開辟一個空間用來存放傳遞過來的地址,將實參所在的內存地址傳遞給形參,對形參的任何改變也不會影響實參所指的內容,但是對形參所指的內容的改變將會影響到實參所指的內容(因為這兩個指針都指向同一個內存空間)
#includeusing namespace std; #define ok 0 int add(int *x) { cout << "指針x所在的地址,和指針a所在地址比較,如果相同說明函數調用時,沒有重新開辟內存空間,反之則開辟了內存空間用以存儲傳來的地址" << &x << endl; cout << "指針x的值" << x << endl; cout << "指針x所指的值" <<* x << endl; x++; cout << "指針x變化後的指針x的值" << x << endl; cout << "指針x變化後的指針x所指的值" << *x << endl; return ok; } int main() { int c = 1; int *a = &c; cout <<"調用前指針a所在的地址"<< &a<
運行下結果如下: 指針a和指針x所在地址不同說明新申請內存空間用以存放傳來的地址。 對指針x的值的改變不會改變指針a的值,也不會改變指針a所指的值,所以輸出結果為0。
#includeusing namespace std; #define ok 0 int add(int *x) { cout << "指針x所在的地址,和指針a所在地址比較,如果相同說明函數調用時,沒有重新開辟內存空間,反之則開辟了內存空間用以存儲傳來的地址" << &x << endl; cout << "指針x的值" << x << endl; cout << "指針x所指的值" << *x << endl; (*x)++; cout << "指針x的所指的內容變化後的指針x的值" << x << endl; cout << "指針x所指的內容變化後指針x所指的值" << *x << endl; return ok; } int main() { int c = 1; int *a = &c; cout << "調用前指針a所在的地址" << &a << endl; cout << "調用前指針a的值(也就是變量c的內存地址)" << a << endl; cout << "調用前指針a所指的值" << *a << endl; add(a); cout << "調用後指針a所在的地址" << &a << endl; cout << "調用後指針a的值(也就是變量c的內存地址)" << a << endl; cout << "調用後指針a所指的值" << *a << endl; return ok; }
運行結果如下: 指針a和指針x所在地址不同說明新申請內存空間用以存放傳來的地址。 對指針x所指的值的改變會改變指針a所指的值。所以輸出結果為2。
引用是什麼?c++中的引用可以理解為typedef的作用(c中是沒有此用法),引用相當於是實參的別名,對形參的任何操作,就是對實參的操作,函數調用時不會再內存中新開辟空間。
#includeusing namespace std; #define ok 0 int add(int &x) { cout << "x所在的地址,和a所在地址比較,如果相同說明函數調用時,沒有重新開辟內存空間,反之則開辟了內存空間" << &x << endl; cout << "x的值" << x << endl; x++; cout << "x的變化後的值" << x << endl; cout << "x變化後的地址" << &x << endl; return ok; } int main() { int a = 1; cout << "調用前a所在的地址" << &a << endl; cout << "調用a的值" << a << endl; add(a); cout << "調用後a所在的地址" << &a << endl; cout << "調用後a的值" << a << endl; return ok; }
運行結果如下: 可以看到實參和形參的地址是相通的,也就是說並沒有開辟一個新的空間。
其形式為function(數據類型 *&指針名),這裡的指針名就是引用,就是傳來的指針的別名。對它的操作就是對實參的操作,對它所指的值的操作,就是對實參所指的值的操作。
#includeusing namespace std; #define ok 0 int add(int *&x) { cout << "指針x所在的地址,和指針a所在地址比較,如果相同說明函數調用時,沒有重新開辟內存空間,反之則開辟了內存空間用以存儲傳來的地址" << &x << endl; cout << "指針x的值" << x << endl; cout << "指針x所指的值" << *x << endl; x++; cout << "指針x變化後的指針x的值" << x << endl; cout << "指針x變化後的指針x所指的值" << *x << endl; return ok; } int main() { int c = 1; int *a = &c; cout << "調用前指針a所在的地址" << &a << endl; cout << "調用前指針a的值(也就是變量c的內存地址)" << a << endl; cout << "調用前指針a所指的值" << *a << endl; add(a); cout << "調用後指針a所在的地址" << &a << endl; cout << "調用後指針a的值(也就是變量c的內存地址)" << a << endl; cout << "調用後指針a所指的值" << *a << endl; return ok; }
運行結果如下: 可以看到調用時沒有在內存中開辟空間存儲傳遞來的地址。 對形參的改變就是對實參的改變。
#includeusing namespace std; #define ok 0 int add(int *&x) { cout << "指針x所在的地址,和指針a所在地址比較,如果相同說明函數調用時,沒有重新開辟內存空間,反之則開辟了內存空間用以存儲傳來的地址" << &x << endl; cout << "指針x的值" << x << endl; cout << "指針x所指的值" << *x << endl; (*x)++; cout << "指針x變化後的指針x的值" << x << endl; cout << "指針x變化後的指針x所指的值" << *x << endl; return ok; } int main() { int c = 1; int *a = &c; cout << "調用前指針a所在的地址" << &a << endl; cout << "調用前指針a的值(也就是變量c的內存地址)" << a << endl; cout << "調用前指針a所指的值" << *a << endl; add(a); cout << "調用後指針a所在的地址" << &a << endl; cout << "調用後指針a的值(也就是變量c的內存地址)" << a << endl; cout << "調用後指針a所指的值" << *a << endl; return ok; }
運行結果如下: 可以看到調用時沒有在內存中開辟空間存儲傳遞來的地址。 對形參所指內容的改變就是對實參所指內容的改變。
###5.1一般時候對傳入的實參如果要做改變優先考慮傳引用(也可以傳址,然後對指針所指內容做改變,但對變量的操作相對對指針的操作一般要更容易思考一些)或者傳入的數據非常大時候,調用函數時可以節約拷貝的時間和空間;如果對傳入的實參不做改變可以傳值也可傳指針。 ###5.2傳引用有些時候可以避免未初始化的錯誤。
#includeusing namespace std; #define ok 0 struct linknode { int data; linknode *next; }; typedef linknode linklist; int initlist(linklist *L) { L = (linknode*)malloc(sizeof(linknode)); return ok; } int main() { linklist *L; initlist(L); }
這裡由於在主函數定義了指針變量L後沒有初始化賦值,因而出現未初始化的錯誤。將int initlist(linklist *L)改成int initlist(linklist *&L)就可以免於此錯誤。 ps:其原理以前我一直以為是定義之後未對其初始化因而調用函數時候傳遞的地址是不可知的,因而出錯。但是又發現如果在主函數中添加一行cout<<&L 不用使用引用也可以正常,並且此時L傳遞的地址仍然也是不可知的。
#includeusing namespace std; #define ok 0 struct linknode { int data; linknode *next; }; typedef linknode linklist; int initlist(linklist *L) { L = (linknode*)malloc(sizeof(linknode)); return ok; } int main() { linklist *L; cout<<&L initlist(L); }