《C程序設(shè)計》課件第8章_第1頁
《C程序設(shè)計》課件第8章_第2頁
《C程序設(shè)計》課件第8章_第3頁
《C程序設(shè)計》課件第8章_第4頁
《C程序設(shè)計》課件第8章_第5頁
已閱讀5頁,還剩155頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

第八章指針8.1指針的概念與定義8.2指針作函數(shù)參數(shù)8.3指針與數(shù)組8.4指針與函數(shù)8.5復(fù)雜指針8.6程序設(shè)計舉例習題8.1指針的概念與定義8.1.1指針的概念指針就是用來存放地址的變量。某個指針存放了哪個變量的地址,就可以說該指針指向了這個變量。實際上,指針還可以指向數(shù)組、字符串等對象,甚至可以用來存放函數(shù)的入口地址。為了理解指針的概念,程序員要有關(guān)于計算機如何在存儲器中存儲信息的基本知識。以下簡單地介紹個人計算機中存儲器存儲的情況。個人計算機中CPU可以直接訪問的,用來存儲程序和數(shù)據(jù)的記憶部件稱為內(nèi)存儲器,內(nèi)存儲器由成千上萬個順序存儲單元組成,每個單元由一個惟一的地址標識。給定計算機的存儲器地址范圍為從0到所安裝的存儲器數(shù)量的最大值。在計算機上運行的每一個程序都要使用存儲器。例如,操作系統(tǒng)要占用一些計算機存儲空間,每個應(yīng)用程序也要占用計算機存儲空間。按照面向過程的結(jié)構(gòu)化程序設(shè)計方法,程序代碼和程序要處理的數(shù)據(jù)是分開存儲的,所以,一個程序在內(nèi)存中要占兩部分空間:數(shù)據(jù)部分和指令代碼部分。本節(jié)考察數(shù)據(jù)段在存儲器中的存儲情況。當C程序中定義一個變量時,編譯器劃分出一定數(shù)目的存儲器單元來存儲那個變量,存儲器單元的數(shù)目由變量的類型確定。編譯器將這幾個存儲單元與變量名聯(lián)系起來,當程序引用這個變量名時,自動地訪問相應(yīng)的存儲器單元,當然程序也可以通過該變量的地址來訪問這些存儲器單元。程序中的變量所需存儲單元的數(shù)目由變量的類型決定。例如,一個int變量占據(jù)的存儲單元可能為2字節(jié)(16位機)或4字節(jié)(32位機),一個float變量為4字節(jié),一個char變量為1字節(jié)等。變量所占據(jù)的存儲單元的地址就是變量的地址,變量的地址表示為表達式

&變量名

&是單目運算符,稱為取地址運算符。例如:

charc=′A′;則&c是字符變量c的地址,即圖8.1中的FFF3H。圖8.1內(nèi)存分配表存放變量的地址的變量稱為指針。如果pc是存放字符變量地址的變量,則語句

pc=&c;將c的地址存入指針pc,如圖8.1所示,稱“pc指向c”,或“pc是c的指針”,被pc指向的變量c稱為“pc的對象”?!皩ο蟆本褪且粋€有名字的內(nèi)存區(qū)域,即一個變量。

#include<stdio.h>

voidmain()

{

inti=0x3038;

charc=′A′;

int*pi=&i;

char*pc=&c;

printf("i=%x,c=%c,*pi=%d,*pc=%c\n",i,c,*pi,*pc);

printf("&i=%p,&c=%p,&pi=%p,&pc=%p\n",pi,pc,&pi,&pc);

}運行結(jié)果:

i=3038,c=A,*pi=3038,*pc=A

&i=FFF4,&c=FFF3,&pi=FFF0,&pc=FFEE該程序在TurboC++3.0下編譯后,各變量的存儲內(nèi)容和內(nèi)存分配情況如圖8.1所示??梢钥吹剑趦?nèi)存中,整型變量i占2個字節(jié),字符型變量c占1個字節(jié),指針變量pi和pc各占2個字節(jié)(在這里,我們應(yīng)該看到,不管指針變量的類型是什么,它在內(nèi)存中所占的字節(jié)數(shù)是一定的;16位系統(tǒng)下是2個字節(jié),32位系統(tǒng)下是4個字節(jié)),這是因為指針保存的是地址,與具體類型是無關(guān)的。從圖8.1中可以看到,既可以通過變量名直接訪問內(nèi)存的數(shù)據(jù),又可以通過變量的地址(即指針)間接訪問該變量。指針類型是對所有類型的指針的總稱,指針的類型是指針所指對象的數(shù)據(jù)類型。例如,pc是指向字符變量的指針,簡稱字符指針。字符指針是基本類型的指針之一,除各種基本類型之外,允許說明指向數(shù)組的指針、指向函數(shù)的指針、指向結(jié)構(gòu)體和共用體的指針以及指向各類指針的指針。在C語言中只有指針被允許用來存放地址的值,其它類型的變量只能存放該類型的數(shù)據(jù)。(很多書中用指針一詞來指地址值,或用指針變量來代表指針,閱讀中應(yīng)注意其具體含義。)8.1.2指針的定義及使用

1.指針的定義指針是一種存放地址值的變量,像其它變量一樣,必須在使用前定義。指針變量的命名遵守與其它變量相同的規(guī)則,即必須是惟一的標識符。指針定義的格式如下:類型名*指針名;其中,“類型名”說明指針所指變量的類型;星號“*”是一個指針運算符,說明“指針名”是一個“類型名”類型的指針而不是一個“類型名”類型的變量。指針可與非指針變量一起說明,如例8.1所示。例8.1

指針與非指針的定義。

char*pcl,*pc2;/*pcl和pc2均為指向char型的指針*/

float*pf,percent;/*pf是float型的指針,而percent為普通的float型變量*/指針的類型是使用指針時必須注意的問題之一。在例8.1中,pc1、pc2和pf都是指針,它們存放的都是內(nèi)存的地址,但這并不意味著它們的類型相同。實際上pc1和pc2是同類型的,而它們與pf的類型卻不同。在使用中,pc1和pc2只能夠存放字符型變量的地址,而pf只能夠存放浮點型變量的地址。指針的當前指向是使用指針的另一個需特別注意的問題。程序員定義一個指針之后,一般要使指針有明確指向,這一點可以通過對指針初始化或賦值來完成。與常規(guī)的變量未賦初值相同,沒有明確指向的指針不會引起編譯器出錯,但對于指針可能導致無法預(yù)料的或隱蔽的災(zāi)難性后果。例8.2

指針的指向。

int*point;

scanf("%d",point);例8.2中指向整型的指針point在定義之后直接使用了,這兩條語句在編譯時不會出現(xiàn)語法錯誤,但在使用時卻幾乎肯定會出問題。表面上看,scanf()函數(shù)的參數(shù)要求給出的是地址,而point的值就代表的是地址,但是point的值究竟是多少,也就是說point究竟指向哪里,我們無法得知,在這種情況下就對point指向的單元進行輸入操作,將沖掉point指向的單元的原有內(nèi)容,假如這個單元是操作系統(tǒng)的所在處,就破壞了操作系統(tǒng),顯然是一件危險的事。

2.指針的有關(guān)運算符兩個有關(guān)的運算符:

&:取地址運算符。*:指針運算符(或稱“間接訪問”運算符)。例如:&a為變量a的地址,*p為指針p所指向的存儲單元的內(nèi)容。

&運算符只能作用于變量,包括基本類型變量和數(shù)組的元素、結(jié)構(gòu)體類型變量或結(jié)構(gòu)體的成員(具體內(nèi)容見第九章),不能作用于數(shù)組名、常量或寄存器變量。例如:

doubler,a[20];

inti;

registerintk;表達式&r、&a[0]、&a[i]是正確的,而&(2*r)、&a、&k是非法表示。單目運算符*是&的逆運算,它的操作數(shù)是對象的地址,*運算的結(jié)果是對象本身。單目*稱為間訪運算符,“間訪”就是通過變量的地址而不是變量名存取(或引用)變量。例如,如果pc是指向字符變量c的指針,則*(&c)和*pc表示同一字符對象c。因而賦值語句:*(&c)=′a′;*pc=′a′;

c=′a′;效果相同,都是將′a′存入變量c。指針可以由帶有地址運算符的語句來使之有明確指向,如例8.3所示。例8.3

取地址運算符。

intvariable,*point;

point=&variable;

3.指針的使用在定義了指針并明確了它的指向后,就可以使用指針了。例8.4和例8.5給出了指針使用的簡單例子。例8.4

指針的使用。

#include<stdio.h>

voidmain()

{

inta,b,*p1,*p2;

a=10;b=20;

p1=&a;p2=&b;

printf("%d\t%d\n",*p1,*p2);

p1=&b;p2=&a;

printf("%d\t%d\n",*p1,*p2);

}運行結(jié)果:

10

20

20

10說明:

(1)在兩個printf()函數(shù)調(diào)用語句中的*是指針運算符,這一單目運算符的運算對象應(yīng)該是指針或地址,它的作用是得到指針指向變量的值。

(2)在第一個printf()函數(shù)調(diào)用時,可以假設(shè)內(nèi)存的分配如圖8.2所示。假設(shè)變量a占用的內(nèi)存單元為FFF4H和FFF5H,變量b占用的內(nèi)存單元為FFF2H和FFF3H,指針p1占用的內(nèi)存單元為FFF0H和FFF1H,指針p2占用的內(nèi)存單元為FFEFH和FFF0H,則它們的值分別是:10(000AH),20(0014H),F(xiàn)FF2H,F(xiàn)FF4H。*p1和*p2的值分別是20(0014H)和10(000AH),這就是第一個printf()函數(shù)調(diào)用所得到的結(jié)果。圖8.2內(nèi)存分配表(一)

(3)在第二個printf()函數(shù)調(diào)用時,可以假設(shè)內(nèi)存的分配如圖8.3所示。圖8.3內(nèi)存分配表(二)此時各變量所占用的內(nèi)存單元不變,但p1和p2的值分別為FFF4H和FFF2H,也就是它們此時分別指向b和a。這樣*p1和*p2的值分別是10(000AH)和20(0014H),所以第二個printf()函數(shù)調(diào)用所得到的結(jié)果為10(000AH)和20(0014H)。

例8.5

指針的使用。

#include<stdio.h>

voidmain()

{

inta,*pi;

floatf,*pf;

a=10;f=20.5;

pi=&a;pf=&f;

printf("%d\t%4.1f\n",a,f);

printf("%d\t%4.1f\n",*pi,*pf);

}運行結(jié)果:

1020.5

1020.5

說明:

(1)printf()函數(shù)調(diào)用時,可以假設(shè)內(nèi)存的分配如圖8.4所示。圖8.4內(nèi)存分配表假設(shè)變量a占用的內(nèi)存單元為FFF4H和FFF5H,浮點型變量f占用的內(nèi)存單元為FFEEH,F(xiàn)FEFH,F(xiàn)FF0H和FFF1H,指針pi占用的內(nèi)存單元為FFF2H和FFF3H,指針pf占用的內(nèi)存單元為FFECH和FFEDH,則它們的值分別是:10(0AH),20.5(3F80FF00H),F(xiàn)FF4H,F(xiàn)FEEH。*pi和*pf的值分別是10(0AH)和20.5(3F80FF00H),這就是printf()函數(shù)調(diào)用所得到的結(jié)果。

(2)printf()函數(shù)調(diào)用語句中的*pi和*pf雖然都是指針運算,但*pi是將pi的值(2000)開始的兩個內(nèi)存單元的值(10)作為運算結(jié)果,而*pf是將pf的值(2002)開始的四個內(nèi)存單元的值作為運算結(jié)果。這就是指針類型不同所帶來的結(jié)果,指針運算符會根據(jù)它的運算對象的類型進行相應(yīng)的運算。

(3)*既可用作指針運算符,也可用作乘號運算符。不必擔心編譯器不能分辨。在*附近總會有足夠的信息使編譯器能分辨是指針運算符還是乘號。

(4)用變量名來訪問變量的內(nèi)容稱為直接訪問;用指針來訪問變量的內(nèi)容稱為間接訪問,即間接地從指針中找到地址值,再據(jù)此地址訪問變量。直接訪問和間接訪問的結(jié)果是一樣的,正如本例中的兩條printf輸出的結(jié)果是相同的。由于&和*運算符在使用指針時經(jīng)常使用,二者優(yōu)先級相同,結(jié)合方向為自右至左,下面進行一些說明。假設(shè)已定義了整型變量a和整型指針point,并已執(zhí)行了“point=&a;”語句,則:

(1)&*point的含義,根據(jù)&和*運算符的優(yōu)先級和結(jié)合性可知,先進行*point運算,它就是變量a,再執(zhí)行&運算。因此&*point和&a相同,也就是point本身。

(2)*&point的含義,根據(jù)&和*運算符的優(yōu)先級和結(jié)合性可知,先進行&point運算,得到point的地址值,因為point作為一個變量,在內(nèi)存中分配單元,所以有確定的地址值。再執(zhí)行*運算,又得到point的值。

(3)*&a的含義,根據(jù)&和*運算符的優(yōu)先級和結(jié)合性可知,先進行&a運算,得到a的地址值,它就是指針point的值,再執(zhí)行*運算,因此*&a和*point相同,也就是a本身。

(4)&*a的含義,根據(jù)&和*運算符的優(yōu)先級和結(jié)合性可知,先進行*a運算,此時將整型變量a作為一個指針來運算,將a的值作為一個地址值對待,這是不允許的,所以&*a不允許使用。

(5)(*point)++相當于a++。如果去掉括號,即成為*point++,根據(jù)運算符的優(yōu)先級和結(jié)合性,它相當于*(point++),這時先按point的原值進行*運算,得到a的值。然后使point的值改變,之后point就不再指向a了。8.2指針作函數(shù)參數(shù)前面已經(jīng)講過,C在函數(shù)調(diào)用時參數(shù)的傳遞是按照單向值傳遞的方式,因而在被調(diào)用函數(shù)中形參的變化不能改變實參變量的值。

例8.6

函數(shù)參數(shù)的傳遞。

#include<stdio.h>

voidswap(intx,inty);

main()

{

inta,b;

a=10;b=20;

swap(a,b);

printf("a=%d,b=%d\n",a,b);

}

voidswap(intx,inty)

{

inttemp;

temp=x;

x=y;

y=temp;

}運行結(jié)果:

a=10,b=20可以看到,雖然在swap()函數(shù)中交換了x和y的值,但main()函數(shù)中a和b的值并未交換。其原因可在圖8.5和圖8.6中看出,在swap()函數(shù)調(diào)用時,a和b的值傳遞給x和y,而在swap()函數(shù)調(diào)用結(jié)束時雖然x和y的值交換了,但是它們所占用的存儲單元也隨swap()函數(shù)調(diào)用結(jié)束而釋放了,a和b的值并未改變。圖8.5swap()函數(shù)被調(diào)用時的內(nèi)存分配圖圖8.6swap()函數(shù)調(diào)用結(jié)束時的內(nèi)存分配圖為了達到交換主調(diào)函數(shù)中的變量a和b的目的,需要用指針作參數(shù)。通過將主調(diào)函數(shù)中變量的地址傳給被調(diào)用函數(shù)的指針形參,這樣,在被調(diào)用函數(shù)中對形參所指向內(nèi)容進行交換就是對主調(diào)函數(shù)中的變量a、b交換,從而達到交換變量a、b的值這一目的。

例8.7

指針作函數(shù)參數(shù)。

#include<stdio.h>

voidswap(int*x,int*y);

main()

{

inta,b,*p1,*p2;

a=10;b=20;p1=&a;p2=&b;

swap(p1,p2);

printf(“a=%d,b=%d\n”,a,b);

/*或printf("%d%d",*p1,*p2)*/

}

voidswap(int*pa,int*pb)

{

inttemp;

temp=*pa;*pa=*pb;*pb=temp;

}運行結(jié)果:

a=20,b=10可以看到,上例中主函數(shù)中以整型指針p1、p2作為swap()函數(shù)的實參,調(diào)用前已用賦值語句使p1指向變量a,p2指向變量b。swap()函數(shù)的形參pa和pb也是整型指針。從圖8.7中可以看到,在swap()函數(shù)被調(diào)用時,實參指針p1和p2分別把它們的值傳遞給形參指針pa和pb,可以認為指針p1和pa都指向變量a,而指針p2和pb都指向變量b。所以*pa就是引用a,*pb就是引用b,交換*pa和*pb就是交換a和b。*pa和*pb既是swap()函數(shù)的輸入?yún)?shù)又是輸出參數(shù),進入swap()時,*pa和*pb是交換之前的a、b,從swap()返回時,*pa和*pb是交換后的a、b,因為形參、實參本來就指向同一內(nèi)存單元,相當于形參所指向內(nèi)容的改變“返回”給了實參所指的內(nèi)容(如圖8.8所示)??梢姡ㄟ^將變量的地址傳遞給被調(diào)函數(shù),可在被調(diào)函數(shù)中改變這些變量的值。圖8.7swap()函數(shù)被調(diào)用時的內(nèi)存分配圖圖8.8swap()函數(shù)調(diào)用結(jié)束時的內(nèi)存分配圖程序運行的結(jié)果使a和b的值得以交換。是不是用指針作函數(shù)參數(shù)時,參數(shù)的傳遞就不是單向值傳遞了呢?事實上,用指針作函數(shù)參數(shù)時,參數(shù)的傳遞仍然符合由實參到形參的單向值傳遞。從圖8.7可以看到,在函數(shù)swap()調(diào)用過程中,交換了pa和pb所指向變量的內(nèi)容(注意,并未交換pa和pb本身的值),也就是交換了變量a和b的值。形參pa,pb和實參p1,p2本身的值均未改變。

swap()的形參pa和pb都是整型指針。于是,調(diào)用swap()時,傳給pa和pb的分別是a的地址和b的地址,為了對指針作函數(shù)參數(shù)進行充分說明,將例8.7進行一些改變,讓我們來分析下面兩個例子。例8.8

指針作函數(shù)參數(shù)。

#include<stdio.h>

voidswap(int*,int*);

voidmain()

{

inta,b,*p1,*p2;

a=10;b=20;p1=&a;p2=&b;

swap(p1,p2);

printf("a=%d,b=%d\n",a,b);

}

voidswap(int*pa,int*pb)

{

int*temp;

temp=pa;

pa=pb;

pb=temp;

}運行結(jié)果:

a=10,b=20例8.8與例8.7的不同之處在于例8.8的swap()函數(shù)中交換的是pa和pb本身的值,而并未交換它們所指向的變量a和b的值,所以最后得到的結(jié)果是變量a和b的值并未交換。從圖8.9和圖8.10中可以看到,函數(shù)swap()調(diào)用結(jié)束時指針pa和pb的值進行了交換,但這一交換不會影響到變量a和b,同樣也不會影響到指針p1和p2,這完全符合函數(shù)參數(shù)的單向值傳遞。圖8.9swap()函數(shù)被調(diào)用時的內(nèi)存分配圖圖8.10swap()函數(shù)調(diào)用結(jié)束時的內(nèi)存分配圖

例8.9

指針作函數(shù)參數(shù)。

#include<stdio.h>

voidswap(int*,int*);

voidmain()

{

inta,b,*p1,*p2;

a=10;b=20;p1=&a;p2=&b;

swap(p1,p2);

printf("a=%d,b=%d\n",a,b);

}

voidswap(int*pa,int*pb)

{

int*temp;*temp=*pa;*pa=*pb;*pb=*temp;

}對于這個例子我們沒有給出運行結(jié)果,這是因為這個例子中有不安全的因素。在swap()函數(shù)中的指針temp在沒有明確指向的情況下就試圖對它所指向的變量進行了操作,這是指針使用中所不允許的。當然,也許在某些系統(tǒng)中,這個程序可以得到運行結(jié)果,即

a=20,b=10但這個程序還是有問題的,必須要經(jīng)過改進才可以??梢詫wap()函數(shù)改變成這樣:

voidswap(int*pa,int*pb)

{

int*temp,t;

temp=&t;*temp=*pa;*pa=*pb;*pb=*temp;

}

此時可以得到運行結(jié)果:

a=20,b=10其原因與例8.7一樣,這里不再重復(fù)。通過以上例題可以總結(jié)出:如果想通過函數(shù)調(diào)用得到n個要改變的值,可以:

(1)在主調(diào)函數(shù)中設(shè)n個變量,用n個指針指向它們。

(2)用指針作實參,將這n個變量的地址傳給所調(diào)用的函數(shù)的形參(也可直接用n個變量的地址作實參來簡化以上兩步)。

(3)通過形參指針,改變該n個變量的值。

(4)在主調(diào)函數(shù)中使用這些改變了值的變量。其它具體示例可參考《〈C程序設(shè)計〉學習指導(第二版)》中本章的典型例題。不論是用普通變量還是用指針作函數(shù)參數(shù),都不違反函數(shù)參數(shù)的由實參到形參的單向值傳遞,只是用指針作函數(shù)參數(shù)時,因為指針的值就是地址,所以傳遞的是地址,此時雖然形參的改變?nèi)詿o法返回給實參,但利用形參指針對其所指向單元內(nèi)容的操作,就有可能改變主調(diào)函數(shù)中的變量的值。這樣往往使函數(shù)的功能更為完善和強大,C的許多標準函數(shù)都采用這種方式,結(jié)構(gòu)化程序設(shè)計方法要求函數(shù)間以此種方式來傳遞數(shù)據(jù),所以這是指針的一個很重要的應(yīng)用,需要進行大量的實踐去體會與掌握。8.3指針與數(shù)組

C語言中數(shù)組與指針有著密切的聯(lián)系,在編程時完全可以用指針代替下標引用數(shù)組的元素,且使數(shù)組的引用更為靈活、有效。當一個數(shù)組被定義后,程序會按照其類型和長度在內(nèi)存中為數(shù)組分配一塊連續(xù)的存儲單元。數(shù)組名成為符號常量,其值為數(shù)組在內(nèi)存中所占用單元的首地址,也就是說數(shù)組名就代表了數(shù)組的首地址。指針就是用來存放地址的變量,當某個指針存放數(shù)組中第一個元素的地址時,可以說該指針指向了這個數(shù)組,這樣我們可以通過指針運算間接訪問數(shù)組中的元素。8.3.1指向一維數(shù)組的指針我們已經(jīng)知道,如下的語句:

inta[10];定義了a是長度為10的一個整型數(shù)組,a[i](i=0,1,…,9)是a的第i個元素。為了用指針表示a的元素,需要定義一個與a的元素同類型的指針,例如:

int*pa;并由賦值語句

pa=&a[0];或pa=a;使pa指向a的第0個元素,習慣上稱為使pa指向數(shù)組a,如圖8.11所示。也可在定義時賦初值,即

inta[10],*pa=a;或

inta[10],*pa=&a[0];然后,只要移動指針pa,就可訪問數(shù)組a的任一元素。圖8.11指向數(shù)組元素的指針如果pa指向a[0],則(pa+i)指向a[i];如果pa指向a[i],則pa+1(pa不變)或++pa(pa增1)指向a[i+1]。如果pa指向a[0],則*pa等價于a[0];如果(pa+i)指向a[i],則*(pa+i)等價于a[i]。同理,如果(pa+1)指向a[i+1],則*(pa+1)等價于a[i+1]。概括地說,指向數(shù)組的指針加1等效于數(shù)組元素的下標加1。類似的,如果pa指向a[i],則*(++pa)等價于a[++i]。實際上,C語言允許這樣的表達方式:pa[i]和*(a+i),它們等價于*(pa+i)和a[i]。由此可見,引用數(shù)組元素有兩種等價的形式:通過下標引用和通過指針引用。以數(shù)組a為例,假定pa指向a[0],元素的下標引用和指針引用的對應(yīng)關(guān)系如下(寫在同一行上的表達式是對同一元素的等價引用形式):

a[0] *pa *a或*(a+0) a[1] *(pa+1) *(a+1) a[2] *(pa+2) *(a+2) a[9] *(pa+9) *(a+9)元素地址的對應(yīng)關(guān)系如下:

&a[0] pa a或a+0 &a[1] pa+1 a+1 &a[2] pa+2 a+2 &a[9] pa+9 a+9

注意:指針pa是變量,數(shù)組名a是常量,因而

pa=a;pa++;是合法的操作,而

a=pa;a++;pa=&a;都是非法的。說明:

(1)如果數(shù)組名a的值為2000,也就是數(shù)組a在內(nèi)存中的首地址為2000。若執(zhí)行了pa=a,則pa的值也為2000。那么,pa+2的值是多少呢?pa+2的值為2000+2×sizeof(int),假設(shè)在我們所使用的系統(tǒng)中int型所占的字節(jié)為2,則pa+2的值為2004,即元素a[2]的地址。指針加1,不是簡單地將指針的值加1,而是指向下一個數(shù),系統(tǒng)會根據(jù)類型自動地計算地址。

(2)當指針指向數(shù)組時,可通過數(shù)組名和指針兩種方式來訪問數(shù)組元素,因為指針是變量而數(shù)組名是常量,所以指針的值可以改變,這就需要特別注意指針的當前指向,是指向了數(shù)組的哪個元素?還是已經(jīng)指向了數(shù)組所占內(nèi)存空間以外的地方?如果已經(jīng)指向了數(shù)組所占內(nèi)存空間以外的地方,則一般會出問題,這是指針使用中常出錯之處,也是指針使用中最危險之處。

(3)*pa++的意義:*和++的優(yōu)先級相同,且為右結(jié)合性,*pa++則相當于*(pa++),它與(*pa)++是不同的,雖然兩個表達式的值是相同的。前者的意思是先取*pa的值,并作為表達式的值,后使pa加1;后者是先取*pa的值,并作為表達式的值,后使*pa加1。注意,兩者自增的對象是不同的。8.3.2數(shù)組作函數(shù)參數(shù)當我們需要將數(shù)組的首地址作為函數(shù)參數(shù)來傳遞時,可采用的方式有兩種。一種是用指向數(shù)組的指針作為函數(shù)參數(shù);另一種是直接用數(shù)組名作為函數(shù)參數(shù)。指針和數(shù)組名都可以作為形參和實參,它們既可以同時作為形參和實參,也可以分別作為形參和實參。這樣可有四種情況:

(1)形參和實參都是指針時,這種情況與8.2節(jié)所討論的問題相似,只是此時實參存放的是某個數(shù)組的首地址,并把這個地址傳遞給形參。

(2)實參是數(shù)組名,形參是指針時,這種情況是同類型的常量實參傳遞給變量形參,此時,對形參指針所指向內(nèi)容的訪問就是對數(shù)組的訪問。

(3)形參和實參都是數(shù)組名時,這時有一些特殊性。因為按照數(shù)組的定義,數(shù)組名應(yīng)該是存放數(shù)組首地址的常量,而此時形參的值卻會在函數(shù)調(diào)用時得到實參傳遞的值,這豈不是矛盾了嗎?實際上,雖然有實參數(shù)組名和形參數(shù)組名兩個數(shù)組名,卻只有一個數(shù)組,也就是在這種情況下,C語言不會給形參數(shù)組再開辟一個數(shù)組的內(nèi)存單,而是認為形參數(shù)組名是實參數(shù)組的別名,也就是說,對形參數(shù)組的操作就是對實參數(shù)組的操作。

(4)實參是指針,形參是數(shù)組名,這與上一問題有些相似。系統(tǒng)認為實參指針是指向某個數(shù)組的,此時形參數(shù)組與實參所指向的數(shù)組是同一數(shù)組,且為該數(shù)組的別名。

例8.10

數(shù)組名作函數(shù)參數(shù)。程序功能:用選擇法對10個整數(shù)排序。

#include<stdio.h>

voidmain()

{

int*p,i,a[10];

p=a;

for(i=0;i<10;i++)

scanf("%d",p++);

p=a;

sort(p,10);

for(p=a,i=0;i<10;i++)

{

printf("%5d",*p);

p++;}printf("\n");

}

voidsort(intx[],intn)

{

inti,j,k,t;

for(i=0;i<n-1;i++)

{k=i;

for(j=i+1;j<n;j++)

if(x[j]>x[k])k=j;

if(k!=i)

{t=x[i];x[i]=x[k];x[k]=t;}

}

}函數(shù)sort()的形參x可以認為是main()函數(shù)中數(shù)組a的別名,所以在函數(shù)sort()中對x的操作就是對a的操作,使得數(shù)組a得以排序,完成了程序的要求。注意在main()函數(shù)中使用指針p時,指針當前指向的變化。當然,main()函數(shù)中調(diào)用sort()函數(shù)時實參可以是指針,也可以是數(shù)組名,在函數(shù)sort()中形參可以是數(shù)組名,也可以是指針??蓪⑸侠某绦蚋膶懭缦拢?/p>

#include<stdio.h>

voidsort(int*,int);

voidmain()

{

inti,a[10];

for(i=0;i<10;i++)

scanf("%d",&a[i]);

sort(a,10);

for(i=0;i<10;i++)

printf("%5d",a[i]);

}

voidsort(int*x,intn)

{

inti,j,k,t;

for(i=0;i<n-1;i++)

{

k=i;

for(j=i+1;j<n;j++)

if(x[j]>x[k])k=j;

if(k!=i)

{t=x[i];x[i]=x[k];x[k]=t;

}

}可以看到在函數(shù)sort()中,除了對形參x的類型說明有一點變化,程序的其它部分沒有改變。雖然x此時是指針,用它訪問數(shù)組元素時可以用下標法,也可用指針法。如將x[j]寫成*(x+j),x[k]寫成*(x+k),x[i]寫成*(x+i)。另外,此例值得注意之處是對“自頂向下,逐步細化,模塊化”的結(jié)構(gòu)化程序設(shè)計思想的典型體現(xiàn)。在第七章的開始,我們已講述了結(jié)構(gòu)化的程序設(shè)計思想,強調(diào)一個函數(shù)應(yīng)只完成單一的任務(wù)。對于本題用選擇法排序便是這樣一個功能單一的最小任務(wù)。而其它功能,如數(shù)組的輸入/輸出等則在其主調(diào)函數(shù)中完成,這是高級語言編寫結(jié)構(gòu)化程序的常見模式。8.3.3指針和字符串在C語言中,字符串(例如"Iamastudent")指在內(nèi)存中存放的一串以′\0′結(jié)尾的若干個字符。在沒有學習指針之前,我們已經(jīng)知道可以用字符數(shù)組來表達一個字符串。例如,可以這樣定義和初始化一個字符數(shù)組:

charstring[]="Iamastudent";數(shù)組長度由字符串長度加1確定。也可以定義一個字符數(shù)組,然后用標準輸入函數(shù)從外部設(shè)備讀入一個字符串。例如:

charstring[20];

scanf("%s",string);數(shù)組長度應(yīng)能足夠存放讀入的最大長度的字符串。利用指針也可以表達字符串,而且比用字符數(shù)組更為方便靈活。例如,可以這樣定義和初始化一個字符指針:

char*point="Iamastudent";point是指向字符串"Iamastudent"的指針,即字符串的首地址賦給了字符指針,因此使一個字符指針指向一個字符串。也可以采用下面的方式:

char*point;

point="Iamastudent";賦值語句“point="Iamastudent";”不是串拷貝,實際上,字符串常量"Iamastudent"的值就是該字符串在內(nèi)存中的首地址,這樣這個賦值語句就很容易理解了,相當于指針point中存放了字符串的首地址,從這一點也可以看出字符串與指針的關(guān)系更為密切。下面這種情況同樣是不允許的:

char*point;

scanf("%s",point);其原因是指針沒有明確的指向,其值是任意的,也許所指向的區(qū)域不是用戶可以訪問的內(nèi)存區(qū)域,或是根本不存在的地方。雖然字符數(shù)組和字符指針都可以用來表達字符串,但它們還是有不同之處。例如:

charstring[]="Iamastudent";

char*point="Iamastudent";string和point的值都是字符串"Iamastudent"的首地址,但string是一個字符數(shù)組,名字本身是一個地址常量,而point是值為字符數(shù)組首地址(第0個元素的地址)的指針。因而point可以被賦值,而string不能,即

point="Iamastudent";合法

string=“Iamastudent”;非法指向字符串的指針常常出現(xiàn)在函數(shù)參數(shù)中,下面舉幾個例子。

例8.11

字符串拷貝函數(shù)。

voidmy_strcpy(char*t,char*s)

{

while((*t=*s)!=′\0′)

{

s++;

t++;

}

}函數(shù)my_strcpy()將串s復(fù)制到串t,準確地講是將s指向的字符串復(fù)制到由t指向的字符數(shù)組。開始時,t和s分別指向兩個實參數(shù)組的頭元素,復(fù)制一個元素;然后各自的指針移向下一個元素,復(fù)制下一個元素;……這一過程進行到字符′\0′被復(fù)制為止,此時串s被全部復(fù)制到t。調(diào)用my_strcpy()時,對應(yīng)于目的串t的實參可以是字符數(shù)組名或指向字符數(shù)組的指針;對應(yīng)于源串s的實參可以是字符串、字符數(shù)組名或指向字符串的指針。例如:

chars1[20],s2[20],*ps1,*ps2;下面對my_strcpy()函數(shù)的調(diào)用都是正確的:

(1)my_strcpy(s1,"Iamastudent");

(2)ps1=&s1[0];

ps2="Iamastudent";

my_strcpy(ps1,ps2);

(3)ps2=&s2[0];

my_strcpy(ps2,"Iamastudent");

my_strcpy(s1,s2);或my_strcpy(s1,ps2);以上三組語句是等效的,都是將串"Iamastudent"復(fù)制到字符數(shù)組s1。

my_strcpy的定義可以寫成更簡練的形式:

voidmy_strcpy(char*t,char*s)

{

while((*t++=*s++)!=′\0′);

}復(fù)制過程繼續(xù)的條件是被復(fù)制的字符為非0(非′\0′)。由于組成字符串的任何字符(′\0′除外)的值都為非0,因此my_strcpy()還可以進一步簡化為:

voidmy_strcpy(char*t,char*s)

{

while(*t++=*s++);

}例8.12

字符串比較函數(shù)。

intmy_strcmp(char*s,char*t){

for(;*s==*t;s++,t++)

if(*s==′\0′)return0;

return(*s-*t);

}函數(shù)my_strcmp()按字典順序逐個比較串s和t的每個對應(yīng)元素,如果s和t的長度相同且所有元素都相等,則s和t相等,my_strcmp()返回值0;否則s和t不相等。當?shù)谝淮纬霈F(xiàn)不相等元素時,my_strcmp()結(jié)束比較,較小的那個字符所在的那個串較小,反之為大。當s<t時,返回值小于0;當s>t時,返回值大于0。8.3.4指向多維數(shù)組的指針在研究多維數(shù)組的問題時,我們可以將數(shù)組僅僅看作是C語言的一個構(gòu)造類型,其元素可以是C語言的任何類型,包括數(shù)組本身。也就是說,數(shù)組可以作為另一個數(shù)組的數(shù)組元素。這樣,就不存在多維數(shù)組的問題了??梢哉f在C語言中,數(shù)組在實現(xiàn)方法上只有一維的概念,多維數(shù)組被看成以下一級數(shù)組為元素的數(shù)組。設(shè)有一個二維數(shù)組的定義為:

staticinta[2][4]={{1,3,5,7},{2,4,6,8}};表面上看,a是一個二維數(shù)組名,我們也可以將它看成是一個一維數(shù)組名。它包含兩個數(shù)組元素,分別為a[0]和a[1]。每個數(shù)組元素又包含四個元素,例如,數(shù)組a[0]包含四個元素,分別為:a[0][0]、a[0][1]、a[0][2]和a[0][3]。a[0]和a[1]雖然沒有單獨地、顯式地定義,它們卻可以被認為是數(shù)組名,是數(shù)組在內(nèi)存中的首地址,這一點與數(shù)組名a一樣,與a不同的是類型,也就是數(shù)組元素的類型不同。a[0]和a[1]數(shù)組的元素類型為整型數(shù),而a數(shù)組的元素類型為整型數(shù)組。我們可以假設(shè)數(shù)組a在內(nèi)存中的分配情況如下:可以看到對于數(shù)組a來說,它所占用的內(nèi)存空間是連續(xù)的。如果我們將a視為一維數(shù)組的話,那么它的兩個數(shù)組元素a[0]和a[1]所占用的內(nèi)存也是連續(xù)的,此時每個數(shù)組元素占用8個內(nèi)存單元。當然如果將a視為二維數(shù)組的話,它的8個數(shù)組元素所占用的內(nèi)存也是連續(xù)的,此時每個數(shù)組元素占用2個內(nèi)存單元。數(shù)組a一旦有了以上的定義后,在C語言的程序中可用的與數(shù)組a有關(guān)的表示形式有很多。為了更清楚地說明,我們可以把二維數(shù)組a看成是一個兩行四列的形式。這樣對于二維數(shù)組可以認為a為首行地址(即第0行地址),而a+1為第1行地址;a[0]為首行首列地址,而a[0]+1為第0行第1列地址。詳細區(qū)分說明如下:

對行地址進行一次指針運算就成為列地址,而對列地址進行一次取地址運算就成為行地址,這就很容易理解雖然a+1和*(a+1)具有相同的值,但卻表示不同的類型。

例8.13

多維數(shù)組。

#include<stdio.h>

voidmain()

{

staticinta[3][4]={{1,3,5,7},{2,4,6,8},{10,20,30,40}};

int*p;

for(p=a[0];p<a[0]+12;p++)/*注1*/

{

if((p-a[0])%4==0)printf("\n");/*注2*/

printf("%4d",*p);

}

}運行結(jié)果:

1357

2468

10203040程序中指針p為一個可以存放整型量地址的變量,在程序的第5行將第0行第0列地址賦給它,實際上行地址也是某個整型量的地址,所以可以這樣做。如果將注1行的a[0]改成a,是否可以呢?不行!雖然a和a[0]的值相同,但類型卻不同,這樣做是不合法的。那么是否可以將注2行的a[0]用a替換呢?也不行!因為指針的加減運算結(jié)果是受到類型影響的,不同類型之間的運算是無法進行的。既然我們用整型指針來存放列地址,那么如何定義行指針來存放行地址呢?下面就是行指針的定義方式。類型名(*指針名)[數(shù)組長度];約束行指針類型的條件有兩個,一是它所指向數(shù)組的類型;一是每行的列數(shù)。下面用行指針來改寫例8.13。

例8.14

多維數(shù)組。

#include<stdio.h>

voidmain()

{

staticinta[3][4]={{1,3,5,7},{2,4,6,8},{10,20,30,40}};

inti,j,(*p)[4];

p=a;

for(i=0;i<3;i++)

{

for(j=0;j<4;j++)

printf("%4d",*(*(p+i)+j));

printf("\n");

}

}運行結(jié)果:

1357

2468

10203040

注意程序中的表達式*(*(p+i)+j)還可以表示成p[i][j]和(*(p+i))[j]。使用多維數(shù)組時一定要注意類型問題,下面以二維數(shù)組為例來說明使用多維數(shù)組作函數(shù)參數(shù)時應(yīng)注意的問題。

(1)形參說明為指向數(shù)組元素的指針,實參為數(shù)組元素的地址或指向元素的指針。例如:調(diào)用函數(shù)f(),用數(shù)組元素的地址作實參:

inta[2][3];

voidf(int*,int);

f(a[0],2*3);

a[0]是元素a[0][0]的地址,f(a[0],2*3)調(diào)用也可以寫成f(&a[0][0],2*3)。2*3是元素的個數(shù)。調(diào)用函數(shù)f(),用指向數(shù)組元素的指針作實參:

inta[2][3],*pi;

voidf(int*,int);

pi=a[0];/*或pi=&a[0][0]*/

f(pi,2*3);

pi是指向元素a[0][0]的指針。函數(shù)f()的定義:

voidf(int*pi,intsize)

{

}形參pi說明為列指針。

(2)形參說明為行指針,實參為行地址或行指針。例如,調(diào)用函數(shù)f(),用行指針作實參:

inta[2][3];

voidf(int(*)[3],int);

f(a,2);

實參a是行指針,類型為int(*)[3];實參2是二維數(shù)組a的行數(shù)。調(diào)用函數(shù)f(),用行指針作實參:

inta[2][3],(*pa)[3];

voidf(int(*)[3],int);

pa=a;

f(pa,2);

pa是行指針,賦值語句“pa=a;”使pa指向a的第0行,pa的類型與a的類型相同。函數(shù)f()的定義:

voidf(int(*pa)[3],intsize)

{

}例8.15

行指針作函數(shù)參數(shù)。輸入一個用年、月、日表示的日期,定義函數(shù)day_of_year()將它轉(zhuǎn)換成該年的第幾天;輸入某年的第幾天,定義函數(shù)month_day()將它轉(zhuǎn)換成該年的某月某日。

#include<stdio.h>/*day_of_year:從月份和日期計算為一年中的第幾天*/

intday_of_year(intyear,intmonth,intday,int*pi)

{

inti,leap;

leap=year%4==0&&year%100!=0||year%400==0;

for(i=1;i<month;i++)

day+=*(pi+leap*13+i);

return(day);

}/*month_day:從一年中的第幾天計算月份和日期*/

voidmonth_day(intyear,intyday,int(*pdaytab)[13],int*pmonth,int*pday)

{

inti,leap;

leap=year%4==0&&year%100!=0||year%400==0;

for(i=1;yday>*(*(pdaytab+leap)+i);i++)

yday-=*(*(pdaytab+leap)+i);*pmonth=i;*pday=yday;

}

intmain(void)

{

intdaytab[2][13]={

{0,31,28,31,30,31,30,31,31,30,31,30,31},

{0,31,29,31,30,31,30,31,31,30,31,30,31}

},y,m,d,yd;

printf("inputyear,month,day:\n");

scanf("%d%d%d",&y,&m,&d);

yd=day_of_year(y,m,d,&daytab[0][0]);

printf("dayofyearis%d\n",yd);

printf("inputyear,day_of_year:\n");

scanf("%d%d",&y,&yd);

month_day(y,yd,daytab,&m,&d);

printf("%d,%din%d\n",m,d,y);

return0;

}運行結(jié)果:

inputyear,month,day: (輸出)

19951211↙ (輸入)

dayofyearis345 (輸出)

inputyear,day_of_year: (輸出)

1994280↙ (輸入)

10,7in1994 (輸出)

day_of_year()函數(shù)的返回值為轉(zhuǎn)換后的該年第幾天;形參year、month和day是輸入的年、月、日信息;pi是指向一個整型變量的指針,調(diào)用時傳給pi的是數(shù)組daytab的首地址。局部變量leap根據(jù)年號year是平年還是閏年分別置為0和1,leap起著daytab數(shù)組行下標的作用:如果year是平年,leap為0,計算時使用第0行元素;否則leap為1,使用第1行元素。*(pi+leap*13+i)根據(jù)leap的值引用第0行的第i個元素或第1行的第i個元素,其中l(wèi)eap*13是當year為閏年時指針越過第0行元素。day的初值是調(diào)用時傳給它的某月的天數(shù),循環(huán)共執(zhí)行(month-l)次,使day的累加和為年號year的第day天。因而day就是函數(shù)day_of_year()的返回值。函數(shù)month_day()無返回值。形參year和day是輸入的年號和該年第幾天的信息。

pdaytab是指向含有13個整型元素的數(shù)組的指針,調(diào)用時傳給它的是daytab數(shù)組第0行的首地址,即*pdaytab或*(pdaytab+0)是指向第0行的指針,當year為閏年時(leap為1),*(pdaytab+leap)越過第0行,指向第1行的第0個元素;形參pmonth和pday是指向整型變量的指針,調(diào)用時傳給pmonth和pday的分別是變量m和d的地址,返回時變量m和d分別為轉(zhuǎn)換結(jié)果月和日。8.3.5指針數(shù)組指針變量可以同其它變量一樣作為數(shù)組的元素,由指針變量組成的數(shù)組稱為指針數(shù)組,組成數(shù)組的每個元素都是相同類型的指針。指針數(shù)組說明的形式為:

類型名*數(shù)組名[常量表達式]:其中“*數(shù)組名[常量表達式]”是指針數(shù)組說明符。例如:

int*ps[10];說明:ps是含有10個元素的指針數(shù)組,每個元素是一個指向int型變量的指針。注意:int*ps[10]不同于int(*ps)[10],后者說明ps是一個指向有10個int型元素的數(shù)組的指針。因為[]的優(yōu)先級高于*,所以int*ps[10]的解釋過程為:ps是一個數(shù)組,它含有10個元素;每個元素是一個int指針。指針數(shù)組可以與其它同類型對象在一個說明語句中說明。例如:

charc,*pc,*name[5];

floatx,*px[5];c是一個字符變量;pc是一個字符指針;name是含有5個元素的指針數(shù)組,每個元素是一個字符指針。x是一個float變量;px是含有5個元素的指針數(shù)組,每個元素是一個float指針。指針數(shù)組的主要用途是表示二維數(shù)組,尤其是表示字符串的數(shù)組。用指針數(shù)組表示二維數(shù)組的優(yōu)點是:每一個字符串可以具有不同的長度。用指針數(shù)組表示字符串數(shù)組處理起來十分方便靈活。設(shè)有二維數(shù)組說明:

inta[4][4];用指針數(shù)組表示數(shù)組a,就是把a看成4個一維數(shù)組,并說明一個有4個元素的指針數(shù)組pa,用于集中存放a的每一行元素的首地址,且使指針數(shù)組的每個元素pa[i]指向a的相應(yīng)行。于是可以用指針數(shù)組名pa或指針數(shù)組元素pa[i]引用數(shù)組a的元素。指針數(shù)組pa的說明和賦值如下:

int*pa[4],a[4][4];

pa[0]=&a[0][0];或pa[0]=a[0];

pa[1]=&a[1][0];或pa[1]=a[1];

pa[2]=&a[2][0];或pa[2]=a[2];

pa[3]=&a[3][0];或pa[3]=a[3];*(*(pa+i)+0),*pa[i]或*(pa[i]+0)(i=0,1,2,3)引用第i行第0列元素a[i][0];*(*(pa+i)+1)或*(pa[i]+1)引用第i行第1列元素a[i][1];…。用指針數(shù)組表示二維數(shù)組在效果上與數(shù)組的下標表示是相同的,只是表示形式不同。用指針數(shù)組表示時,需要額外增加用作指針的存儲開銷;但用指針方式存取數(shù)組元素比用下標速度快,而且每個指針所指向的數(shù)組元素的個數(shù)可以不相同。例如,可用有5個元素的指針數(shù)組和5個不同長度的整型數(shù)組來描述下面的三角矩陣:

a00

a10

a11

a20

a21

a22

a30

a31

a32

a33

a40

a41

a42

a43

a44存儲三角矩陣的數(shù)組和每一行的指針可說明如下:

inta1[1],a2[2],a3[3],a4[4],a5[5],*pa[5];下面的語句使pa的每個元素指向三角矩陣的每一行:

pa[1]=&a1[0];

pa[2]=&a2[0];

pa[3]=&a3[0];

pa[4]=&a4[0];

pa[5]=&a5[0];對照前面所講二維數(shù)組的指針表示可以看出,用指針數(shù)組表示二維數(shù)組其實質(zhì)就是用指針表示二維數(shù)組,只是用指針數(shù)組更直觀、更方便而已(主要體現(xiàn)在處理字符串數(shù)組上)。用指針數(shù)組表示二維數(shù)組的方法可以推廣到三維以上數(shù)組。例如,對三維數(shù)組來說,指針數(shù)組元素的個數(shù)應(yīng)與左邊第一維的長度相同,指針數(shù)組的每個元素指向的是一個二維數(shù)組,而且每個二維數(shù)組的大小也可以不同。指針數(shù)組不經(jīng)常用于描述整型、浮點型等多維數(shù)組,用得最多的是描述由不同長度的字符串組成的數(shù)組。8.4指針與函數(shù)指針除了可以作為函數(shù)參數(shù)外,它與函數(shù)本身還有兩方面的關(guān)系。一方面,對于指針來說,它可以是指向函數(shù)的,也就是說,指針存放的是函數(shù)的入口地址。另一方面,對于函數(shù)來說,它的返回值可以是一個地址,我們可以將該函數(shù)的返回值定義為某種類型的指針。8.4.1指向函數(shù)的指針對于函數(shù)和數(shù)組來說,可以通過函數(shù)名和數(shù)組名來訪問它們,也可以通過指向它們的指針來訪問,這一點是類似的。

C語言可以定義指向函數(shù)的指針,函數(shù)型指針的定義形式為:類型標識符(*指針名)();例如:

int(*fp)();說明:fp是指向int類型函數(shù)的指針。與指向數(shù)組的指針說明類似,說明符中用于改變運算順序的()不能省。如果將(*fp)()寫成*fp(),則fp成為返回值為指針類型的函數(shù)。指向函數(shù)的指針是存放函數(shù)入口地址的變量,一個函數(shù)的入口地址由函數(shù)名表示,它是函數(shù)體內(nèi)第一個可執(zhí)行語句的代碼在內(nèi)存中的地址。如果把函數(shù)名賦給一個指向函數(shù)的指針,就可以用該函數(shù)型指針來調(diào)用函數(shù)。函數(shù)型指針可以被賦值,可以作為數(shù)組的元素,可以傳給函數(shù),也可以作為函數(shù)的返回值。其中常用的是將函數(shù)名傳給另一函數(shù)。C語言允許將函數(shù)的名字作為函數(shù)參數(shù)傳給另一函數(shù),由于參數(shù)傳遞是單向值傳遞,相當于將函數(shù)名賦給形參,因此在被調(diào)用函數(shù)中,接收函數(shù)名的形參是指向函數(shù)的指針。被調(diào)用函數(shù)可以通過函數(shù)的指針來調(diào)用完成不同功能的具體函數(shù)。下面的簡單例子說明函數(shù)指針的用法。

例8.16

指向函數(shù)的指針。設(shè)一個函數(shù)operate(),在調(diào)用它的時候,每次實現(xiàn)不同的功能。輸入a和b兩個數(shù),第一次調(diào)用operate()得到a和b中最大值,第二次得到最小值,第三次得到a與b之和。

#include<stdio.h>

voidmain()

{

voidoperate();

intmax(),min(),sum(),a,b;

/*必須進行函數(shù)聲明,否則無法調(diào)用*/

printf("Entertwonumber:");

scanf("%d%d",&a,&b);

printf("max=");operate(a,b,max);

printf("min=");operate(a,b,min);

printf("sum=");operate(a,b,sum);

}

intmax(intx,inty)

{

if(x>y)return(x);

elsereturn(y);

}

intmin(intx,inty)

{

if(x<y)return(x);

elsereturn(y);

}

intsum(intx,inty)

{

return(x+y);

}

voidoperate(intx,inty,int(*fun)())

{

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論