第七講 指針與引用 (沒咋聽懂)
第七講 ?指針與引用
一 ?指 針
1 ?指針變量的定義與使用
指針的定義格式 格式: 目標數(shù)據(jù)對象類型 * 指針變量名稱; 例一:定義 p 為指向整數(shù)的指針:
int * p;
例二:定義 p 為指向結(jié)構(gòu)體類型的指針:struct POINT{ int x, y; }; POINT * p;
多個指針變量的定義 例三:
int * p, * q;
例四:typedef int * PINT; PINT p, q;
取址操作符“&” 獲取數(shù)據(jù)對象的地址,可將結(jié)果賦給指針變量 示例:
int n = 10; int * p; p = &n; int * q; q = p;
引領(lǐng)操作符“*” 獲取指針所指向的目標數(shù)據(jù)對象 例一: int m, n = 10; int * q = &n; m = *q; 使得 m 為 10 例二(接上例): *q = 1;使得 n 為 1 ?
指針的意義與作用 a.作為函數(shù)通信的一種手段 使用指針作為函數(shù)參數(shù),不僅可以提高參數(shù)傳遞效率, 還 可以將該參數(shù)作為函數(shù)輸出集的一員,帶回結(jié)果 b.作為構(gòu)造復雜數(shù)據(jù)結(jié)構(gòu)的手段 使用指針構(gòu)造數(shù)據(jù)對象之間的關(guān)聯(lián),形成復雜數(shù)據(jù)結(jié)構(gòu) c.作為動態(tài)內(nèi)存分配和管理的手段 在程序執(zhí)行期間動態(tài)構(gòu)造數(shù)據(jù)對象之間的關(guān)聯(lián) d.作為執(zhí)行特定程序代碼的手段 使用指針指向特定代碼段,執(zhí)行未來才能實現(xiàn)的函數(shù) ?
2 ?指針與函數(shù)
數(shù)據(jù)交換函數(shù)
例:編寫程序互換兩個整型數(shù)據(jù)對象的值,要求使用函數(shù)實現(xiàn)數(shù)據(jù)對象值的互換
?#include <iostream>
?using namespace std;
?void Swap( int * x, int * y );
?int main()
?{
?int m = 10, n = 20;
?#ifndef NDEBUG
?cout << "main (before swapped): m = " << m << "; n = " << n << endl;
?#endif
?Swap( &m, &n ); /* 調(diào)用Swap函數(shù)互換目標數(shù)據(jù)對象的值 */
?#ifndef NDEBUG
?cout << "main (after swapped): m = " << m << "; n = " << n << endl;
?#endif
?return 0;
?}
?void Swap( int * x, int * y )
?{
?int t;
?if( !x || !y ){
?cout << "Swap: Parameter(s) illegal." << endl;
?exit(1);
?}
?#ifndef NDEBUG
?cout << "Swap (before swapped): *x = " << *x << "; *y = " << *y << endl;
?#endif
?t = *x;
?*x = *y;
?*y = t;
?#ifndef NDEBUG
?cout << "Swap (after swapped): *x = " << *x << "; *y = " << *y << endl;
?#endif
?}
常量指針與指針常量
常量指針:指向常量的指針 性質(zhì):不能通過指針修改目標數(shù)據(jù)對象的值,但可以改變指針值,使其指向其他地方 示例一:
int n = 10; const int * p = &n;
典型使用場合:作為函數(shù)參數(shù),表示函數(shù)內(nèi)部不能修改指針所指向的目標數(shù)據(jù)對象值 示例二:void PrintObject( const int * p );
指針常量:指針指向的位置不可變化 性質(zhì):不可將指針指向其他地方,但可改變指針所指向的目標數(shù)據(jù)對象值 示例三:int n = 10; int * const p = &n;
指針常量和其他常量一樣,必須在定義時初始化 常量指針常量:指向常量的指針常量(指針的雙重只讀屬性) 性質(zhì):指針值不可改變,指向的目標數(shù)據(jù)對象值也不可改變 示例四:const int n = 10; const int * const p = &n;
典型使用場合:主要作為函數(shù)參數(shù)使用 ?
返回指針的函數(shù)
指針類型可以作為函數(shù)返回值 函數(shù)內(nèi)部返回某個數(shù)據(jù)對象的地址 調(diào)用函數(shù)后將返回值賦值給某個指針 特別說明: 不能返回函數(shù)內(nèi)部定義的局部變量地址 程序示例
int global = 0;
int * ReturnPointer()
{
return &global;
}
3 ?指針與復合數(shù)據(jù)類型 ?
指針與數(shù)組 數(shù)據(jù)對象地址的計算指針關(guān)系運算 可以測試兩個指針是否相等 例一:設(shè) p、 q 為指針,則 p == q 測試兩個指針是否指向同一個目 標數(shù)據(jù)對象 空指針: NULL 指針值 0:表示指針不指向任何地方,表示為 NULL 例二:設(shè) p 為指針,則 p = NULL 表示 p 不指向任何目標數(shù)據(jù)對象 例三(測試指針 p 是否有意義): if( p != NULL ) 等價于 if( p ) 使用指針前一定要測試其是否有意義! ?
作為函數(shù)參數(shù)的指針與數(shù)組
指針與數(shù)組的可互換性
多維數(shù)組參數(shù)的傳遞
指針與結(jié)構(gòu)體 指向結(jié)構(gòu)體的指針 指針作為結(jié)構(gòu)體類型的成員 ?
二 ?字符串
字符數(shù)組
字符數(shù)組的定義:與普通數(shù)組定義格式相同 示例:
char s[9] = { 'C', 'P', 'P', '-', 'P', 'r', 'o', 'g' ,‘/0’};
字符指針
字符串整體
C標準字符串庫:
"cstring"
C++字符串類:
"string"
三 ?動態(tài)存儲管理
C格式:
malloc/free
malloc 函數(shù)的一般用法 首先定義特定類型的指針變量: char * p; 調(diào)用 malloc 函數(shù)分配內(nèi)存:
p = (char *)malloc(11);
參數(shù)表示所需要分配的存儲空間大小,以字節(jié)為單位 例:若要分配能夠保存 10 個字符的字符串,分配 11 個字節(jié)(字 符串結(jié)束標志也要分配空間) 將返回值轉(zhuǎn)換為 char * 類型賦值給原指針,使 p 指向新分配空間 的匿名目標數(shù)據(jù)對象 ?free 函數(shù)的一般用法 傳遞一個指向動態(tài)分配內(nèi)存的目標數(shù)據(jù)對象的指針 示例一:
char * p; p = (char *)malloc(11); free(p);
示例二:int * p = ( int * )malloc( 10 * sizeof( int ) ); free( p );
示例二分配能夠容納 10 個整數(shù)的連續(xù)存儲空間,使 p 指向該空間的基地址,最后調(diào)用 free 函數(shù)釋放 p 指向的整個空間 特別說明:有分配就有釋放 free 函數(shù)釋放的是 p 指向的目標數(shù)據(jù)對象的空間,而不是 p 本身的存儲空間 調(diào)用 free 函數(shù)后, p 指向的空間不再有效,但 p 仍指向它 為保證在釋放目標數(shù)據(jù)對象空間后,不會再次使用 p 訪問,建議按照下述格式 書寫代碼:free( p ); p = NULL;
C++格式:
new/delete
new/new[ ] 操作符
動態(tài)創(chuàng)建單個目標數(shù)據(jù)對象 分配目標對象: int * p; p = new int; *p = 10; 分配目標對象: int * p; p = new( int ); *p = 10; 分配目標對象并初始化: int * p; p = new int(10); // 將 *p 初 始化為 10 分配目標對象并初始化: int * p; p = new(int)(10); 動態(tài)創(chuàng)建多個目標數(shù)據(jù)對象 分配數(shù)組目標對象: int * p; p = new int[8]; // 分配 8 個元素 的整數(shù)數(shù)組 ?
delete/delete[ ] 操作符
釋放單個目標數(shù)據(jù)對象 釋放目標對象: int * p; p = new int; *p = 10; delete p; 釋放多個目標數(shù)據(jù)對象 釋放數(shù)組目標對象: int * p; p = new int[8]; delete[] p; 不是delete p[ ]! ?
空懸指針問題 所有權(quán)的重疊:指針賦值操作導致兩個指針數(shù)據(jù)對象指向同樣的目 標數(shù)據(jù)對象,即兩個指針都聲稱“自己擁有目標數(shù)據(jù)對象的所有權(quán)” 示例:
int *p, *q; q = ( int* )malloc( sizeof(int) ); p = q;
產(chǎn)生原因:如果在程序中通過某個指針釋放了目標數(shù)據(jù)對象,另一 指針并不了解這種情況,它仍指向不再有效的目標數(shù)據(jù)對象,導致 空懸指針 示例:free( p ); p = NULL; // q 為空懸指針,仍指向原處
解決方案 確保程序中只有惟一一個指針擁有目標數(shù)據(jù)對象,即只有它負責目標數(shù)據(jù)對象的存儲管理,其它指針只可訪問,不可管理;若目標數(shù)據(jù)對象仍有存在價值,但該指針不再有效,此時應(yīng)進行所有權(quán)移交 在一個函數(shù)中,確保最多只有一個指針擁有目標數(shù)據(jù)對象,其它指針即使存在,也僅能訪問,不可管理 如果可能,在分配目標數(shù)據(jù)對象動態(tài)內(nèi)存的函數(shù)中釋放內(nèi)存,如main函數(shù)分配的內(nèi)存在 main 函數(shù)中釋放退一步,如果上述條件不滿足,在分配目標數(shù)據(jù)對象動態(tài)內(nèi)存的函數(shù)的主調(diào)函數(shù)中釋放內(nèi)存,即將所有權(quán)移交給上級函數(shù)級級上報,層層審批 ?
四 ?引 用 ?
1 ?引用類型
引用的定義 定義格式: 數(shù)據(jù)類型& 變量名稱 = 被引用變量名稱; 示例: int a; int & ref = a;
引用的性質(zhì) 引用類型的變量不占用單獨的存儲空間 為另一數(shù)據(jù)對象起個別名,與該對象同享存儲空間
特殊說明 引用類型的變量必須在定義時初始化 此關(guān)聯(lián)關(guān)系在引用類型變量的整個存續(xù)期都保持不變 對引用類型變量的操作就是對被引用變量的操作 ?
2 ?引用作為函數(shù)參數(shù) ?
引用的最大意義:作為函數(shù)參數(shù) 參數(shù)傳遞機制:引用傳遞,直接修改實際參數(shù)值 使用格式: 返回值類型 函數(shù)名稱( 類型 & 參數(shù)名稱); 函數(shù)原型示例:
void Swap( int & x, int & y );
函數(shù)實現(xiàn)示例:void Swap( int & x, int & y ){
int t; t = x; x = y; y = t; return;
}
函數(shù)調(diào)用示例:int main(){
int a = 10, b = 20; Swap( a, b ); return 0;
}
常量引用:僅能引用常量,不能通過引用改變目標對象值;引用本身 也不能改變引用對象
引用作為函數(shù)返回值時不生成副本 函數(shù)原型示例:
int & Inc( int & dest, const int & alpha );
函數(shù)實現(xiàn)示例:int & Inc( int & dest, const int & alpha ){
dest += alpha; return dest;
}
函數(shù)調(diào)用示例:引用類型返回值可以遞增int main(){
int a = 10, b = 20, c; Inc( a, b ); c = Inc(a, b)++; return 0;
}