




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第9章指針
本章要點(diǎn):
0指針的概念
0指向數(shù)組的指針
0指針的各種應(yīng)用
9.1指針與指針變量
■指針是C語言中的一個(gè)重要概念,也是C語言的重要
■指針類型是C語言的一種特殊的數(shù)據(jù)類型。正確而
靈活地應(yīng)用指針,可以有效地表示復(fù)雜的數(shù)據(jù)結(jié)構(gòu)、
動(dòng)態(tài)地分配內(nèi)存、方便地使用字符串、有效而方便
地使用數(shù)組、直接處理內(nèi)存地址等。使用指針編寫
的程序在代碼質(zhì)量上比用其他方法效率更高,因此
指針在C程序中用得非常多。指針是C語言的精華所
在,同時(shí)也是c語言的難點(diǎn)之一。學(xué)習(xí)指針應(yīng)該充
分地理解指針的概念,在上機(jī)實(shí)踐中進(jìn)一步掌握它。
2
9.L1指針的概念
指針是一種數(shù)據(jù)類型,是一個(gè)變量在內(nèi)存中所對(duì)應(yīng)單元的
地址。
這個(gè)地址可以是變量的地址,也可以是數(shù)組、函數(shù)的起始
地址,還可以是一個(gè)指針變量的地址。
3
變量一經(jīng)定義,系統(tǒng)為其分配存儲(chǔ)單元。
如:inta=10,b=8;
內(nèi)存中的每個(gè)字節(jié)有編號(hào),稱之為地址。
訪問變量有直接和間接兩種方式
■直接訪問方式:按變量的
□地址,直接存取變量侑。
■如:a=10;
■或:scanff6%d?\&b);
將鍵盤輸入的數(shù),送到
地址為2002開始的存儲(chǔ)單元。
內(nèi)存
4
■間接訪問方式:將變量a的地址存放在另一個(gè)變量
p中。
■取a中數(shù)的過程:先通過p的內(nèi)容,得到a的地址
2000,再到地址為2000的存儲(chǔ)單元中取出數(shù)10。
■變量的地址稱為指針。
■存放地址的變量p稱為
指針變量。
5
9.1.2指針變量的定義
■定義格式:類型名*指針變量名
■例如:/*定義指向整型變量的指針*/
■float*p2;/*定義指向?qū)嵭妥兞康闹羔?/
o
■使指針pl指向整型變量i:pl1
■pl=&i;
■使指針p2指向?qū)嵭妥兞縡:p2
■p2=&f;&f
■注意:指針變量只能放地址。
6
9.1.3指針變量的兩種運(yùn)算符
C語言提供了兩種指針運(yùn)算符:
&:取地址運(yùn)算符。
*:指針內(nèi)容運(yùn)算符(也稱為:間接訪問運(yùn)算符)
例如:intx=10,*p,y;
p=&x;/*將變量x的地址賦給指針變量p*/
*p是P所指向的變量。
y=*p;/*等價(jià)于y=x*/
7
■&和*兩個(gè)運(yùn)算符優(yōu)先級(jí)相同
□結(jié)合性:從右到左。
若有int*p;p=&a;
(1)則&*p的含義:即相當(dāng)于&(*p)
先執(zhí)行*P操作,即訪問a,
再進(jìn)行&操作:即所以&*p等價(jià)于
(2)而*&a的含義:即相當(dāng)于*(&a),
先執(zhí)行&a,得到a的地址,
再對(duì)該地址取*操作:*(&a),得到a的值。
所以*&a等價(jià)于*p,等價(jià)于a。
8
■*與++優(yōu)先級(jí)相同。
(1)*p++即相當(dāng)于*(p++)
執(zhí)行p++,先用p的原值,執(zhí)行*p得a;然后執(zhí)行p++,
p將示指向aTo
(2)(*p)++等價(jià)于:a++
■因?yàn)?p就是a,(*p)++就是(a)++,即a++
9
如果:intx=10,y,*px;
且有:px=&x;
則變量X與指向變量X的指針px之間有以下等價(jià)關(guān)系:
y=*px;等價(jià)于y=x;
(*px)++;等價(jià)于x++;/*對(duì)指針變量px的內(nèi)容加1
*/
y=(*px)+5;等價(jià)于y=x+5;
y=*(&x);等價(jià)于y=x;/*y二變量x地址的內(nèi)容
*/
C語言中用NULL表示空指針。若有語句:p=NULL;表示
指針P為空,沒有指向任何對(duì)象。
10
注意:
L&運(yùn)算符只能作用于變量,包括基本類型變量和數(shù)
組的元素、結(jié)構(gòu)體類型變量或結(jié)構(gòu)體的成員,不能
作用于數(shù)組名、常量或寄存器變量。
2.單目運(yùn)算符*是&的逆運(yùn)算,它的操作數(shù)是對(duì)象的
地址,*運(yùn)算的結(jié)果是對(duì)象本身。單目*稱為間接訪
問運(yùn)算符,是通過變量的地址存取(或引用)變量。
例如:doubler,a[20];
inti;則表達(dá)式&r、&a[0],&a[i]是正確的,
而&(2*r)、&a、&k是非法表示。
charc,*pc=&c;賦值語?:*(&c)='a';*pc='a,;c-a*;
registerintk;效果相同,都是將字符W存入變量c。
11
9.1.4指針變量的初始化
在使用指針變量前,要首先對(duì)指針變量進(jìn)行初始化,
讓指針變量指向一個(gè)具體的變量。進(jìn)行指針變量初
始化的方式有兩種:
方法一:使用賦值語句進(jìn)行指針初始化,如:
inta,*pa;
pa=&a;賦值后將變量a的地址賦給指針pa。
方法二:在定義指針變量的同時(shí)進(jìn)行初始化如:
inta,*pa=&a;將變量a的地址賦給指針。
注真:不要將其與一般的賦值語句混淆,也不要表示
成:inta,*pa;
*pa=&a;這是錯(cuò)誤的。
12
【例9.1】通過指針變量訪問整型變量。
程序代碼如下:
/*c09_0Lc*/
#include''stdio.h"
main()程序的運(yùn)行結(jié)果為:
{inta,b;10,20
int*pl/p2;10,20
a=10;b=20;
pl=&a;p2=&b;
printf(n%d,%d\n'「a,b);
printf(n%d,%d\nn/pl/p2);
J3
9.L5引用指針變量
引用變量的方式有兩種:用變量名直接引用,也可以通過指
向變量的指針間接引用。
【例9.2】分析程序的執(zhí)行過程比較變量引用方式。
直接引用方式:
#include<stdio.h>
main()
{inta,b;
scanf(n%d%dn,&a,&b);
/*在scanf函數(shù)中直接使用變量a和b的地址*/
printf(na=%d,b=%d\nn,a,b);
/*直接輸出變量a和b的值刃
}
14
間接引用方式:通過變量的地址輸出變量的值
#include<stdio.h>
main(){inta,b,*pa,*pb;
pa=&a,pb=&b;/*指針pa和pb分別指向變量a和b*/
scanf(n%d%dM,pa,pb);
printf(na=%d,b=%d\n!\*pa,*pb);
/*通過*運(yùn)算符實(shí)現(xiàn)間接訪問*/
}
運(yùn)行程序:程序的運(yùn)行結(jié)果為:
217J
a=21,b=7
15
【例9.3】輸入a和b兩個(gè)數(shù),按大小順序輸出a和b。
程序代碼如下:/*c0902-2.C/
#include"stdio.h"程序的運(yùn)行結(jié)果為:
main()Inputa=?,b=?:59J
{inta,b;a=5,b=9
int*pl,*p2,*p;max=9,min=5
printf(rrInputa=?,b=?\n");
scanf(〃%d%d〃,&a,&b);
pl=&a;p2=&b;
if(a<b){p=pl;pl=p2;p2=p;}
printf("\na=%d,b=%d\n”,a,b);
printf("max=%d,min=%d\n",*p2);
}
16
9.2指針與函數(shù)
■前面章節(jié)我們?cè)诤瘮?shù)之間傳遞過一般的變量
的值,同樣在函數(shù)之間可以傳遞指針。
■函數(shù)利用指針傳遞參數(shù)有三種方式:
□1.指針作為函數(shù)的參數(shù);
□2.指針作為函數(shù)的返回值;
□3.利用指向函數(shù)的指針傳遞。
17
9.2.1指針作函數(shù)的參數(shù)
利用指針傳遞函數(shù)的參數(shù)是一種間接傳值方式。
知道變量的地址就可以通過地址間接訪問變量的數(shù)值,
通過地址間接訪問變量的數(shù)值就是通過指針間接訪
問指針?biāo)傅膬?nèi)容。指針作函數(shù)的參數(shù)就是在函數(shù)
間傳遞變量的地址。
此時(shí),在調(diào)用函數(shù)時(shí)變量的地址作為實(shí)參,被調(diào)用函
數(shù)使用指針變量作為形參接收傳遞的地址。
18
【例9.4]使用函數(shù)phis求兩個(gè)數(shù)的和。
#include<stdio.h>
程序的運(yùn)行結(jié)果為:
main()EnterAandB:820J
{inta,b,c;A+B=28
printf(nEnterAandB:
n!
scanf(%d%d\&a9&b);
c=phis(&a,&b);/*調(diào)用phis函數(shù),實(shí)參為變量a和b的地
址*/
printf(°A+B=%d!\c);
)
intplus(int*px,int*py)/*形參為指向整型變量的指針刃
{return(*px+*py);/*返回兩個(gè)整數(shù)的和*1
■我們學(xué)習(xí)函數(shù)時(shí)知道,函數(shù)調(diào)用結(jié)束時(shí)返回一個(gè)結(jié)
果,是函數(shù)的返回值,這個(gè)返回值只有一個(gè)。
■如果試圖用一個(gè)函數(shù)交換主函數(shù)main中兩個(gè)變量值,
并將交換的結(jié)果返回主函數(shù),使用普通變量做函數(shù)
參數(shù)是無法實(shí)現(xiàn)。
■可以采用兩個(gè)指針變量傳遞地址的方式完成,即設(shè)
置兩個(gè)指針變量做函數(shù)的參數(shù)。
20
【例9.5】用函數(shù)交換main函數(shù)中兩個(gè)變量的值。
■voidswap(int*px,int*py)PXa
■{intt;
■t=*px;
px=*py;
■*py=t;
■printf(ninswap:*px=%d,*py=%d\n'\*px,*py);
■}________________
■voidmain()I程序的運(yùn)行結(jié)果為:
■{inta,b;Ibeforeswap:a=5,b=10
■a=5;b=10;Iinswap:*px=10,*py=5
■printf(nbeforeswap:a=%d|afterswap:a=10,b=5
■swap(&a,&b);
■printf(nafterswap:a=%d,b=%d\nn,a,b);
以下程序能否改變即b的值?
■voidswap(intx,inty)Xa
□{intt;
口t=x;x=y;y=t;}
■main()
■{inta,b;
■scanf(“%d,%d”,&a,&b);
■if(a<b)swap(a,b);
■printf("a=%d,b=%d\n”,a,b);
■運(yùn)行:輸入:5,8J
■輸出:a=5,b=8
22
練習(xí)題(1)
■voidfun(int*x)
□{printf(66%d”,++*x)
□*x=10;
□)
■main()
□{inta=25;
□fun(&a);
printf(“%d”,a);
口}
■運(yùn)行結(jié)果2610
23
練習(xí)(2)
■intast(intx^inty,int*qp,int*Qp)
■main
■ast(a,b\&c\&d);
■printf(^%d%d\n",.d);
■結(jié)果顯示71
24
9.2.2函數(shù)返回指針
指針能作為函數(shù)的返回值。過去我們將整型等簡(jiǎn)單類型作為
返回值,現(xiàn)在我們將函數(shù)的返回值設(shè)置為指針,
一般定義形式:
數(shù)據(jù)類型*函數(shù)名(參數(shù)列表)
〃數(shù)據(jù)類型〃后面的*表示:函數(shù)的返回值是一個(gè)指向該數(shù)據(jù)類
型的指針。注意,此時(shí)定義的是函數(shù),而不是指針。
25
■[例9.6]使用函數(shù)求兩個(gè)變量的最大值。
voidmain()
■{inta,b,*max;
■int*maxi(int*x,int*y);
■printf(uEnterab:n);運(yùn)行結(jié)果如下:
■scanf(n%d&b);Enterab:128J
■max=maxl(&a,&b);max=12
■printf(''max=%d\n'',*max);
■}
■int*maxi(int*x,int*y)
■{int*p;
■p=*x>*y?x:y;
■return(p);
}
26
9.2.3指向函數(shù)的指針
在定義一個(gè)函數(shù)之后,編譯系統(tǒng)為每個(gè)函數(shù)確定一個(gè)
入口地址,當(dāng)調(diào)用該函數(shù)的時(shí)候,系統(tǒng)會(huì)從這個(gè)
“入口地址”開始執(zhí)行該函數(shù)。
函數(shù)名代表函數(shù)的入口地址.
存放函數(shù)的入口地址的指針就是一個(gè)指向函數(shù)的指針,
簡(jiǎn)稱函數(shù)的指針。
函數(shù)的指針的定義格式:
類型標(biāo)識(shí)符(*指針變量名)()
27
類型標(biāo)識(shí)符為函數(shù)返回值的類型。特別值得注意的是,由于c
語言中,()的優(yōu)先級(jí)比*高,因此,〃*指針變量名〃外部
必須用括號(hào),否則指針變量名首先與后面的()結(jié)合,就是
前面介紹的〃返回指針的函數(shù)〃。試比較下面兩個(gè)定義語句:
int(*pf)();/*定義一個(gè)指向函數(shù)的指針,該函數(shù)的返
回值為整型數(shù)據(jù)*/
int*f();/*定義一個(gè)返回值為指針的函數(shù),該指針
指向一個(gè)整型數(shù)據(jù)*/
和變量的指針一樣,函數(shù)的指針也必須賦初值,才能指向具
體的函數(shù)。由于函數(shù)名代表了該函數(shù)的入口地址,因此,
一個(gè)簡(jiǎn)單的方法是:直接用函數(shù)名為函數(shù)指針賦值,即:
函數(shù)指針名二函數(shù)玄
函數(shù)型指針經(jīng)定義和初始化之后,在程序中可以引用該指針,
目的是調(diào)用被指針?biāo)傅暮瘮?shù)。由此可見,使用函數(shù)型指
針,增加了函數(shù)調(diào)用的方式。
28
用指向函數(shù)的指針變量調(diào)用函數(shù)
■函數(shù)的指針:指函數(shù)的入口地址。
■函數(shù)名:代表函數(shù)的入口地址。
■指向函數(shù)的指針變量的定義:類型名(*變量名)()
■例:int(*p)();定義p為指向整型函數(shù)的指針變量。
■例:求a、b中的較大者。
■intmax(intx,inty)/*定義函數(shù)*/
■{intz;
■z=(x>y)?x:y;
■returnz;}
29
方法1:直接調(diào)用函數(shù):方法2:用指針變量調(diào)用函
數(shù):
main()
main()
{intabc;
{inta,b,c;99
int(*p)();
scanf("%d,%d”,&a,&b);
p=max;/*p指向函數(shù)*/
c=max(a9b);/*調(diào)用函數(shù)*/
scanf(n%d%d!\&a&b);
printf(“max=%d\n",c);95
c=(*p)(a,b);/*調(diào)用函數(shù)*/
printf(umax=%d\n!\c);
30
【例9.7]用指針調(diào)用函數(shù),輸出三個(gè)數(shù)中最大值。
funmax(intx,inty)
{return(x>y)?x:y;運(yùn)行結(jié)果如下:
)2,34,8J
main()a=2,b=34,c=8,
max=34
{intrpf)O;
inta,b,c,d,e;
pf=funmax;/*指針變量指向funmax函數(shù)*/
scanfC6%d,%d%d%&a,&b,&d);
c=(*pf)(a,b);9/*等彳介于?=£11111114乂(4力)*/
e=(*pf)(c,d);/*等價(jià)于e=funmaxCd)*/
nn
prmtf(a=%d,b=%d5d=%d9max=%d,a9b,d,e);
31
當(dāng)一個(gè)指針指向一個(gè)函數(shù)時(shí),通過指針,就可以訪問
它指向的函數(shù)。
需要注意的是,一個(gè)函數(shù)指針可以先后指向不同的函
數(shù),將哪個(gè)函數(shù)的地址賦給它,它就指向哪個(gè)函數(shù),
使用該指針,就可以調(diào)用函數(shù).
另外,如果有函數(shù)指針(*pf)(),則pf+n、pf++、
pf一等運(yùn)算是無意義的。
32
9.3指針與數(shù)組
我們可以定義指針來訪問數(shù)組元素。一個(gè)變量在內(nèi)
存中有相應(yīng)的地址,而數(shù)組包含多個(gè)元素,每個(gè)
數(shù)組元素在內(nèi)存中都占有一個(gè)內(nèi)存地址,因此我
們也可以定義一個(gè)指針指向這個(gè)地址。
元素的指針:是指數(shù)組每個(gè)元素的地址
數(shù)組的指針:是指數(shù)組的首地址。
數(shù)組名:代表數(shù)組首地址。
可以利用指針引用數(shù)組元素。
33
9.3.1通過指針引用一維數(shù)組元素
■在數(shù)組中我們已經(jīng)知道,可以通過數(shù)組的下標(biāo)唯一確定某
個(gè)數(shù)組元素在數(shù)組中的順序和存儲(chǔ)地址。
■例如:inta[5]={1,2,3,4,5},x,y,*p;
■通過下標(biāo)可直接訪問數(shù)組a中的元素:
■x=a[2];y=a[4];
■由于每個(gè)數(shù)組元素相當(dāng)于一個(gè)變量,因此指針變量可以指
向數(shù)組中的元素,也就是可以用“指針方式”訪問數(shù)組中
的元素。
■指向數(shù)組元素的指針,與指向變量的指針相同。
■例:inta[10];int*p;
■p=&a[0];/*等價(jià)于p=a;數(shù)組的首地址賦給p*/
■或初始化指針變量:int*p=&a[0];等價(jià)于:int*p=a;
34
地址o
■若int*p=a;(BPp=&a[OJ).a
P,a—
■則等價(jià)于
*p=l;a[O]=l;p+1,a+1
(等于指向下一個(gè)元素
■p+1a[l]p+2,a+2
■p+i(等于&a[i])指向元素a[i]
rO
p+i,a+履LA^
nG
p+9,a+9_>aV
=
35
■因?yàn)?a+l,p+l是a[l]的地址
■則*(p+l)或*(a+l)等價(jià)于a[l]
■因?yàn)椋篴+i,p+i是a[i]的地址,
■貝lj*(p+i)或*(a+i)等價(jià)于a[i]
■例:*(a+9)=10;或*(p+9尸10;
等價(jià)于:a[9]=10;
■*(p+i)也可以表示為p[i]0
■總之,數(shù)組元素引用方法如下:
■(1)下標(biāo)法:a[i]
■(2)指針法:*(a+i)、*(p+i)或p[i]
36
【例9.8】數(shù)組元素的三種引用方法。
(1)下標(biāo)法。
程序代碼如下:
/*c09_08_l.c*/
#includenstdio.h"
main()
{intaflOJ;
inti;
for(i=0;i<10;i++)
nn
scanf(%d9&a[i]);
printf(n\n");
for(i=0;i<10;i++);
printf(n%d「a[i]);
printf(n\nn);
}
37
(2)通過數(shù)組名計(jì)算數(shù)組元素地址,求元素的值。
程序代碼如下:/*c09_08_2.c*/
#include"stdio.h"
main()
{inta[10J;
inti;
for(i=0;i<10;i++)
scanfC%dH,或scanf("%d[a+i);
printf(n\nn);
for(i=0;i<10;i++)printf(n%dn,*(a+i));
printf(n\nn);
(3)通過指針變量得到元素的值。
程序代碼如下:/*c09_08_3,c*/
#include<stdio.h>
main()
{inta[10J;三個(gè)程序運(yùn)行結(jié)果相同如下:
intij;1234567890
int*p=a;1234567890
for(i=0;i<10;i++)
scanf(〃%d〃,&a[i]);
printf("\n");
for(i=0;i<10;i++)
{printf(〃%(T,*p);p++;}
printf("\n");
39
地址
【例9.9】分析程序。a[]
p=a―>
main()1a[0]
押二
{inta[]={1,2,3,4,5,6};2a[l]
int*p;3a[2]
p=a;/*指針p為數(shù)組的首地址刃a+34
5
printf(n%dfl,*p);p+二3
6a[5]
printf(n%d\n”,*(++p));
printf(n%dn,*++p);
printf(n%d\nn,*(p--));
p+=3;
printf(n%d%d\nf\*p,*(a+3));運(yùn)行結(jié)果:
12
33
5440
注意,
例中*(++p)等價(jià)于*++p,表示:先使p=p+l,再取
*p的值。
而尸是先取指針P值作“”運(yùn)算,再使指針P自
減1。
*p++表示:先取*P的值,再使p=p+l
41
練習(xí)
■main()
■{inta[10]={l,2,3,4,5,6,7,8,9,0};
■int*p=a;
■printf("%d,%d\iTJ(p+2),p[5]);
■printf(^%dJ:*a);
■printfC%d\n”,*(a+8));
■}3,6
■輸出結(jié)果1,9
?可見對(duì)一維數(shù)組而言,a指向a[0]、a+i指向a[i]
42
9.3.2指針基本運(yùn)算
對(duì)于指針的運(yùn)算有:指針的加減運(yùn)算和兩個(gè)指針的關(guān)
系運(yùn)算。
1.指針的加、減運(yùn)算
當(dāng)指針P指向數(shù)組中的元素時(shí),n為一個(gè)正整數(shù),表達(dá)
式:p±n表示:指針p所指向當(dāng)前元素之后或之
前的第n個(gè)元素。
最常見的指針加減運(yùn)算p++、P--的含義是:
指針加1,指向數(shù)組中的后一個(gè)元素;
指針減1,指向數(shù)組中的前一個(gè)元素。指針與整數(shù)進(jìn)
行加減運(yùn)算后,它們的相對(duì)關(guān)系如圖9.7所示。
43
數(shù)組指針
P-R
p-2
p-1
p指針當(dāng)前位置
p+1
p+2
p+n
圖9.7指針的加減運(yùn)算
44
■注意:p++操作,改變了指針變量的值。使用時(shí)要注意指針
變量所指的當(dāng)前位置。
■而a++是不允許的。因?yàn)閍是數(shù)組名,固定代表數(shù)組首地址。
■例:注意下題中出現(xiàn)的問題
□main()
□{inta[10],i,*p;
□p=a;
□for(i=0;i<10;i++)
□scanf(^%d工p++);
□printf(“\n”);
□for(i=0;i<10;i++,p++)
□printf(“%d”,*p);
□)
45
■上例中,由于第一個(gè)循環(huán)中p++使P指向下一個(gè)元素,
循環(huán)結(jié)束時(shí),p指向*(a+10),所以第二個(gè)循環(huán),用
P輸出的是a數(shù)組以外的內(nèi)存中的數(shù)據(jù)。
■因此在第二個(gè)循環(huán)之前,應(yīng)重新設(shè)置P指針的初值:
■for(p=a4=0;i<10;i++,p++)
printf(6<;p<a+10;
■也可以改為:
□for(p=aJ=0;i<10;i++)
□printf(u%d”,*p++);
46
■由于指針P所指的具體對(duì)象不同,所以對(duì)指針與整
數(shù)進(jìn)行加減運(yùn)算時(shí),C語言會(huì)根據(jù)所指的不同數(shù)據(jù)
類型計(jì)算出不同的存儲(chǔ)單元的大小,以保證正確操
作實(shí)際的運(yùn)算對(duì)象。
■數(shù)據(jù)類型的存儲(chǔ)單元的大小等于一個(gè)該數(shù)據(jù)類型的
變量所占用的內(nèi)存單元字節(jié)數(shù)。
■對(duì)于char型,存儲(chǔ)單元的大小為1字節(jié);
■對(duì)于int型,存儲(chǔ)單元的大小為2字節(jié);
■對(duì)于long型,存儲(chǔ)單元的大小為4字節(jié);
■對(duì)于double型,存儲(chǔ)單元的大小為8字節(jié)。
■p+1運(yùn)算,其中的1意味著是該類型變量的一個(gè)存
儲(chǔ)單元。
47
【例9.10】編程將串strl復(fù)制到串str2中。
main()
{charstr1[80],str2[80],*pl,*p2
printf("Enterstring1:");
gets(strl);
pl=strl;
p2=str2;
while((*p2=*pl)!='\0')/*pl所指的元素內(nèi)容送到
p2所指的元素中*/
{pl++;p2++;}/*指針pl和p2分別后移1個(gè)元素*/
printf("String2:〃j
運(yùn)行結(jié)果如下:
puts(str2);I
Enterstring1:china
String2:china
48
程序中的關(guān)鍵是while語句,“(*p2=*pl)!二‘\0’”
的含義是:
先將指針P1所指元素的內(nèi)容送到指針P2所指元素的元
素中,然后再判斷所賦值的字符是否是串結(jié)束標(biāo)記
'\0',如果不是串結(jié)束標(biāo)記,則執(zhí)行循環(huán)繼續(xù)進(jìn)行字
符復(fù)制;如果是串結(jié)束標(biāo)記,則退出循環(huán),完成串復(fù)
制。
對(duì)于上面程序中的while循環(huán),可以進(jìn)行如下改進(jìn):
方法一:
while(*p2=*pl)
{pl++;p2++;}
方法二:
while(*p2++=*pl++);
/*循環(huán)體為空語句*/
49
【例9.n】編寫程序求字符串的長(zhǎng)度。
分析:字符串的存儲(chǔ)結(jié)束標(biāo)志為、0、可以設(shè)置一個(gè)指針
變量P指向字符串首字符,判斷p當(dāng)前所指的字符如果
為非,網(wǎng),則p++,指向下一個(gè)字符,再判斷,直到p指
向字符串尾,程序結(jié)束。字符串的長(zhǎng)度應(yīng)為p的當(dāng)前位
置與字符串首地址的差。
main()
運(yùn)行結(jié)果如下:
{charstr[50],wp=str;
Enterstring:china」
nn;
printf(Enterstring:)Stringlength=5
gets(str);
while(*p)
p++;
printf(nStringlength=%d\nn,p-str);
}
50
2.兩個(gè)指針的關(guān)系運(yùn)算
只有當(dāng)兩個(gè)指針指向同類型的數(shù)據(jù)元素時(shí),才能進(jìn)行關(guān)系運(yùn)
算。即:
■P<q當(dāng)P所指的元素在q所指的元素之前時(shí),表達(dá)式的值為
1;反之為0。
■p>q當(dāng)P所指的元素在q所指的元素之后時(shí),表達(dá)式的值為
1;反之為0。
■p==q當(dāng)P和q指向同一元素時(shí),表達(dá)式的值為1;反之為0。
■p!二q當(dāng)P和q不指向同一元素時(shí),表達(dá)式的值為1;反之為
0o
51
■任何指針p與NULL進(jìn)行“p二二NULL”或“p!二NULL”
運(yùn)算均有意義,
■“p二二NULL”的含義是當(dāng)指針p為空時(shí)關(guān)系表達(dá)式
為真
■〃p!二NULL〃的含義是當(dāng)p不為空時(shí)表達(dá)式為真。
■指向兩個(gè)不同數(shù)組的指針進(jìn)行比較,沒有任何實(shí)際
的意義。
52
【例9.12】編寫程序?qū)⒁粋€(gè)字符串逆置。
#include<stdio.h>
main()運(yùn)行結(jié)果如下:
{charstr[50],*p,*s,c;Enterstring:china
printf(nEnterstring:");anihc
gets(str);
p=s=str;/*指針p和s指向str數(shù)組*/
while(*p)
p++;/*找到串結(jié)束標(biāo)記)(T號(hào)
p--;/*指針回退一個(gè)字符,使p指向最后一個(gè)字符刃
while(s<p)/*當(dāng)串前面的指針串后面的指針p時(shí),進(jìn)行循環(huán)*/
{C=*s;/*交換兩個(gè)指針?biāo)赶虻淖址?/
*s++=*p;/*串前面的指針S向后(+1)移動(dòng)刃
*p-=C;/*串后面的指針P向前(-1)移動(dòng)*/
}
puts(str);
53
9.3.3通過指針引用二維數(shù)組元素
■二維數(shù)組a[3][4],有以下元素:
a[O]¥a[O][O]a[O][l]a[0][2]a[0][3]
a[l]-a[l][O]曬HLa[l][2]a[l][3]
a[2]E][0]a[2][l]a[2][2]a[2][3]
■二維數(shù)組a[3][4]可以理解為:
■a數(shù)組中,包含3個(gè)元素:a[O]a[l]a[2],每
個(gè)元素都是一個(gè)一維數(shù)組的名字,代表該
行元素的首地址。
54
■1.多維數(shù)組的地址
■若定義以下數(shù)組:
■inta[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}};
■可理解為:a數(shù)組包含3個(gè)元素:a[0]>a[l]>a[2]
■這三個(gè)元素本身各代表一個(gè)一維數(shù)組。
■a:代表數(shù)組首地址,指向a[0],即第0行首地址
■a+1:指向即第1行首地址
■賽a為行指針」可見:行指針+1,將指向下一行元素。
a-={1357}
a+Ja[l]={9111315}
a+2一[聞={17192123}
55
列地址:a[0]a[O]+la[0]+2a[0]+3
a—4a[o]={i357)
a+1-a[l]={9111315}
a+2一={17192123)
a[O]:是第0行元素的首地址——&a[O][O]
a[O]+l:是&a[O][lba[0]+2是&a[0][2]
可見,列指針+1.指向下一個(gè)元素.
a[l]:是第1行元素的首地址——&a[l][O]
a[2]:是第2行元素的首地址——&a[2][0]
*a[O]:是a[O][O]元贅
*(a[O]+l):是時(shí)0]口]三素
*(a[2]+l):是元素
所以元素用列指針表示為*(a[i]+j)
<AU56
元素用列指針表示為*(a[i]+j)
用行指針a表示元素:
■*a即*(a+0):表示a[0](即列指針)
■*(a+l):表示a[l]
■*(a+i):表示a[i]
■因而*(a[i]+j)可表示為*(*(a+i)+j)
■因?yàn)橛昧兄羔樢迷氐男问?*(a[i]+j)
■所以表示元素。
■總之:
■行指針a,加1,指向下1行;
■列指針a[0],加1,指向下1個(gè)元素。
■要找到某行中的某個(gè)元素,要用列指針a[i]運(yùn)算
■要找到某行的首地址,要用行指針a運(yùn)算
■*a=a[O](列指針)
57
2.指向二維數(shù)組的指針變量p=a[OL1
p++―A2
■(1)存放列地址的指針變量3
■這種指針變量,可以尋找到每個(gè)元素。4
■定義形式和指向普通變量的指針變量一樣。一
■【例9.13】多維數(shù)組的輸出。工
■main()
■{inta[3][4]={{l,2,3,4},{5,6,7,8},{9J8Jl」2}};1f
■int*P;a[O]+ll—JI
■for(p=a[0];p<a[0]+12;p++)/*p得到列地Ha[0]*/
if((p-a[0])%4==0)printff6\nw);
printf("%4d”/p);}程序的運(yùn)行結(jié)果為:
1234
5678
9101112
58
■(2)指向m個(gè)元素組成的一維數(shù)組的指針變量
■定義格式:int(*p)[m|;
■則p+1移過m個(gè)元素。
■可見:這里p應(yīng)接受行地址。
59
【例9.14】給定某年某月某日,將其轉(zhuǎn)換成這一年的第
幾天并輸出。
#include<stdio.h>
main()
{intday_tab[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}};
inty,m,d;
scanf(H%d%d%df\&y,&m,&d);
printf(n%d\nn,day_o^year(day_tab,y,m,d));/*實(shí)參
為二維數(shù)組名*/一
60
■day_o^year(int(*day_tab)[13],intyear,intmonth,intday)
■/*形參為指向13個(gè)元素的一維數(shù)組的指針變量*/
■{inti5j;
■i=(year%4==0&&year%100!=0)||year%400==0;/*為閏
年i=l,否則i=0*/
■for(j=l;j<month;j++)
■day+=*(*(day_tab+i)+j);
■return(day);
■}
■運(yùn)行結(jié)果如下:
■200023/*輸入數(shù)據(jù)年月日*/
■34
61
9.4字符串與指針
■9.4.1字符數(shù)組與字符指針
■字符串的訪問方法:用字符串的首地址。
■字符數(shù)組名,代表字符串的首地址。
■L字符數(shù)組存放字符串
■例如,有語句:charstring[]=66IamChinese.”;
■此時(shí),string是字符數(shù)組,存放了一個(gè)字符串。
■例main()
■{charstring[]="IamChinese.59;
■printff6%s55,string);
運(yùn)行時(shí),輸出:
IamChinese.
62
2用字符指針變量指向一個(gè)字符串。
■字符指針也可以指向一個(gè)字符串。我們可以用字符串常量
對(duì)字符指針進(jìn)行初始化。例如,有語回
■char*str="China.";對(duì)字符指針進(jìn)行初始化。
■此時(shí),字符指針變量存放的是字符串的首地址,即指向字
符串的首地址。
■例main()
str-
■{char*str="China.”;h
■printf(66%s5\str);str+2—>*
■printf("%s\ntr+2);n.
SL
■}
■運(yùn)行結(jié)果顯示:\o
■China,ina.
■這里char*str="China.";等價(jià)于以下兩行:
char*str;
str=6'China.”;
63
在程序中,可以使用如下語句:
str++;/*指針str加1*/
str="ThisisaNEWstring.";/*使指針指
向新的字符串*/
str=strl;/*改變指針str的指向*/
strcpy(string,“ThisisaNEWstring.")/*
改變字符數(shù)組的的內(nèi)容*/
strcat(string,str)/*進(jìn)行串連接操作*/
strcpy(str,string)/*指針變量沒有初始化時(shí),
不要向str進(jìn)行串復(fù)制,可能會(huì)破壞其它數(shù)據(jù)*/
64
9.4.2常見的字符串操作
■由于使用指針編寫的字符串處理程序比使用數(shù)組方式處理
字符串的程序更簡(jiǎn)潔、更方便,所以在c語言中中,大量使
用指針對(duì)字符串進(jìn)行各種處理。
■在處理字符串的函數(shù)中,一般都使用字符指針作為形參。
■由于數(shù)組名代表著數(shù)組的首地址,因此在函數(shù)之間可以采
用指針傳遞整個(gè)數(shù)組,這樣在被調(diào)用函數(shù)的內(nèi)部,就可以
用指針方式訪問數(shù)組中的元素。
■下面我們來看幾個(gè)使用指針處理字符串的程序。
65
【例9.15]用字符指針指向一個(gè)字符串。
程序代碼如下:
/*c09_15.c*/
#includenstdio.hn
main(){
char*str=nhelloworldn;
printf(n%s\nn,str);
}
運(yùn)行結(jié)果如下:
helloworld
66
程序分析與注意事項(xiàng):
這里的str是指向字符串“helloworld”的指針,即
字符串的首地址賦給了字符指針,使一個(gè)字符指
針指向了一個(gè)字符串。
C語言對(duì)字符串常量是按字符數(shù)組處理的,在內(nèi)存
開辟了一個(gè)字符數(shù)組用來存放字符串常量。
定義str的部分:char*str="helloworld7;
str被定義為一個(gè)指向字符型數(shù)據(jù)的指針變量,在
指向字符串時(shí),并不是把字符串的所有的字符存
放到str中,也不是把字符串賦給*str,只是把
字符串的首地址賦給字符指針。
67
下面的情況是不允許的:
char*str;
scanf("%s",str);
因?yàn)橹羔槢]有明確的指向,其值是任意的,也許所
指向的區(qū)域不是用戶可以訪問的內(nèi)存區(qū)域,或者
是根本不存在的地方。
輸出一個(gè)字符串時(shí),系統(tǒng)先輸出字符指針?biāo)赶虻?/p>
一個(gè)字符數(shù)據(jù),然后自動(dòng)使str加1,指向下一個(gè)
字符,直到遇到字符串結(jié)束標(biāo)志’\0’為止。
68
雖然字符數(shù)組和字符指針都可以用來表達(dá)字符串,但是它們
還是有不同之處,例如:
charstring口二“helloworld”;
char*str="helloworld”;
■string和str的值都是字符串"helloworld”的首地址,但是
string是一個(gè)字符數(shù)組,名字本身是一個(gè)地址常量;而str
是指向字符串首地址的指針變量。
■因而str可以被賦值,而string不能。例如str+=2可以,但
string+=2則不可以.
■若定義了一個(gè)指針變量,并使它指向一個(gè)字符串,就可以
用下標(biāo)形式引用指針變量所指向的字符串中的字符。
■如str[l]表示*(str+l),即串中第2個(gè)字符Q。
69
【例9.16】用指針作為函數(shù)的形式參數(shù),編寫字符串復(fù)制函
■#include<stdio.h>運(yùn)行結(jié)果如下:
■main()Enterstring:china
■{chara[30],b[30];a=china
b=china
■printf(nEnterstring:'');
■scanf(n%s!\a);
■strcopy(a,b);/*調(diào)用函數(shù)的實(shí)參為數(shù)組名,即數(shù)組的首址*/
■printf(na=%s\nb=%s\nu,a,b);
■)
■voidstrcopy(char*strl,char*str2)/*函數(shù)的形參為指
針變量*/
■{while(*str2++=*strl++);/*通過指針操作實(shí)參數(shù)組*/
}
70
【例9.17]編寫函數(shù),求字符串的長(zhǎng)度。
intstrlen(char*str)
{char*p=str;
while(*p)
p++;/*指針后移,直到串尾*/
return(p-str);_______
運(yùn)行結(jié)果如下:
main()Enterstring:English
{chara[50];Stringlength=7
printf(MEnterstring:11);
scanf(n%sn,a);
printf(nStringlength=%d\nn,strlen(a));
71
【例9.18]編寫函數(shù),實(shí)現(xiàn)兩個(gè)串的連接。
#include<stdio.h>
char*strcat(char*strl,char*str2)
{char*p=strl;
while(*p)p++;/*找至U串strl的尾刃
while(*p++=*str2++);
return(strl);}運(yùn)行結(jié)果如下:
main()Enterstringl:penJ
{chara[50],b[30];Enterstring2:childJ
printf(nEnterstringl:n);a+b=penchild
scanf(n%sn,a);
printf(nEnterstring2:'');
scanf(n%s!\b);
printf(na+b=%s\nn,strcat(a,b));}
72
【例9.19]用下標(biāo)的形式引用字符串中的元素。
程序代碼如下:/*c09_19.c*/
nn
#includestdio.h運(yùn)行結(jié)果如下:
main()Thefifthcharcteriso
{char*a="helloworld'';helloworld
inti;
printf(nThefifthcharcteris%c\n!\a[4]);
for(i=0;a[i]!=l\0,;i++)
printf(n%cl\a[i]);
printf(n\nn);
73
【例9.20]輸入兩個(gè)有序的字符串(小f大),編寫一
個(gè)合并兩個(gè)字符串的函數(shù),使合并后的字符串,
仍然是有序排列。程序代碼如下:
#include<stdio.h>stri[80]H2ac\o
■main()P
■{charstr1[80],str2[80],str[80];str2[80]]?bgh\0一
■char*p,*q,*r,*s;彳一
■inti,j,n;str[80]]
■printf(nEnterstringl:n);gets(strl);1
■printf(uEnterstring?:'');gets(str2);
■for(p=strl,q=str2,r=str;*p!=f\0f&&*q!=\(F;)
■if(*pv*q)*r++=*p++;/*若strl中的字符較小,則將它復(fù)
制至l]str中*/
■else*r++=*q++;/*若str2中的字符較小,則將它復(fù)制
至!Jstr中*/
74
■s=(*p)?p:q;/*判斷哪個(gè)字符串還沒有處理完畢*/
■while(*s)/*繼續(xù)處理(復(fù)制)未處理完畢的字符串*/
■*r++=*s++;
■*r=,\0,;/*向str中存入串結(jié)束標(biāo)記*/
■printf(^Result:11);
■puts(str);}運(yùn)行結(jié)果如下:
Enterstringl:112ac
Enterstring2:Obgh
Result:0112abcgh
75
9.5指針數(shù)組、數(shù)組指針及應(yīng)用
951指針數(shù)組與指向數(shù)組的指針變量
■1指針數(shù)組:
■數(shù)組中的每個(gè)元素,都是指針變量。
■一維指針數(shù)組的定義形式:inttpa[5]inta[5]
■類型名*數(shù)組名[常量表達(dá)式]pa[0]&a[(ga[0]
例如:int*pa[5];pa[l]&a[lja[l]
表示定義一個(gè)由5個(gè)指針變量構(gòu)成的pa[2]&a[2;a[2]
指針數(shù)組pa,數(shù)組中的每個(gè)數(shù)組元素pa[3]&a[31a[3]
都是指針,都可指向一個(gè)整數(shù).pa[4]&a[45a[4]
設(shè)有:inta[5],*pa[5];
for(i=0;i<5;i++)
pa[i]=&a[i];
76
2指向m個(gè)元素組成的一維數(shù)組的指針變量
定義的形式為:
類型(*數(shù)組名)[m];
例如:int(*pb)[5];
表示定義一個(gè)指向數(shù)組的指針變量pb,pb指向
的數(shù)組是5個(gè)元素組成的一維整型數(shù)組.
■則pb+1將移過5個(gè)元素。
■可見:這里pb可以接受二維數(shù)組的行地址。
例如:char*line[5];
表示line是一個(gè)數(shù)組,每個(gè)元素是一個(gè)指向字符型數(shù)據(jù)的一
個(gè)指針。若設(shè)指向的字符型數(shù)據(jù)(字符串)分別是“ONE”、
“TWO”、…、"FIVE”,則數(shù)組line的結(jié)構(gòu)如圖9.H所示.
指針數(shù)組常適用于指向若干字符串,這樣使字符串處理更加
靈活方便。
line[0]
line⑵
line[3]
line[4]
圖9.n指向字符串常量的指針
數(shù)組
78
【例9.21]輸入一個(gè)字符串,判斷該字符串是否是英文的星
期幾。使用指針數(shù)組實(shí)現(xiàn)。
程序代碼如下:/*c09_21.c*/
#include<stdio.h>
char*week_day[8]={''sun'',''mon'',ntuen,''wed'',
"thu'',Z'fri","sat”,NULL};
/*定義指針數(shù)組。數(shù)組中的每個(gè)元素指向一個(gè)字符串*/
main()
{intm;
charstring[20];
printf(uEnterastring:'');
scanf(n%sn,string);
m=lookup(string);
printf(nl=%d\nu,m);}
lookup(charch[])/*傳遞字符串(字符數(shù)組)*/
{inti,j;
char*pc;
for(i=0;week_day[i]!=NULL;i++)/*完成查找工作刃
{for(pc=week_day[i],j=0;*pc==ch[j];j++,pc++)
if(*pc==6\0f)return(i);/*若找到則返回對(duì)應(yīng)的序號(hào)*/
)
return(-l);/*若沒有找到,則返回-1*/
運(yùn)行結(jié)果如下:
Enterastring:wedJ
1=3
80
■程序中沒有使用二維的字符數(shù)組,而是采用指針數(shù)
組week_day??梢钥吹街羔様?shù)組比二維字符數(shù)組有
明顯的伍點(diǎn),一是指針數(shù)組中每個(gè)元素所指的字符
串不必限制在相同的字符長(zhǎng)度,二是訪問指針數(shù)組
中的一個(gè)元素是用指針間接進(jìn)行的,效率比下標(biāo)方
式要高。
81
【例9.22】輸入星期幾,輸出對(duì)應(yīng)星期的英文名稱。用指
針數(shù)組實(shí)現(xiàn)。
程序代碼如下:/*c09_22.c*/
#include<stdio.h>
char*week_day[8]={''sunday'',''monday'',ntuesdayn,
nWednesday0,nt
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 石油天然氣合作開發(fā)合同
- 中小企業(yè)人員書面勞動(dòng)合同
- 綠色低碳產(chǎn)業(yè)項(xiàng)目合作合同
- 砂礫石供貨合同
- 危險(xiǎn)廢物運(yùn)輸合同協(xié)議
- 煤炭銷售合同
- 環(huán)保項(xiàng)目資金籌措及使用協(xié)議
- 新能源汽車充電基礎(chǔ)設(shè)施建設(shè)合作合同
- 2023-2024學(xué)年高中信息技術(shù)選修2(浙教版2019)-網(wǎng)絡(luò)基礎(chǔ)-教學(xué)設(shè)計(jì)-2.2-網(wǎng)絡(luò)體系結(jié)構(gòu)與TCPIP協(xié)議
- 劇組場(chǎng)地使用損壞賠償協(xié)議
- 保安員考核評(píng)分標(biāo)準(zhǔn)與細(xì)則
- 四年級(jí)豎式計(jì)算大全100道
- 履行法定義務(wù)糾正違法行為的模板
- 崗位績(jī)效獎(jiǎng)勵(lì)制度
- JGT161-2016 無粘結(jié)預(yù)應(yīng)力鋼絞線
- Visual Studio 2019(C#)Windows數(shù)據(jù)庫項(xiàng)目開發(fā)高職全套教學(xué)課件
- 學(xué)前兒童保育學(xué)(學(xué)前教育專業(yè))全套教學(xué)課件
- 畜牧養(yǎng)殖設(shè)備(共73張PPT)
- 消防安全每月防火檢查記錄
- 論文寫作與學(xué)術(shù)規(guī)范 課程教學(xué)大綱
- DB32/T 4443-2023 罐區(qū)內(nèi)在役危險(xiǎn)化學(xué)品(常低壓)儲(chǔ)罐管理規(guī)范
評(píng)論
0/150
提交評(píng)論