官术网_书友最值得收藏!

icon2

1.4 指針

1.指針的概念

為了理解什么是指針,必須先弄清楚數(shù)據(jù)在內(nèi)存中是如何存儲(chǔ)的,又是如何讀取的。如果在程序中定義了一個(gè)變量,在編譯時(shí)就給這個(gè)變量分配內(nèi)存單元。系統(tǒng)根據(jù)程序中定義的變量類型,來分配一定長度的空間。例如,C++編譯系統(tǒng)在32位機(jī)器上為整型變量分配4Byte,為單精度浮點(diǎn)型變量分配4Byte,為字符型變量分配1Byte。內(nèi)存區(qū)的每一個(gè)字節(jié)有一個(gè)編號(hào),這個(gè)編號(hào)就是地址,如表1-1所示。

表1-1 用戶數(shù)據(jù)、變量、地址直接的對(duì)應(yīng)關(guān)系

表1-1中展示了用戶數(shù)據(jù)、變量、地址直接的對(duì)應(yīng)關(guān)系。假設(shè)有變量i,存的數(shù)據(jù)是3,那它在內(nèi)存中的地址就是2000。

請(qǐng)務(wù)必弄清楚一個(gè)內(nèi)存單元的地址與內(nèi)存單元的內(nèi)容這兩個(gè)概念的區(qū)別。其實(shí)程序經(jīng)過編譯以后已經(jīng)將變量名轉(zhuǎn)換為變量的地址,對(duì)變量值的存取都是通過地址進(jìn)行的。這種按變量地址存取變量值的方式稱為直接存取方式,或直接訪問方式。還可以采用另一種稱為間接存取(間接訪問)的方式,在程序中定義一種特殊的變量,專門用來存放地址。

由于通過地址能找到所需的變量單元,因此可以說,地址指向該變量單元。因此將地址形象化地稱為“指針”,一個(gè)變量的地址稱為該變量的指針。如果有一個(gè)變量是專門用來存放另一變量地址(即指針)的,則它稱為指針變量。指針變量的值(即指針變量中存放的值)是地址(即指針)。

指針也是一種變量,普通的變量存放的是實(shí)際的數(shù)據(jù),而指針變量包含的是內(nèi)存中的一塊地址,這塊地址指向某個(gè)變量或者函數(shù)。指針的內(nèi)容包括:指針的類型、指針?biāo)赶虻念愋汀⒅羔樀闹狄约爸羔槺旧硭嫉膬?nèi)存區(qū)。例1.6展示了指針的使用。

【例1.6】 指針使用舉例。


#include<iostream>
using namespace std;
int main(){
    int p1=1;               // p1是一個(gè)普通的整型變量
    int *p2;               // p2是一個(gè)指針,指向一個(gè)整型變量
    p2=&p1;               // p1的地址賦值給p2p2也就指向了p1
    cout<<p1<<" "<<*p2<<endl;     // *p2就是取p2所指向的地址的內(nèi)容
    p1=2;                    // 那么*p2的值也是2
    cout<<p1<<" "<<*p2<<endl;
    *p2=3;                    // 那么p1的值也是3
    cout<<p1<<" "<<*p2<<endl;
    return 0;
}

程序的執(zhí)行結(jié)果是:


1 1
2 2
3 3

例1.6中定義了一個(gè)整型變量p1,一個(gè)指向整型變量的指針p2,并將p2指向p1。要使用p2指向的內(nèi)容,必須在p2前面加個(gè)*號(hào),也就是*p2。修改了p1的值,*p2的內(nèi)容也會(huì)跟著改變;同樣地,修改*p2的值,p1的值也會(huì)跟著改變。

2.數(shù)組與指針

在C++中,數(shù)組名代表數(shù)組第一個(gè)元素的地址,如下程序定義了兩個(gè)變量:


int *p;
int a[10];

若p=a等價(jià)于p=&a[0],可以通過對(duì)p、a的偏移(int類型的指針+1或-1,是向上或向下偏移sizeof(int)個(gè)byte)來訪問數(shù)組里的元素,若用*(p+i)、*(a+i)也可以通過傳統(tǒng)的數(shù)組a[i]訪問各個(gè)元素。

(1)數(shù)組指針,也稱行指針,具體內(nèi)容如下所述。

假設(shè)有定義int(*p)[n];且()優(yōu)先級(jí)高,首先說明p是一個(gè)指針,且指向一個(gè)整型的一維數(shù)組。這個(gè)一維數(shù)組的長度是n,也可以說是p的步長,也就是說執(zhí)行p+1時(shí),p要跨過n個(gè)整型數(shù)據(jù)的長度。如要將二維數(shù)組賦給一指針,應(yīng)這樣賦值:


int a[3][4];
int (*p)[4];          // 該語句是定義一個(gè)數(shù)組指針,指向含4個(gè)元素的一維數(shù)組。
p=a;               // 將該二維數(shù)組的首地址賦給p,也就是a[0]&a[0][0]
p++;               // 該語句執(zhí)行過后,也就是p=p+1;p跨過行a[0][]指向了行a[1][]
                    // 所以數(shù)組指針也稱指向一維數(shù)組的指針,亦稱行指針。

(2)指針數(shù)組不同于數(shù)組指針,具體內(nèi)容如下所述。

假設(shè)有定義int*p[n];且[]優(yōu)先級(jí)高,可以理解為先與p結(jié)合成為一個(gè)數(shù)組,再由int*說明這是一個(gè)整型指針數(shù)組,它有n個(gè)指針類型的數(shù)組元素。這里若執(zhí)行p+1操作則是錯(cuò)誤的,p=a這樣賦值也是錯(cuò)誤的,因?yàn)閜是個(gè)不可知的表示,只存在p[0]、p[1]、p[2]...p[n-1],而且它們分別是指針變量,只用來存放變量地址。但可以這樣*p=a賦值這里*p表示指針數(shù)組第一個(gè)元素的值,a的首地址的值。

如要將二維數(shù)組賦給一指針數(shù)組,程序可以是:


int *p[3];
int a[3][4];
for(i=0;i<3;i++){
    p[i]=a[i];
}

這里int*p[3]表示一個(gè)一維數(shù)組內(nèi)存放著3個(gè)指針變量,分別是p[0]、p[1]、p[2],所以要分別賦值。

這樣數(shù)組指針和指針數(shù)組兩者的區(qū)別就很明顯了:數(shù)組指針只是一個(gè)指針變量,可以認(rèn)為是C語言里專門用來指向二維數(shù)組的,它占用內(nèi)存中一個(gè)指針的存儲(chǔ)空間;指針數(shù)組是多個(gè)指針變量,以數(shù)組形式存在內(nèi)存當(dāng)中,占用多個(gè)指針的存儲(chǔ)空間。還需要說明的一點(diǎn)就是,同時(shí)用來指向二維數(shù)組時(shí),其直接引用和用數(shù)組名引用都是一樣的。

比如要表示數(shù)組中第i行j列一個(gè)元素,這幾種方式都可以:

*(p[i]+j)、*(*(p+i)+j)、(*(p+i))[j]、p[i][j]。

其中,優(yōu)先級(jí):()>[]>*。

3.字符串與指針

字符串是C++中最經(jīng)常用到的操作對(duì)象之一。用字符數(shù)組和字符指針變量都可以實(shí)現(xiàn)字符串的存儲(chǔ)和運(yùn)算。例1.7展示了字符數(shù)組和字符指針是如何使用的。

【例1.7】 字符數(shù)組、字符指針、字符指針數(shù)組、字符串變量應(yīng)用舉例。


#include<iostream>
#include<string>
using namespace std;
int main(){
    char str[] = "I am a programmer." ;     // str 是一個(gè)字符數(shù)組
    char * str1="abc";               // str1是一個(gè)字符指針變量,可以指向一個(gè)字符串
    char * str2[]={"hello world","good bye"};
                              // str2是一個(gè)字符指針數(shù)組,可以存多個(gè)字符串
    string str3 = "I am a programmer, too.";
                              // str3是一個(gè)字符串變量
    cout<<"str: "<<str<<endl;
    cout<<"str1: "<<str1<<endl;
    cout<<"str2[0]: "<<str2[0]<<endl;
    cout<<"str3: "<<str3<<endl;
    return 0;
}

程序的執(zhí)行結(jié)果是:


str: I am a programmer.
str1: abc
str2[0]: hello world
str3: I am a programmer, too.

例1.7中,str是一個(gè)字符數(shù)組,str1是一個(gè)字符指針變量,str2是一個(gè)字符指針數(shù)組,str3是一個(gè)字符串變量。

(1)字符串指針變量本身是一個(gè)變量,用于存放字符串的首地址。可以改變str1使它指向不同的字符串,但不能改變str1所指的字符串常量。因?yàn)槎x指針時(shí),編譯器并不為指針?biāo)赶虻膶?duì)象分配空間,它只是分配指針本身的空間,所以abc會(huì)被當(dāng)成常量,并且被放到程序的常量區(qū),不能被修改。

(2)字符串本身是存放在以該首地址為首的一塊連續(xù)的內(nèi)存空間中,并以'\0'作為字符串的結(jié)束標(biāo)志。

(3)字符數(shù)組是由于若干個(gè)數(shù)組元素組成的,每個(gè)元素中存放字符串的一個(gè)字符。在定義一個(gè)字符數(shù)組時(shí),編譯后就會(huì)分配一個(gè)內(nèi)存單元,每個(gè)元素都有確定的地址。

4.函數(shù)與指針

函數(shù)指針是指向函數(shù)的指針變量。所以,函數(shù)指針首先是個(gè)指針變量,而且這個(gè)變量指向一個(gè)函數(shù)。C++在編譯時(shí),每一個(gè)函數(shù)都有一個(gè)入口地址,該入口地址就是函數(shù)指針?biāo)赶虻牡刂贰S辛酥赶蚝瘮?shù)的指針變量后,就可以用該指針變量調(diào)用函數(shù)了。

函數(shù)指針的聲明方法是:


返回值類型 (*指針變量名)([形參列表]);

其中,返回值類型說明函數(shù)的返回值類型,(*指針變量名)這句的括號(hào)不能省略。

例如:


int func(int a);                    // 聲明一個(gè)函數(shù)
int (*f) (int a);                    // 聲明一個(gè)函數(shù)指針
f=&func;

將func函數(shù)的首地址賦值給函數(shù)指針,這里也等價(jià)于f=&func;賦值時(shí)函數(shù)不帶括號(hào),也不帶參數(shù),函數(shù)名就代表了函數(shù)的首地址。例1.8展示了函數(shù)指針調(diào)用函數(shù)的方法。

【例1.8】 函數(shù)指針使用范例。


#include<iostream>
using namespace std;
int Mmin(int x,int y){
    if(x<y)return x;
    return y;
}
int Mmax(int x,int y){
    if(x>y)return x;
    return y;
}
int main(){
    int (*f)(int x,int y);
    int a=10,b=20;
    f=Mmin;                    // Mmin函數(shù)的入口地址賦給f
    cout << (*f)(a,b)<<endl;
    f=Mmax;                    // Mmax函數(shù)的入口地址賦給f
    cout << (*f)(a,b)<<endl;
    return 0;
}

程序的執(zhí)行結(jié)果是:


10
20

例1.8中定義了一個(gè)函數(shù)指針f,兩個(gè)函數(shù)Mmin和Mmax,先后把f指向Mmin和Mmax函數(shù),執(zhí)行比較兩個(gè)數(shù),分別得出較小值和較大值。

主站蜘蛛池模板: 荆州市| 济源市| 大方县| 新沂市| 永寿县| 江安县| 松江区| 通道| 邓州市| 福建省| 称多县| 阜阳市| 安溪县| 保康县| 弋阳县| 潼南县| 合山市| 犍为县| 泾阳县| 商都县| 阿巴嘎旗| 饶平县| 淮北市| 华安县| 武义县| 瓦房店市| 托克托县| 井研县| 朔州市| 高陵县| 仁布县| 永城市| 景泰县| 卢湾区| 隆尧县| 肇州县| 綦江县| 晋城| 崇州市| 和平区| 榆林市|