




已阅读5页,还剩76页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第9章 指 针,特 点,能直接对内存地址操作, 使用灵活,实现动态存储管理,可以使程序简洁、紧凑、高效,用间接访问的方式改变数据的逻辑顺序,调用函数时可实现变量的引用传递,地址和指针的概念,变量的地址和变量的值,int i=3; float j=6; double k=9;,3,6.0,9.0,变量i,变量j,变量k,2200,2206,2202,2214,程序中定义的变量, 系统根据它的 类型给它分配一定长度的内存单元, 该内存单元的起始地址即为变量的地址。,该内存单元的内容就是变量的值。,直接访问和间接访问,直接访问:,用变量名直接从它对应的地址存取内容。,如: int x=5,y=8,z=0; z =x+y;,13,直接从 x 和 y 对应的地址2200和2202 取出内容5和8然后相加将结果13存入 变量 z 对应的地址2204的单元中。,间接访问,定义一个存放地址的变量p (p的地址1500), 将x的地址 2200存放在变量 p 中。通过 变量p取出地址2200, 再按此 地址存取其中的内容, 就间接 的完成了对x的存取。,当p的内容改为2202时, 通过 变量p取出地址2202, 再按此 地址, 存取的就是变量y的内 容。,p就是指针变量,5,8,0,变量x,变量y,变量z,2200,2202,2204,2202,指针变量的定义,一般形式:,基类型名 *指针变量名,说明:,基类型名: 指针变量所指向的变量的类型名称,指针变量名: 所定义的指针变量的名称,*: 表示它后面的变量名是指针类型,功能:,(1)定义该指针变量名为指向基类型的指针变量,为 该变量分配存储单元, 其长度等于存储地址的字节数。,(2) 基类型确定用指针变量“间接”存取数据的存储单 元个数和存储形式。该变量只能指向基类型数据。,指针变量的初始化,用 =&变量名 来给指针变量赋初值。选项中的变量名必须 是已定义过的,其类型必须与基类型一致。表示将它对应的地 址值赋给所定义的指针变量。,例如: int x,p=,int x,*p=,int x; float *p=,可以用赋值语句给指针变量赋值:,float y, *py; py=,指针变量的引用,引用指针变量的指针值与引用其它 类型的变量一样直接用它的变量名,引用指针变量所指向的变量时, 用“*指针变量名”,注意: 指针变量的值与它所指向变量的值之间的差别,指针变量只有正确赋值后才能通过它访问指向的变量。,int x;,p=,int *p;,*p,*p=5;,5,指针变量的运算,1. &: 取地址运算符, 取右边变量的地址,2. * : 指向运算符(间接访问运算符), 访问指针变量右边所指向的变量。,&a是变量a的地址,*p 是指针变量p指向的变量。,说明: “&”和“*”都是单目运算符, 它们的优先级 相同, 按自右而左方向结合。,如果已定义 float a, *p=,则 *p,是变量 a,&*p,是变量a的地址 p,&*p,等价于 p,而 &a,是变量a的地址 p,*&a,是p所指向的变量 a,*&a,等价于a,注意,(1). 指针变量定义和引用指向变量的“*”含义有差别。,(2).不能引用没有赋值的指针变量,不要误认为p定义后 变量*p就已存在,必须给p正确赋值后,变量*p才存在。,(3).p= 是给p指向的变量 赋值。两者含义完全不同。,(4).给指针变量赋值必须用同类型的指针。,(5).指针变量只存放地址, 地址值是无符号整数, 但不能直 接用整型量(或其它非地址量)赋值给指针变量。,int *p1=2200;,给变量赋值的两种方法,1. 直接访问用变量名,如: int i; i=5;,2. 间接访问通过指向变量i的地址的指针变量 p 赋值,如:int i, *p; p=,取地址运算符&和指向运算符*的应用,main( ) int m, n; int *p= ,运行结果: Input m,n: 123 456 m=123 &m=FFD6 *p=123 p=FFD6 n=456 &n=FFD8 *q=456 q= FFD8,printf(“min=%d, max=%dn“,*p1,*p2); ,main( ),运行结果: min=6, max=8,例:通过交换指针变量值按大小顺序输出,指针变量作为函数的参数,以指针类型为函数的参数,作用是将变量的地址传入函数。,int x,y; int *pt1;*pt2;,x=8;y=6;,pt1=,if (xy) swap(pt1,pt2);,printf(“x=%d, y=%dn“,x,y);,swap(int *p1,int *p2),p=*p1;,*p1=*p2;,*p2=p;, int p;,8, main() ,6,8,运行结果: x=6, y=8,int x,y; int *pt1;*pt2;,x=8;y=6;,pt1=,if (xy) swap(pt1,pt2);,swap(int *p1,int *p2),p=*p1;,*p1=*p2;,*p2=p;, int p;,printf(“x=%d, y=%dn“,x,y);,指针与数组,C语言中规定数组名是指针类型的符号常量, 该符号常量值等于数组首元素的地址 ( 简称数 组首地址) ,它的类型是指向数组元素的指针类型。 即数组名是指向该数组首元素的指针常量。,指向数组元素的指针,1.定义指向数组元素的指针变量,定义指向数组元素的指针变量与定义指向变量的指针变量的 方法相同.如:,int a10; int *p; p=,由于数组名是指向0号元素的指针类型符号常量, 所以a与&a0相等。,p= 两句等价,p=a不是把a的各元素赋给p,注意数组名与指针变量的区别,指针运算,指针变量可以加减一个整数,两个同类型指针可以 相减 得到一个整数。指针变量每增减1, 地址值增减量等于所指向 的变量类型的字节数sizeof(type), 将它称作地址步进单位d。 当指针变量指向数组元素时, 指针变量每加减1,表示指针前 后移动1个元素, 地址值增减d。,如: int a10,*p; p=a; p+; p+=3;,注意: 指针变量的运算顺序。,+*p,*p+,*(+p),(*p)+ 四者之间的差别:,+*p,先给p指向的变量加1,然后取其值,(*p)+,先取p指向的变量值, 然后该变量值加1,*p+,取p所指向变量的值, 然后p增1,*+p,P先增1, 然后取p所指向变量的值,main() int a4=1,2,3,4,b,c,d,e; int *p=a; b=*p+; printf(“n%d,%d,”,b,*p); c=*+p; d=+*p; printf(“%d,%d”,c,d); ,运行结果 1,2,3,4,通过指针引用数组元素,在 int a10,*p=a; 定义的情况下:,(1) p+i或a+i就是ai的地址。都要进行a+id的运算。,(2) *(p+i)或*(a+i)就是p+i或a+i所指向的数组元素ai。 数组元素中的 “ ” 是变址运算符, 相当于*( + ) , ai 相当于*(a+i)。,(3) 指向数组元素的指针变量也可带下标, 如 pi与*(p+i)等价。 所以, ai,*(a+i) ,pi,*(p+i) 四种表示法全部等价。,(4) 注意p与a的差别,p是变量a是符号常量,不能给a赋值, 语句a=p; a+; 都是错的。,a,引用数组元素可用: 1)下标法,如ai,pi。 2) 指针法,如*(p+i)或*(a+i),其中p是指向数组a的元素的指针变量。,main( ) int a10; int *p,i; for(p=a;p(a+10);p+) scanf(“%d“, p); printf(“n“); for(i=0;i10;i+) printf(“%d“, ai); , for(i=0;i10;i+) printf(“%d“, *(a+i); p=a; /*不能省略*/ for(i=0;i10;i+,p+) printf(“%d“, *p); for(p=a;p(a+10);p+) printf(“%d“,*p);,例.输入/输出数组全部元素,用字符型指针访问字符数组和字符串,【例9.5】用字符型数组名和字符指针变量 两种方法整体输入/输出字符串。,main() char s81=“Hello!“,*p=s; char *ps=“Welcome to you!“; printf(“%sn“,s); printf(“%sn“,ps); gets(s); printf(“%sn“,s); gets(p); printf(“%sn“,s); ,字符指针变量和字符数组的区别,(1) 存储的内容不同:,字符数组存储着字符串的内容, 而字符指针变量 存放的是字符串首元素的地址,不是它的内容。,(2) 分配的内存单元不同:,字符数组分配一段有确定地址的内存。而指针变 量只分配存放地址的内存单元,该指针变量可以 指向一个字符型数据,但若未赋初值,则它并未指向 一个明确的地址。此时它指向的变量并不存在。,(3) 赋值方法不同:,对字符数组只能在定义时整体赋初值, 不能用赋值语句 整体赋值。赋值语句只能对各个元素分开赋值。,如: char s16; s=“I am a student.“;,char s16=“I am a student.“;,对字符指针变量, 可以采用下面方法赋值: char *p; p=“I am a student.“;,(4) 指针变量的值是可以改变的, 字符数组名是地址常量其值是不能改变的。,数组或指针变量作函数参数,如: main( ) f(int a , int n) int array10; . . . . . . f(array,10) . . . ,由于数组名代表首地址,能接收并存放地址值的只能 是指针变量。故编译系统将形参数组名作为指针变量 来处理。例中函数首部 f(int a , int n) 可写成 f(int *a, int n) 两种完全等价。,归纳起来,如果有一个数组,想在被调用的函数中 改变其元素的值,实参与形参的对应关系有以下四种:,(1).实参和形参都用数组名。 (2).实参用数组名, 形参用指针变量。 (3).实参用指针变量, 形参用数组名。 (4).实参和形参都用指针变量。,实质都是地址值的传递,【例9.7】通过调用函数, 将整型数组的所有元素 加10。参数传递用四种方法实现。,void add(int b , int n) int i; for(i=0; in; i+) bi+=10; main( ) int i, a10= 1,2,3,4,5,6,7,8,9,10; add(a,10); for(i=0; i10; i+) printf(“%4d“,ai); ,void add(int *p, int n) int *pend=p+n; for(; ppend; p+) *p+=10; main( ) int i, a10= 1,2,3,4,5,6,7,8,9,10; add(a,10); for(i=0; i10; i+) printf(“%4d“,ai); ,void add(int b , int n) int i; for(i=0; in; i+) bi+=10; main( ) int i, a10= 1,2,3,4,5,6,7,8,9,10; int *q=a; add(q,10); for(i=0; i10; i+) printf(“%4d“,ai); ,void add(int *p, int n) int *pend=p+n; for(; ppend; p+) *p+=10; main( ) int i, a10= 1,2,3,4,5,6,7,8,9,10; int *q=a; add(q,10); for(i=0; i10; i+) printf(“%4d“,ai); ,用字符数组或指针做函数参数传递字符串,将字符串从一个函数传递到另一个函数, 可以用地址传递的方法, 即用字符数组名 或用字符指针变量作参数。在被调用的函 数中可以改变字符串中的内容, 在主调函数 中可以得到改变了的字符串。,【例9.8】 字符串复制函数主要功能的实现。,(1)用字符数组作参数,void strcpy(char s1 ,char s2 ) int i=0; while(s2i!=0) s1i=s2i; i+; s2i=0; main( ) char a20=“I am a teacher.“; char b =“you are a srudent.“; printf(“string a=%sn string b=%sn“,a,b); strcpy (a,b); printf(“n string a=%sn string b=%sn“,a,b); ,(2)形参用字符指针变量。,程序如下: void strcpy(char *s1, char *s2) for( ; *s2!=0; s2+, s1+) *s1=*s2; *s1=0; main( ) char a20=“I am a teacher.“; char *b=“you are a srudent.“; printf(“string a=%sn string b=%sn“,a,b); strcpy(a,b); printf(“n string a=%sn string b=%sn“,a,b); , while( *s1=*s2)!=0 ) s1+; s2+; *s1=0; , while( *s2!=0 ) *s1+=*s2+; *s1=0; , while( *s2 ) *s1+=*s2+; *s1=0; , while( *s1+=*s2+)!=0 ) , while( *s1+=*s2+ ) ,多维数组和指向分数组的指针,多维数组的地址,以二维数组为例,设二维数组a有3行4列。 int a34=1,2,3,4,5,6,7,8,9,10,11,12,a是数组名, a数组有3行, 即3个分数组:a0,a1,a2。 每个分数组又是含4个列元素的一维数组 。,2000,基类型,行指针 与列指针,a23 *(a2+3) *(*(a+2)+3),+3,+2,+1,+0,a0,a0,a0,a0,*(a+0),*(a+0),*(a+0),*(a+0),+3,+2,+1,+0,a1,a1,a1,a1,*(a+1),*(a+1),*(a+1),*(a+1),注意,a+1与a0+1不同 a+1是a第1行分数组地址 *(a+1)是第1行数组名 *(a+1)是元素a10 a0是第0行分数组名 a0+1是元素a01 地址 *(a0+1)是元素a01,形式 含义 内容 a ,&a0 二维数组名,0行分数组地址 1000 a0,*(a+0),*a ,&a00 0行一维数组名,0行0列元素地址 1000 a0+1,*a+1,&a01 0行1列元素地址 1002 a+1,&a1 1行一维数组首地址 1008 a1,*(a+1) ,&a10 1行一维数组名,1行0列元素地址 1008 a1+3,*(a+1)+3,&a13 1行3列元素地址 1014 *(a2+3),*(*(a+2)+3),a23 2行3列元素 12 注意: a和a0的地址均为1000但不等价,a+1和a0+1不等。,指向多维数组的指针,1.指向多维数组元素的指针,例:用指针变量输出数组元素的值。 main( ) int a34=1,2,3,4,5,6,7,8,9,10,11,12; int *p; for (p=a0;pa0+15;p+) if(p-a0)%5=0) printf(“n“); printf(“%4d“,*p); ,定义形式: 数据类型 (*指针名)一维数组维数;,一维数组指针变量维数和二维数组列数必须相同。,例:int a34, (*p)4=a;,2.指向分数组的指针,p0+1,p,或*p+1,p1+2,p+1,或*(p+1)+2,p+2,int a34; int (*p)4=a;,例:用指向二维数组的分数组的指针变量,按行输出。 main( ) int a34=1,2,3,4,5,6,7,8,9,10,11,12; int *q,(*p)4; for(p=a;pa+3;p+) for(q=*p;q*p+4;q+) printf(“%5d“,*q); printf(“n“); ,注意: int (*p)5; 表示p是一个指针变量,可以指向含有5个元素的一维数组,其中每个元素都是整型的。 如果定义为 int *p5; 由于 “ ” 优先级高, 则表示p首先是数组,它有5个元素, 每个元素为指向整型变量的指针。,用多维数组名和指针变量作函数参数,(1)用多维数组名作实参或形参。,如: f(int a 4, int n);,(2)用指向元素的指针变量作实参或形参。,如: f1(int *p);,(3)用指向分数组的指针变量作函数参数。,如:f2(int (*q)4, int m);,【例9.16】 用两个二维数组存储矩阵,调用函数求两个 矩阵之差,差矩阵存放在第一个实参数组中,用指向分数 组的指针变量作形参。矩阵输出也用函数实现。,#define N 4 sub(int (*p1)N,int (*p2)N,int m) int *q1,*q2,(*u)N; u=p1+m; for(;p1u;p1+,p2+) for(q1=*p1,q2=*p2;q1*p1+N;q1+,q2+) *q1-=*q2; print(int (*p)N,int m) int *q,(*u)N; u=p+m; for(;pu;p+) for(q=*p;q*p+N;q+) printf(“%6d“,*q); printf(“n“); printf(“n“); main() int i,j,a N=1,2,3,4,5,6,7,8 ; int b N=10,20,30,40,50,60,70,80; print(a,2); print(b,2); sub(b,a,2); print(b,2); ,指针数组,如果每个数组元素均为指针类型的变量,即数组元 素的类型是指针类型,则称这样的数组为指针数组。,一维指针数组的定义形式为: 基类型名 *数组名 数组长度 =地址初值列表,例如: int i,j,k,m,n; int *q5=,main() char a =“Program“; char b =“Fortran“; char c =“Basic“; char *p4; p0=a; p1=b; p2=c; p3=NULL; ,char *p4,0,或: main() char *p4; p0= “Program“; p1= “Fortran“; p2= “Basic“; p3=NULL; ,初始化: main() char *p =“Program“, “Fortran“, “Basic“,NULL; ,用指针数组处理多个字符串,例:将5个字符串递增排序后输出。 #include #include main() char *pccolor =“red“, “blue“, “yellow“, “green“, “purple“; int n=5; printf(“Before sorting is:n“); OutPut(pcolor,n); Sort(pcolor,n); printf(“After sorting is:n“); OutPut(pcolor,n); ,void Sort(char *a , int n) int i,j,k; char *t; for(i=0;in-1;i+) for(j=i+1;jn;j+) k=j; if(k!=i) t=ai; ai=ak; ak=t; ,if(strcmp(ak,aj)0),void OutPut(char *a ,int n) int i; for(i=0;in;i+) printf(“%sn“,ai); ,排 序 前,排 序 后,指向指针的指针(二级指针),指针变量中存放一级指针变量的地址,例 int *p1; int *p2; int i=3; p2=,二级指针,一级指针,目标变量,二级间接寻址,&p2,&i,5,3,用指向指针的指针访问指针数组,通过指针变量来访问指针数组的元素,就必须定义 指向指针的指针变量。用所定义的指向指针的指针 变量来指向指针数组的各元素,进行间接访问。若 要通过该指针变量来访问指针数组元素所指向的变 量的内容,则需要进行两次间接访问。,【例9.10】 指针数组的各元素指向整型数据的简单实例,main() static int s5=10,20,30,40,50; int *q5= ,指针数组作main( )函数的形参,C语言规定,main() 函数形参是固定的,第一个形参为 整型,它接收实参的个数,第二个形参为字符指针数组, 它的各元素分别接收命令行输入的各字符串的首地址。,例如:main(int argc,char *argv ),形参argc接收实参的个数, 字符指针数组argv接收各字符串的首地址。,它的一般形式为: 命令名 参数1 参数2 参数n-1,【例9.11】编写源程序show.c,在命令行输入show和 若干个字符串后,顺序分行显示这些字符串。,show.c 的程序如下: main(int argc,char *argv) int i; for(i=1;iargc;i+) printf(“%sn“,argvi); ,改写为: main(int argc,char *argv) while(-argc0) printf(“%sn“,*+argv); ,【例9.12】 编写程序echo.c,实现操作系统中的echo命令, echo命令是将后面所带的参数原样显示出来。它与上例相似 但不分行,所带的参数都显示在同一行。,main(int argc,char *argv) while(-argc0) printf(“%s%c“,*+argv,(argc1)? :n); ,在操作系统命令行状态下输入: echo Welcome to you ! ,执行后输出以下信息: Welcome to you !,【例9.18】实现系统提供的字符串复制函数strcpy()的全部功能。,char *strcpy(char *s1,char *s2) char *p=s1; while(*s1+=*s2+); return(p); main() char s20; printf(“%sn“,strcpy(s,“Welcome to you!“); ,结构体与指针,指向结构体变量的指针,结构体指针变量的定义: struct 结构体名 * 指针变量名; 例如: struct student *pt=,struct student int num; char name20; char sex; int age; stu;,使用结构体指针变量引用成员形式,(*结构体指针名).成员名,结构体指针名-成员名,结构体变量名.成员名,struct student int num; char name20; char sex; int age; stu; struct student *p=,(*p).num,p-num,stu.num,p=&stu.num,例:结构体指针的使用,#include #include struct student int num; char name20; char sex; int age; ; main() struct student stu, *p; p= ,例:结构体数组指针的使用,struct student int num; char name20; char sex; int age; stu3= 10101, “Li Lin“,M,18, 10102,“Zhang Fun“,M,19, 10103,“Wang Min“,F,20; main() struct student *p; for(p=stu;pnum,p-name, p-sex,p-age); ,10101,Li Lin,M,18,10102,Zhang Fun,M,19,10103,Wang Min,F,20,结构体指针作函数参数,用结构体变量的成员作参数-单值传递 用结构体变量作参数-多值传递 用指向结构体变量或数组的指针作参数 -地址传递。,【例9.17】 采用“引用传递”的方式,用指向结构体 的指针变量作参数,在input函数中输入并计算平均成 绩,在main函数输出。,#define N 4 #include #define FMT “%5d %-11s%5d%8d%8d%10.1fn“ struct st int num; char name11; int s3; float aver; ; void input(struct st *p) scanf(“%d%s%d%d%d“, ,指针与链表,链表可以动态的进行存储分配,head: 头指针,存放一个地址,指向链表中的第一个元素.,每一个元素称为一个“结点”,每个结点都包括两部分:,1.用户需要的实际数据;,2.下一个结点的地址.,表尾: 它的地址部分放一个“NULL”,链表到此结束.,可用结构体类型的变量来存储链表中的结点元素.,每一个结点中存放地址的部分可用指针来实现.,例: struct student int num; float score; struct student *next; ;,简单静态链表,# define NULL 0 struct student long num; float score; struct student *next; ; main( ) struct student a,b,c,*head,*p; a.num=9901; a.score=89.5; b.num=9903; b.score=90; c.num=9905; c.score=85; head= ,9901,89.5,9903,90,9905,85,&a,&b,&c,NULL,&a,&b,&c,NULL,动态链表,处理动态链表所需的函数,1. malloc 函数,void *malloc (unsigned int size);,作用是: 在内存的动态存储区分配一个长度为size的连续空间,原型说明在“stdlib.h”头文件和“alloc.h”头文件中,2.calloc函数,void *calloc(unsigned n,unsigned size);,作用是: 在内存的动态区分配n个长度为size的连续空间.,3. free函数,void free(void *p);,作用是: 释放由p指向的内存区.,typedef struct Node int data; struct Node *next; Node;,链表的插入操作,s-next=pre-next;,pre-next=s;,顺序可以 颠倒吗?,void InsList(Node *L,int i,int e) Node *pre,*s; int k=0; pre=L; while(pre!=NULL ,链表的删除操作,pre-next=pre-next-next;,free(r);,void DelList(Node *L,int i) Node *pre,*r; pre=L; int k =0; while(pre-next!=NULL ,建立动
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 《手术室医院感染控制课件》
- 电视购物与多渠道融合营销考核试卷
- 纤维板制造原理考核试卷
- 人工智能在风险评估中的自然语言处理应用考核试卷
- 计划生育技术服务在灾害应急中的应对措施考核试卷
- 《出血性疾病课件概述》
- 数字智慧方案5425丨莆田港务集团5G智慧港口项目建设方案
- 2019-2025年材料员之材料员专业管理实务自我提分评估(附答案)
- 2025年基金从业资格证之证券投资基金基础知识真题练习试卷A卷附答案
- 海上风电运维船安全
- 河道治理及生态修复工程施工方案与技术措施
- (二模)2025年合肥市高三第二次教学质量检测英语试卷(含答案)
- 水利水电工程质量保证体系
- 《思想道德与法治》(23版):第五章 遵守道德规范 锤炼道德品格
- 人工智能在生活中的应用课件
- 2024年安徽省《辅警招聘考试必刷500题》考试题库及完整答案(必背)
- 中国古代文学作品选一完全版
- 生物分离工程模考试题含参考答案
- 中国老年患者术后谵妄-
- 香梨果实硬度与果实成熟度之间的关系探讨
- 2025年部编版新教材语文一年级下册期末测试题及答案(一)
评论
0/150
提交评论