?? 05章 指針與字符串.txt
字號:
C++大學教程(第5章 指針與字符串-01)
教學目標
●能夠使用指針
●能用指針按引用調用向函數傳遞參數
●了解指針、數組與字符串之間的密切關系
●了解指針在函數中的使用
●能夠聲明和使用字符串數組
5.1 簡介
本章介紹“C++編程語言一個最強大的特性——指針。指針是C++中最難掌握的問題之一。第3章介紹了引用可以用于實現按引用調用。指針使程序可模擬按引用調用,生成與操作動態數據結構,即能夠伸縮的數據結構,如鏈表、隊列、堆棧和樹。本章介紹基本的指針概念,而且強調了數組、指針與字符串之間的密切關系.并包括一組很好的字符串操作練習。
第6章介紹結構中的指針使用。第9章和第10章介紹如何用指針和引用進行面向對象編程。第15章介紹動態內存管理技術以及生成和使用動態數據結構的例子。
把數組和字符串看成指針是從C語言演變而來的。本書后面會介紹把數組和字符串當作成熟的對象。
5.2 指針變量的聲明與初始化
指針變量的值為內存地址。通常變量直接包含特定值,而指針則包含特定值變量的地址。因此可以說,變量名直接(directly)引用數值,而指針間接(indirectly)引用數值(如圖5.1)。通過指針引用數值稱為間接引用。
指針和任何其他變量一樣,應先聲明后使用。下列聲明:
int *countPtr, count;
聲明變量countPtr的類型為int*(即指向整型值的指針),或者說成"countPtr是int的指針"或"countPtr指向整數類型的對象"。變量count聲明為整數,而不是整型值的指針。聲明中的*只適用于countPtr。
聲明為指針的每個變量前面都要加上星號(*)。例如,下列聲明:
float *xPtr,*yPtr;
表示xPtr和yPtr都是指向float值的指針。聲明中以這種方式使用*時,它表示變量聲明為指針。指針可以聲明為指向任何數據類型的對象。
常見編程錯誤5.1
假設對指針的聲明會分配到聲明中逗號分隔的指針變量名列表中的所有指針變量名,從而將指針聲明為非指針。聲明為指針的每個變量前面都要加上星號(*)。
編程技巧5.1
盡管不是必需的,但在指針變量名中加上Ptr字樣能更清楚地表示這些變量是指針,需要相應的處理。
圖5.1 直接和間接引用變量
指針應在聲明時或在賦值語句中初始化。指針可以初始化為0、NULL或—個地址。數值為0或NULL的指針不指任何內容。NULL是頭文件<iostream.h>(和另外幾個標準庫頭文件)中定義的符號化常量。將指針初始化為NULL等于將指針初始化為0,但C++中優先選擇0。指定0時,它變為指針的相應類型。數值0是惟一可以不將整數轉換為指針類型而直接賦給指針變量的整數值。5.3節將介紹將變量地址賦給指針。
測試與調試提示5.1
初始化指針以防止其指向未知的或未初始化的內存區。
5.3 指針運算符
&(地址)運算符是個一元運算符,返回操作數的地址。例如,假設聲明:
int y = 5;
int *yPtr;
則下列語句:
yPtr = &y;
將變量y的地址賦給指針變量yPtr。變量yPtr“指向”y。圖5.2顯示了執行上述語句之后的內存示
意圖。圖中從指針向所指對象畫一個箭頭.表示“指向關系”。
圖5.3顯示了指針在內存中的表示,假設整型變量y存放在地址600000,指針變量yPtr存放在
地址500000。地址運算符的操作數應為左值,(即要賦值的項目,如變量名).地址運算符不能用于
常量、不產生引用的表達式和用存儲類regtster聲明的變量。
”*”運算符通常稱為間接運算符(indirection operator)或復引用運算符(dereferencing operator),
返回操作數(即指針)所指對象的同義詞、別名或渾名。例如(圖5.2再次引用),下列語句:
cout << * yPtr << endl;
指向變量y的值(5),如同下列語句:
cout << y << endl;
圖5.2 指針指向內存中整數變量的示意圖
這里使用*的方法稱為復引用指針(dereferencing a pointer)。注意復引用指針也可以用于賦值語句左邊,例如下列語句:
*yPtr = 9;
將數值9賦給圖5.3中的y。復引用指針也可用于接收輸入值,例如:
cin>> *yPtr;
復引用的指針是個左值。
yptr y
500000 600000 600000 5
圖 5.3 指針在內存中的表示
常見編程錯誤5.2
如果指針沒有正確地初始化或沒有指定指向內存中的特定地址,則復引用指針可能造成致命的運行時錯誤,或者意外修改重要數據。雖然運行完程序,但得到的是錯誤結果。
常見編程錯誤5.3
復引用非指針是個語法錯誤。
常見編程錯誤5.4
復引用0指針通常是個致命的運行時錯誤。
圖5.4的程序演示了指針運算符。本例中通過<<用十六進制整數輸出內存地址(十六進制整數見附錄“數值系統”)。
可移植性提示 5. 1
輸出指針的格式與機器有關,有些系統用十六進制整數,而有些系統用十進制整數。
注意a的地址和aPtr的值在輸出中是一致的,說明a的地址實際賦給了指針變量aptr。&和*運算符是互逆的,如果兩者同時作用于aPtr,則打印相同的結果。圖5.5顯示了前面所介紹的運算符的優先級和結合律。
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 }
輸出結果:
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 &與*指針運算符
------------------------------------------------------------------------------
運算符 結合律 類型
------------------------------------------------------------------------------
() [] 從左向右 括號
++ -- + - static_cast<type>() 從右向左 一元
& *
* / % 從左向右 乘
+ - 從左向右 加
<< >> 從左向右 插入/讀取
< <= > >= 從左向右 關系
== != 從左向右 相等
&& 從左向右 邏輯AND
|| 從左向右 邏輯或
?: 從右向左 條件
= += -= *= /= %= 從右向左 賦值
, 從左向右 逗號
------------------------------------------------------------------------------
圖 5.5 運算符的優先級和結合律
5.4 按引用調用函數
C++用三種方式向函數傳遞數值:按值調用(call-by-value)、用引用參數按引用調用(call-by-reference reference argument)和用指針參數按引用調用(call-by-reference pointer argument)。第3章比較了按引用調用與按值調用,本章主要介紹用指針參數按引用調用。
第3章曾介紹過,return可以從被調用函數向調用者返回一個值(或不返回值而從被調用函數返回控制)。我們還介紹了用引用參數將參數傳遞給函數,使函數可以修改參數的原有值(這樣可以從函數“返回”多個值),或將大的數據對象傳遞給函數而避免按值調用傳遞對象的開銷(即復制對象所需的開銷)。指針和引用一樣,也可以修改調用者的一個或幾個變量,或將大的數據對象指針傳遞給函數而避免按值調用傳遞對象的開銷。
在C++中,程序員可以用指針和間接運算符模擬按引用調用(就像C語言程序中的按引用調用一樣)。調用函數并要修改參數時,傳遞該參數地址,通常在要修改數值的變量名前面加上地址運算符(&)。第4章曾介紹過,數組不能用地址運算符(&)傳遞,因為數組名是內存中數組的開始位置(數組名等同于&arrayName[0]),即數組名已經是個指針。向函數傳遞參數地址時,可以在函數中使用間接運算符形成變量名的同義詞、別名或渾名,并可用其修改調用者內存中該地址的
值(如果變量不用const聲明)。
圖5.6和5.7的程序是計算整數立方函數的兩個版本cubeByValue和cubeByReference。圖5.6按值調用將變量number傳遞給函數cubeByValue。函數cubeByValue求出參數的立方,并將新值用return語句返回main,井在main中將新值賦給number。可以先檢查函數調用的結果再修改變量值。例如,在這個程序中,可以將cubeByValue的結果存放在另一變量中,檢查其數值,然后再將新值賦給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 }
輸出結果:
The original value of number is 5
The new value of number is 125
圖5.6 按值調用求出參數的立方
圖5.7的程序按引用調用傳遞變量nunber(傳遞number的地址)到函數cubeByReference。函
數cubeByReference取nPtr(int的指針)作為參數。函數復引用指針并求出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 }
輸出結果:
The original value of number is 5
The new value of number is 125
圖 5.7 用指針參數按引用調用求出參數的立方
常見編程錯誤5.5
要復引用指針以取得指針所指的值時不復引用指針是個錯誤。
接收地址參數的函數要定義接收地址的指針參數。例如,cubeByReference的函數首部如下所示:
void cubeByReference(int *nPtr)
這個函數首部指定函數cubeByReferenee接收整型變量的地址(即整型指針)作為參數,在nPtr中局部存放地址,不返回值。
cubeByReference的函數原型包含括號中的int*。和其他變量類型一樣,不需要在函數原型中包括指針名。參數名僅用于程序中的說明,編譯器將其忽略。
在需要單下標數組參數的函數首部和函數原型中,可以用cubeByReference參數表中的指針符號。編譯器并不區分接收指針的函數和接收單下標數組的函數。當然,函數必須“知道”何時接收數組或要進行按引用調用的單個變量。編譯器遇到形如int b[]的單下標數組函數參數時,編譯器將參數變為指針符號int* const b(b是指向整數的常量指針),const見第51節介紹。聲明函數參數為單下標數組的兩種形式可以互換。
編程技巧5.2
除非調用者顯式要求被調用函數修改調用者環境中參數變量的值,否則按值調用將參數傳遞給函數。這是最低權限原則的另一個例子。
圖 5.8典型的按值調用分析
圖 5.9典型的用指針參數按引用調用分析
5.5 指針與常量限定符
const限定符可以使程序員告訴編譯器特定變量的值不能修改。
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -