?? 05章 指針與字符串.txt
字號(hào):
C++大學(xué)教程(第5章 指針與字符串-01)
教學(xué)目標(biāo)
●能夠使用指針
●能用指針按引用調(diào)用向函數(shù)傳遞參數(shù)
●了解指針、數(shù)組與字符串之間的密切關(guān)系
●了解指針在函數(shù)中的使用
●能夠聲明和使用字符串?dāng)?shù)組
5.1 簡(jiǎn)介
本章介紹“C++編程語(yǔ)言一個(gè)最強(qiáng)大的特性——指針。指針是C++中最難掌握的問(wèn)題之一。第3章介紹了引用可以用于實(shí)現(xiàn)按引用調(diào)用。指針使程序可模擬按引用調(diào)用,生成與操作動(dòng)態(tài)數(shù)據(jù)結(jié)構(gòu),即能夠伸縮的數(shù)據(jù)結(jié)構(gòu),如鏈表、隊(duì)列、堆棧和樹。本章介紹基本的指針概念,而且強(qiáng)調(diào)了數(shù)組、指針與字符串之間的密切關(guān)系.并包括一組很好的字符串操作練習(xí)。
第6章介紹結(jié)構(gòu)中的指針使用。第9章和第10章介紹如何用指針和引用進(jìn)行面向?qū)ο缶幊獭5?5章介紹動(dòng)態(tài)內(nèi)存管理技術(shù)以及生成和使用動(dòng)態(tài)數(shù)據(jù)結(jié)構(gòu)的例子。
把數(shù)組和字符串看成指針是從C語(yǔ)言演變而來(lái)的。本書后面會(huì)介紹把數(shù)組和字符串當(dāng)作成熟的對(duì)象。
5.2 指針變量的聲明與初始化
指針變量的值為內(nèi)存地址。通常變量直接包含特定值,而指針則包含特定值變量的地址。因此可以說(shuō),變量名直接(directly)引用數(shù)值,而指針間接(indirectly)引用數(shù)值(如圖5.1)。通過(guò)指針引用數(shù)值稱為間接引用。
指針和任何其他變量一樣,應(yīng)先聲明后使用。下列聲明:
int *countPtr, count;
聲明變量countPtr的類型為int*(即指向整型值的指針),或者說(shuō)成"countPtr是int的指針"或"countPtr指向整數(shù)類型的對(duì)象"。變量count聲明為整數(shù),而不是整型值的指針。聲明中的*只適用于countPtr。
聲明為指針的每個(gè)變量前面都要加上星號(hào)(*)。例如,下列聲明:
float *xPtr,*yPtr;
表示xPtr和yPtr都是指向float值的指針。聲明中以這種方式使用*時(shí),它表示變量聲明為指針。指針可以聲明為指向任何數(shù)據(jù)類型的對(duì)象。
常見(jiàn)編程錯(cuò)誤5.1
假設(shè)對(duì)指針的聲明會(huì)分配到聲明中逗號(hào)分隔的指針變量名列表中的所有指針變量名,從而將指針聲明為非指針。聲明為指針的每個(gè)變量前面都要加上星號(hào)(*)。
編程技巧5.1
盡管不是必需的,但在指針變量名中加上Ptr字樣能更清楚地表示這些變量是指針,需要相應(yīng)的處理。
圖5.1 直接和間接引用變量
指針應(yīng)在聲明時(shí)或在賦值語(yǔ)句中初始化。指針可以初始化為0、NULL或—個(gè)地址。數(shù)值為0或NULL的指針不指任何內(nèi)容。NULL是頭文件<iostream.h>(和另外幾個(gè)標(biāo)準(zhǔn)庫(kù)頭文件)中定義的符號(hào)化常量。將指針初始化為NULL等于將指針初始化為0,但C++中優(yōu)先選擇0。指定0時(shí),它變?yōu)橹羔樀南鄳?yīng)類型。數(shù)值0是惟一可以不將整數(shù)轉(zhuǎn)換為指針類型而直接賦給指針變量的整數(shù)值。5.3節(jié)將介紹將變量地址賦給指針。
測(cè)試與調(diào)試提示5.1
初始化指針以防止其指向未知的或未初始化的內(nèi)存區(qū)。
5.3 指針運(yùn)算符
&(地址)運(yùn)算符是個(gè)一元運(yùn)算符,返回操作數(shù)的地址。例如,假設(shè)聲明:
int y = 5;
int *yPtr;
則下列語(yǔ)句:
yPtr = &y;
將變量y的地址賦給指針變量yPtr。變量yPtr“指向”y。圖5.2顯示了執(zhí)行上述語(yǔ)句之后的內(nèi)存示
意圖。圖中從指針向所指對(duì)象畫一個(gè)箭頭.表示“指向關(guān)系”。
圖5.3顯示了指針在內(nèi)存中的表示,假設(shè)整型變量y存放在地址600000,指針變量yPtr存放在
地址500000。地址運(yùn)算符的操作數(shù)應(yīng)為左值,(即要賦值的項(xiàng)目,如變量名).地址運(yùn)算符不能用于
常量、不產(chǎn)生引用的表達(dá)式和用存儲(chǔ)類regtster聲明的變量。
”*”運(yùn)算符通常稱為間接運(yùn)算符(indirection operator)或復(fù)引用運(yùn)算符(dereferencing operator),
返回操作數(shù)(即指針)所指對(duì)象的同義詞、別名或渾名。例如(圖5.2再次引用),下列語(yǔ)句:
cout << * yPtr << endl;
指向變量y的值(5),如同下列語(yǔ)句:
cout << y << endl;
圖5.2 指針指向內(nèi)存中整數(shù)變量的示意圖
這里使用*的方法稱為復(fù)引用指針(dereferencing a pointer)。注意復(fù)引用指針也可以用于賦值語(yǔ)句左邊,例如下列語(yǔ)句:
*yPtr = 9;
將數(shù)值9賦給圖5.3中的y。復(fù)引用指針也可用于接收輸入值,例如:
cin>> *yPtr;
復(fù)引用的指針是個(gè)左值。
yptr y
500000 600000 600000 5
圖 5.3 指針在內(nèi)存中的表示
常見(jiàn)編程錯(cuò)誤5.2
如果指針沒(méi)有正確地初始化或沒(méi)有指定指向內(nèi)存中的特定地址,則復(fù)引用指針可能造成致命的運(yùn)行時(shí)錯(cuò)誤,或者意外修改重要數(shù)據(jù)。雖然運(yùn)行完程序,但得到的是錯(cuò)誤結(jié)果。
常見(jiàn)編程錯(cuò)誤5.3
復(fù)引用非指針是個(gè)語(yǔ)法錯(cuò)誤。
常見(jiàn)編程錯(cuò)誤5.4
復(fù)引用0指針通常是個(gè)致命的運(yùn)行時(shí)錯(cuò)誤。
圖5.4的程序演示了指針運(yùn)算符。本例中通過(guò)<<用十六進(jìn)制整數(shù)輸出內(nèi)存地址(十六進(jìn)制整數(shù)見(jiàn)附錄“數(shù)值系統(tǒng)”)。
可移植性提示 5. 1
輸出指針的格式與機(jī)器有關(guān),有些系統(tǒng)用十六進(jìn)制整數(shù),而有些系統(tǒng)用十進(jìn)制整數(shù)。
注意a的地址和aPtr的值在輸出中是一致的,說(shuō)明a的地址實(shí)際賦給了指針變量aptr。&和*運(yùn)算符是互逆的,如果兩者同時(shí)作用于aPtr,則打印相同的結(jié)果。圖5.5顯示了前面所介紹的運(yùn)算符的優(yōu)先級(jí)和結(jié)合律。
1 // Fig. 5.4: fig05_04.cpp
2 // Using the & and * operators
3 #include <iostream.h>
4
5 int main()
6{
7 int a; // a is an integer
8 iht *aPtr; // aPtr is a pointer to an integer
9
10 a = 7;
11 aPtr = &a; // aPtr set to address of a
12
13 cout << "The address of a is "<< &a
14 << "\nThe value of aPtr is" << aPtr;
15
16 cout << "\n\nThe value of a is "<<a
17 << "\nThe value of *aPtr is" << *aPtr;
18
19 cout << "\n\nShowing that * and & are inverses of"
20 << "each other.\n&*aPtr =" << &*aPtr
21 << "\n*&aPtr =" << *&aPtr << endl;
22 return 0;
23 }
輸出結(jié)果:
The address of a is Ox0064FDF4
The value of aPtr is 0x0064FDF4
The value of a is 7
The value of *aPtr is 7
Showing that * and & are inverses of each other.
&*aPtr = 0x0064FDF4
*&aPtr = 0x0064FDF4
圖 5.4 &與*指針運(yùn)算符
------------------------------------------------------------------------------
運(yùn)算符 結(jié)合律 類型
------------------------------------------------------------------------------
() [] 從左向右 括號(hào)
++ -- + - static_cast<type>() 從右向左 一元
& *
* / % 從左向右 乘
+ - 從左向右 加
<< >> 從左向右 插入/讀取
< <= > >= 從左向右 關(guān)系
== != 從左向右 相等
&& 從左向右 邏輯AND
|| 從左向右 邏輯或
?: 從右向左 條件
= += -= *= /= %= 從右向左 賦值
, 從左向右 逗號(hào)
------------------------------------------------------------------------------
圖 5.5 運(yùn)算符的優(yōu)先級(jí)和結(jié)合律
5.4 按引用調(diào)用函數(shù)
C++用三種方式向函數(shù)傳遞數(shù)值:按值調(diào)用(call-by-value)、用引用參數(shù)按引用調(diào)用(call-by-reference reference argument)和用指針參數(shù)按引用調(diào)用(call-by-reference pointer argument)。第3章比較了按引用調(diào)用與按值調(diào)用,本章主要介紹用指針參數(shù)按引用調(diào)用。
第3章曾介紹過(guò),return可以從被調(diào)用函數(shù)向調(diào)用者返回一個(gè)值(或不返回值而從被調(diào)用函數(shù)返回控制)。我們還介紹了用引用參數(shù)將參數(shù)傳遞給函數(shù),使函數(shù)可以修改參數(shù)的原有值(這樣可以從函數(shù)“返回”多個(gè)值),或?qū)⒋蟮臄?shù)據(jù)對(duì)象傳遞給函數(shù)而避免按值調(diào)用傳遞對(duì)象的開銷(即復(fù)制對(duì)象所需的開銷)。指針和引用一樣,也可以修改調(diào)用者的一個(gè)或幾個(gè)變量,或?qū)⒋蟮臄?shù)據(jù)對(duì)象指針傳遞給函數(shù)而避免按值調(diào)用傳遞對(duì)象的開銷。
在C++中,程序員可以用指針和間接運(yùn)算符模擬按引用調(diào)用(就像C語(yǔ)言程序中的按引用調(diào)用一樣)。調(diào)用函數(shù)并要修改參數(shù)時(shí),傳遞該參數(shù)地址,通常在要修改數(shù)值的變量名前面加上地址運(yùn)算符(&)。第4章曾介紹過(guò),數(shù)組不能用地址運(yùn)算符(&)傳遞,因?yàn)閿?shù)組名是內(nèi)存中數(shù)組的開始位置(數(shù)組名等同于&arrayName[0]),即數(shù)組名已經(jīng)是個(gè)指針。向函數(shù)傳遞參數(shù)地址時(shí),可以在函數(shù)中使用間接運(yùn)算符形成變量名的同義詞、別名或渾名,并可用其修改調(diào)用者內(nèi)存中該地址的
值(如果變量不用const聲明)。
圖5.6和5.7的程序是計(jì)算整數(shù)立方函數(shù)的兩個(gè)版本cubeByValue和cubeByReference。圖5.6按值調(diào)用將變量number傳遞給函數(shù)cubeByValue。函數(shù)cubeByValue求出參數(shù)的立方,并將新值用return語(yǔ)句返回main,井在main中將新值賦給number。可以先檢查函數(shù)調(diào)用的結(jié)果再修改變量值。例如,在這個(gè)程序中,可以將cubeByValue的結(jié)果存放在另一變量中,檢查其數(shù)值,然后再將新值賦給number。
1 // Fig. 5,6: fig0506,cpp
2 // Cube a variable using call-by-value
3 #include <iostream.h>
4
5 int cubeByValue( int ); // prototype
6
7 int main()
8 {
9 int number = 5;
10
11 cout << "The original value of number is "<< number;
12 number = cubeByValue( number );
13 cout << "\nThe new value of number is" << number << endl;
14 return 0;
15 }
16
17 int cubeByValue( int n )
{
18
19 return n * n * n; // cube local variable n
2O }
輸出結(jié)果:
The original value of number is 5
The new value of number is 125
圖5.6 按值調(diào)用求出參數(shù)的立方
圖5.7的程序按引用調(diào)用傳遞變量nunber(傳遞number的地址)到函數(shù)cubeByReference。函
數(shù)cubeByReference取nPtr(int的指針)作為參數(shù)。函數(shù)復(fù)引用指針并求出nPtr所指值的立方,從
而改變main中的number值。圖5.8和5.9分別分析了圖5.6和1.7所示程序。
1 // Fig. 5.7: fig05_07.cpp
2 // Cube a variable using call-by-reference
3 // with a pointer argument
4 #include <iostream.h>
5
6 void cubeByReference( int* ); // prototype
7
8 int main()
9 {
10 int number = 5;
11
12 cout << "The original value of number is "<< number;
13 cubeByReference( &number );
14 cout << "\nThe new value of number is "<< number << endl;
15 return O;
16 }
17
18 void cubeByReference( int *nPtr )
19 {
20 *nPtr = *nPtr = *nptr * *nptr; // cube number in main
21 }
輸出結(jié)果:
The original value of number is 5
The new value of number is 125
圖 5.7 用指針參數(shù)按引用調(diào)用求出參數(shù)的立方
常見(jiàn)編程錯(cuò)誤5.5
要復(fù)引用指針以取得指針?biāo)傅闹禃r(shí)不復(fù)引用指針是個(gè)錯(cuò)誤。
接收地址參數(shù)的函數(shù)要定義接收地址的指針參數(shù)。例如,cubeByReference的函數(shù)首部如下所示:
void cubeByReference(int *nPtr)
這個(gè)函數(shù)首部指定函數(shù)cubeByReferenee接收整型變量的地址(即整型指針)作為參數(shù),在nPtr中局部存放地址,不返回值。
cubeByReference的函數(shù)原型包含括號(hào)中的int*。和其他變量類型一樣,不需要在函數(shù)原型中包括指針名。參數(shù)名僅用于程序中的說(shuō)明,編譯器將其忽略。
在需要單下標(biāo)數(shù)組參數(shù)的函數(shù)首部和函數(shù)原型中,可以用cubeByReference參數(shù)表中的指針?lè)?hào)。編譯器并不區(qū)分接收指針的函數(shù)和接收單下標(biāo)數(shù)組的函數(shù)。當(dāng)然,函數(shù)必須“知道”何時(shí)接收數(shù)組或要進(jìn)行按引用調(diào)用的單個(gè)變量。編譯器遇到形如int b[]的單下標(biāo)數(shù)組函數(shù)參數(shù)時(shí),編譯器將參數(shù)變?yōu)橹羔樂(lè)?hào)int* const b(b是指向整數(shù)的常量指針),const見(jiàn)第51節(jié)介紹。聲明函數(shù)參數(shù)為單下標(biāo)數(shù)組的兩種形式可以互換。
編程技巧5.2
除非調(diào)用者顯式要求被調(diào)用函數(shù)修改調(diào)用者環(huán)境中參數(shù)變量的值,否則按值調(diào)用將參數(shù)傳遞給函數(shù)。這是最低權(quán)限原則的另一個(gè)例子。
圖 5.8典型的按值調(diào)用分析
圖 5.9典型的用指針參數(shù)按引用調(diào)用分析
5.5 指針與常量限定符
const限定符可以使程序員告訴編譯器特定變量的值不能修改。
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -