第八章指针ppt课件.ppt
第八章 指针,本章教学目标:,1、地址与指针的概念2、变量的指针和指向变量的指针变量3、数组的指针和指向数组的指针变量4、指针做函数参数,第8章 指针,变量和数据在内存中存放都要占用一定数量的内存空间(单位为字节)。计算机内存中的每个字节都有一个编号,该编号称为内存地址即指针。,变量的地址:每个变量的地址是指该变量所占存储单元 的第一个字节的地址。,指针:由于通过地址能找到所需的变量单元,可以说,地址“指向”该内存单元。所以,c语言中又将 地址形象化的称作“指针”。即某个变量的指针就是该变量的地址。,8.1指针和地址的概念,指针变量:C语言中有一种特殊的变量可以存放普通变量的地址,称为指针变量。而要取得一个普通变量a的地址可使用&运算符(取地址运算符)。例如:若有变量a,则:&a即表示变量a的地址。反之,若要取得变量a的地址则可使用&运算符,即&a。即:专门存放指针(地址)的变量称为指针变量。,8.2 变量的指针和指向变量的指针变量,由上节可知,变量的指针就是变量的地址。存放变量地址的变量就是指针变量,用来指向另一个变量。,例如:int i=3;,3,变量p的空间,2000H,此处p即为指针变量,变量i的空间,在这里也可以说变量p指向变量i,在程序中用“*”表示“指向的对象”。,用*表示指向,即*p就表示变量i,所以,*p=3 与 i=3 等价,要使用指针变量,首先要弄清指针变量的4个要素:,1、指针变量的类型:int型。,2、指针变量基类型:指针变量所指向的变量的类型。,3、指针变量的值:指针变量所指向的变量的地址。,4、指针变量本身所占据的存储单元:指针变量用来存放地址时所需占用的内存大小。,形式:,变量名,*,类型名称,注:1)*说明符,用来说明该变量为指针变量,2)类型名称:基类型,用来指定指针变量所指向的变量的类型。,3)指针变量的值是其所指向的变量的地址,而不能是普通的数据。,例如:若有定义 int*p,x;,若使p指向x,则可用:,p=,p=3;(错误),一、指针变量的定义,练习:(1)定义一个指向单精度型数据的指针变量q(2)定义一个指向字符型数据的指针变量p,float*q;,char*p;,4)一个指针变量只能指向同一个类型的变量。,例如:若有定义 int x;float y;int*p;,p=,p=,warning:incompatible types-from float*to int*,二、指针变量的引用,1、给指针变量赋值,指针变量在使用之前必须先定义,而且必须赋值后才能使用,未经赋值的指针变量不能使用。,(1)定义的同时赋值如:int a;int*pa=&a;,(2)先定义再赋值如:int a,b;int*p;p=&a;p=&b;,注:指针变量的赋值只能赋予地址,而不允许把一个数值赋给指针变量。,如:int*p;P=1000;(错误),例 int i;int*p=,变量必须已说明过且类型应一致,例 int*p=,例 int i;int*p=,用已初始化的指针变量作初值,2、引用指针变量的值,如有:int i;int*p=,则:printf(“%x”,p);,等价于:printf(“%x”,3、引用指针变量指向的变量,注:*指针运算符或者间接访问运算符,例题(lt1.c),pa=,pb=,/用pa指向变量a,/用pb指向变量b,scanf(“%d,%d”,pa,pb);,printf(“%d,%d”,*pa,*pa);,指针变量经过定义及初始化后,就可以使用指针变量来引用普通变量的值了。形式:*指针变量,scanf(“%d,%d”,printf(“%d,%d”,a,b);,/从键盘输入数据给a,b赋值,/输出a,b的值,总结:要使用指针变量,首先要弄清指针变量的4个要素:,1、指针变量的类型:int型。,2、指针变量基类型:指针变量所指向的变量的类型。,3、指针变量的值:指针变量所指向的变量的地址。,4、指针变量本身所占据的存储单元:指针变量用来存放地址时所需占用的内存大小。,5、&与*的优先级相同,结合性:自右而左。,所以,若有定义 int x,*p=则,&*p 表示x的地址,等价于&x 等价于p,*&x 表示x的地址所指的单元,等价于*p 等价于x,例题2(lt2.c)main()int a3=1,3,5,*p,i;p=a;printf(n);printf(n);,for(i=0;i3;i+)printf(%6d,);,*(p+i),/*将数组首地址赋值给指针变量p*/,for(i=0;i3;i+)printf(%6d,);,/*输出数组元素*/,或者*(a+i),printf(%6d,*p);p=p+1;,printf(%6d,*p);p+;,ai,for(p=a;pa+3;p+)printf(%6d,*p);,main()int a3,*p,i;printf(n);printf(n);,for(p=a;pa+3;p+)scanf(%d,p);,/*给数组元素赋值*/,for(p=a;pa+3;p+)printf(%6d,*p);,/*输出数组元素*/,注:1)指针移动的最小单位是一个存储单元,而不一定是一个字节。对于基类型不同的指针变量,其增减1所“跨越”的字节数是不同的。,2)只有当指针指向一串连续的存储单元时,指针的移动才有意义。,8.2 指针与数组,8.2.1指针与一维数组,数组元素的指针:数组元素的地址。,数组的指针:数组的首地址。,一、数组元素的指针,数组元素的指针就是数组元素的地址。同前所述的普通变量的指针,例如:int a3,*p;p=/*指针变量p指向元素a1*/,二、指针的运算,C语言中指针指向数组元素时,可以对指针进行以下运算:,如有指针变量p、q,普通整型变量n,则可进行如下形式的运算:,p+n,p-n,p+,p-,q-p、p-q,例如,若有定义:int a10;,则:a 与&a0的关系?,数值相等,再有定义:int*p=a;,则:p、a 与&a0的关系?,数值相等,则:*p、*a 与a0的关系?,相等,所以若有定义:int a10;,则:a 与&a0的关系?,数值相等,a+1 与&a1的关系?,数值相等,a+i 与&ai的关系?,数值相等,再有定义:int*p=a;,则:p+i、a+i 与&ai 的关系?,数值相等,*(p+i)、*(a+i)与 ai 的关系?,数值相等,数组中任意元素的地址,数组中任意元素的引用,所以若有定义:int a10,*p=a;请考虑以下问题:,a=a+1;是否正确,为什么?,p=p+1;是否正确,为什么?,三、用指针引用数组元素,若有定义:int a10,*p=a;则,1)下标为i的元素的地址:,2)下标为i的元素:,3)数组的指针变量可以用下标的形式:*(p+i)等价于pi,&ai,a+i,p+i,ai,*(a+i),*(p+i),例 int a=1,2,3,4,5,6,7,8,9,10,*p=a,i;数组元素地址的正确表示:(A)&(a+1)(B)a+(C)&p(D)&pi,分析以下几种形式正误p+或者p-a+或者a-a+1 或者a-1,(),(),(x),关于指针的运算:1)+与*的优先级相同,结合性:自右而左。,2)*p+等价于*(p+),表示先取出p的值,得到*p,再使p的值增1。,*+p 等价于*(+p),表示先使p的值增1,再得到*p,3)(*p)+表示先取得p所指单元的内容,然后使该单元内容加1。,4)+(*p)表示先使p所指单元的内容加1然后取得该单元内容。,则下列表达式的值分别为多少?,(1)*p+,20,(2)*+p,30,(2)+*p,21,若指针p、s均为int型,且p已经指向a1,则:,1)通过指针p给s赋值,使s指向a4的语句为:,s=p+3;,2)用以移动s,使其指向a2的表达式为:,s-=2,3)已知k=2,指针s指向a2,则表达式*(s+k)的值为:,50,4)指针s指向a2,不移动指针,通过s引用a3的表达式为:,*(s+1),5)指针s指向a2,p指向a0,则s-p的值为:,2,指针做函数参数,形参是指针,实参是地址值或者指针变量。(见以下示例),当指针做函数参数时,形参和实参对应的是相同的内存空间,所以当在函数中改变形参的值时,改变的就是原来实参的值。,请看以下例题(lt6_5.cpp):,因为数组名是数组的首地址,所以当数组名做函数参数时,传递是地址(指针)。因此当在函数中对形参数组进行操作时,实际上就是对实参数组的操作。,四、指针做函数参数,#include using namespace std;void swap(int*,int*);void main()int x=5,y=8;coutx=x,y=yendl;swap(,实参是地址值,形参是指针,#include using namespace std;void main()int x=5,y=8;printf(x=%d,y=%dn,x,y);swap(,&x,&y,将实参的值传给形参,5,8,int*px=,swap(px,py);,void swap(int*,int*);,/函数声明,练习:请分析一下程序的运行结果(lt6_5.cpp)#include using namespace std;void swap(int b);void main()int a=5,8;couta0=a0,a1=a1endl;swap(a);couta0=a0,a1=a1endl;void swap(int b)int t;t=b0;b0=b1;b1=t;,/实参是数组名,/形参是数组名,void swap(int b)int t;t=b0;b0=b1;b1=t;,void swap(int b)int t;t=b0;b0=b1;b1=t;,等价于,*b,1)若对swap函数的调用,实参是数组名:swap(a),形参数组可以为以下形式:,int t;t=*(b+0);*(b+0)=*(b+1);*(b+1)=*(b+0);,所有int a2,*p=a;,形参可以是数组名,形参可以是指针变量,2)若对swap函数的调用,实参是指针变量:swap(p),形参数组可以为以下形式:,所有int a2,*p=a;,void swap(int*b)int t;t=*(b+0);*(b+0)=*(b+1);*(b+1)=*(b+0);,void swap(int b)int t;t=b0;b0=b1;b1=t;,等价于,形参可以是数组名,形参可以是指针变量,总结:归纳起来,如果有一个实参数组,要想在函数中改变此数组中的元素的值,实参于形参的对应关系有以下4种情况:,1)形参和实参都用数组名。,2)实参用数组名,形参用指针变量。,3)实参用指针变量,形参用数组名。,4)实参和形参都用指针变量。,练习:请分析以下函数的功能。void upper(char*p)do if(*p=a,函数功能:将p字符串中的小写字母转换成对应的大写字母,练习:写出以下程序的运行结果:#include void upper(char*p)do if(*p=a,练习1):以下函数的功能是将一个数组中的元素倒序排放,请填空:void reverse(int*p,int n)int*q,t;for(;pq;p+,)t=*p;*p=*q;*q=t;,q=p+n-1,q-,练习2)以下程序是调用reverse函数,将实参数组中的元素倒序排放,请填空。(lt8_8.c),#include void main()int i,a10,*p=a;printf(请输入10个数组元素:n);for(i=0;i10;i+,)scanf(%d,p);printf(n);reverse(,10);printf(变化后的数组元素为:n);for(;pa+10;p+)printf(%d,);printf(n);void reverse(int*p,int n)int*q,t;for(q=p+n-1;pq;p+,q-)t=*p;*p=*q;*q=t;,p+,p=a;,void reverse(int*,int);,*p,p=a,p,请大家仔细阅读教材208页例题8.8!,五、通过指针引用二维数组,1、二维数组地址的表示方法,在c语言中,可以把一个二维数组先看成一个一维数组,数组中每个元素又是包含若个元素的一维数组。,若有定义:int a34;请思考下列问题:,a的值?,a0的值?,&a00的值?,a+1的值?,a0+1的值?,&a00+1的值?,数值是否相等?含义是否相同?,数值是否相等?,由以上分析可以得出:,ai:表示第i行的首地址,每加1相当于加1列,也称为列地址。,a:表示整个数组的首地址,每加1相当于加1行,也称为行地址。,a+i,ai,&ai0在数值上等同,但含义不同。,注:不要把&ai简单地理解为 ai元素的物理地址,因为并不存在ai这样一个变量。它只是一种地址的计算方法,能得到第i行的首地址,&ai与ai值相同,但含义不同。,&a00或者 a0或者*a,1)指向二维数组元素的指针变量 这样的指针为指向某一具体类型的指针变量。,例如:main()int a34=1,2,3,4,5,6,7,8,9,10,11,12;int*p;p=/*使p指向首元素*/for(;pa0+12;p+)printf(“%d“,*p);,&a00,a0,a,*a,2、指向二维数组的指针变量,2)指向由m个元素组成的一维数组的指针变量,格式:类型名(*指针变量名)m;,例如:int(*p)4;,含义:p是指针变量,它指向一个数组,数组含有4个元素,每个元素的类型是int。此时,p的增值以一维数组的长度为单位。,注:括号不可省。int(*p)4;与 int*p4;是不同的含义,例如:main()int a34=1,2,3,4,5,6,7,8,9,10,11,12;int i,j;int(*p)4;p=;/*使p指向数组的首地址*/for(i=0;i3;i+)for(j=0;j4;j+)printf(“%d”,);,&a00,a0,a,*a,*(*(p+i)+j),3)用指向数组的指针做函数参数,一维数组名称可以做函数参数,二维数组名称也可以做函数参数。在用指针变量做形参接受实参传递的地址时,注意实参和形参类型的一致。,若有定义int a34;有一个fun函数,请思考以下问题:,函数调用形式:,fun(a0,),函数定义时的形式:,fun(,),int*p,fun(a,),fun(,),int(*p)4,例题:编写一个函数求一个二维数组中所有元素的平均值。,float aver(float,int n)float s;int i;for(i=0;in;i+,p+)s=s+;return;,float aver(float,int n)float s;int i;for(i=0;in;i+,p+)for(j=0;j4;j+)s=s+;return;,具有n个元素的二维数组,*p,每行4个元素的n行的二维数组,(*p)4,*p,*(*p+j),s/n,s/(n*4),练习:有一个班级,有5个同学,每个同学4门成绩,编写程序完成(lt8_12.c)1)用一个函数实现求所有同学所有成绩的平均分。2)用一个函数实现输出某个同学的成绩信息。3)用一个函数输出有不及格课程的同学所有成绩。4)在main函数中调用以上三个函数,输出相应的信息验证以上函数的正确性。,作业:247页第14题,#include float aver(float(*p)4,int n)float s=0;int i,j;for(i=0;in;i+,p+)for(j=0;j4;j+)s=s+*(*p+j);return s/(n*4);void show(float(*p)4,int n)int i;for(i=0;i4;i+)printf(%.2f,*(*(p+n)+i);void lose(float(*p)4,int n)int i,j,flag=0;for(i=0;in;i+,p+)flag=0;for(j=0;j4;j+)if(*(*p+j)60)flag=1;break;if(flag=1)printf(No:%d:,i+1);for(j=0;j4;j+)printf(%.2f,*(*p+j);printf(n);,void main()int n;float a24=30,40,50,60,90,60,70,80;printf(average is:%.2fn,aver(a,2);lose(a,2);printf(input the number you want to search:);scanf(%d,main()char s320=china,beijing,jinan;char(*p)20;int i;/*使p指向第一个字符串*/for(i=0;i3;i+)/*输出p所指向的字符串*/*使p所指向下一个字符串*/,练习:用指向一维数组的指针输出字符串数组中的每一个字符串。,puts(p);,p+;,p=s;,3、指针数组,1)指针数组的概念,指针数组是一种特殊的数组,它每个元素的类型都是指针类型(即地址),其它与一般数组相同。,2)指针数组的定义,类型名*指针数组名常量表达式如:int*ap3;char*s10;等等。每个元素api 都等同于一个普通整型指针变量,可把某个变量的地址赋给该元素(指针变量),该元素即指向那个变量,即可通过该元素对相应的变量进行间接访问。,注意:int*ap3;与 int(*ap)3;的区别,3)指针数组的常用作用:(1)通常可用一个指针数组来指向一个二维数组。指针数组中的每个元素用来指向二维数组的每一行。,例题:输出二维数组的每个元素。,main()int a33=1,2,3,4,5,6,7,8,9,i,j;/*定义一个包含3个元素的int型的指针数组p*/*使p数组的3个元素分别指向a数组的每一行*/for(i=0;i3;i+)for(j=0;j3;j+)printf(%d,aij);printf(“n”);,int*p3;,for(i=0;i3;i+)pi=ai;,p0=a0p1=a1p2=a2,*(Pi+j),课程回顾,1、说明语句int(*p)M;的含义是()P是指向整型数据的指针变量P是指向函数的指针变量P是指向有M个整型数据组成的一维数组的指针变量P是由M个指针元素组成的一维数组,C,2、以下程序的运行结果是()#include void main()int a33=1,2,3,4,5,6,7,8,9;int(*p)3=a,j;for(j=0;j3;j+)printf(“%d”,*(*(p+j)+j);,1 5 9,3、关于int*p4和int(*q)4,以下说法正确的是()A.p和q都是数组名 B.p为指针数组名,q为指向整型变量的指针变量 C.q是一个指针,它指向一个含有4个整型元素的一维数组 D.两个表达式等价,C,4、若有int a34,(*p)4;p=a;则以下表达式等价的是()A.p+1和a1 B.*(p+1)和a1 C.*(p+1)和a1 D.*(*p+2)+1和a2+1,A,main()char s320=china,beijing,jinan;/*定义一个指针数组*/int i;/*使p数组的3个元素分别指向a数组的每一行*/for(i=0;i3;i+)/*输出每行字符串*/,(2)指针数组也常用来表示一组字符串,这时指针数组的每个元素被赋予一个字符串的首地址。,练习:用指针数组输出字符串数组中的每一个字符串。,char*p3;,puts(pi);,for(i=0;i3;i+)pi=ai;,char*p3=china,beijing,jinan;,char*p3=china,beijing,jinan;,8.4指针与字符串,字符串是一种特殊的一维数组,所以上节中介绍的方法同样适用于对字符串的访问。字符串的特殊性在于:以 0 作为结束标志,所以访问字符串时常用结束标志进行判断。,字符串指针变量的定义说明与指向字符变量的指针变量说明是相同的,只能按对指针变量的赋值不同来区别。,例如:有如下定义:char c,str=“happy”;char*p;,p=,p指向的字符变量c,p=str;,p指向的字符串“happy”,1、字符串结构的分析,设有数组定义为:char s=“abcde”;则s是一个字符数组,它里面存放的是一个字符串。它在内存中占用6个字节,但字符串长度为5。其结构为:,s,s0 s1 s2 s3 s4 s5,结束标志,若:char*ps=s;,字符串还可以定义为:char*s=“abcde”;它在内存中占用6个字节,长度为5。其结构为:,s,s0 s1 s2 s3 s4 s5,结束标志,2、用字符数组与用指针使用字符串的比较,定义及初始化char s=“abcde”;char*p=“abcde”;赋值char s6;char*p,b20;s=“abcde”;/*不对*/p=“abcde”;p=b;strcpy(s,“abcde”);strcpy(p,“abcde”);使用s不能加/减,s+;p可以加/减,p+;,例 char str10;scanf(“%s”,str);而 char*cp;scanf(“%s”,cp);,改为:char*cp,str10;cp=str;scanf(“%s”,cp);,(),(),(),练习:1、若有char*s=“abcd”,以下叙述正确的是()A.s为字符数组名 B.字符串被存放在变量s中 C.上面语句等价于 char*s;s=“abcd”;D.字符串被存放在字符数组中,C,2、下面语句正确的是()A.char a=“abcd”;B.char a10;a=“abcd”;C.char*p;*p=“abcd”;D.char a10;a=“abcd”;,A,3、若有char*a2=“123”,”456”;,以下说法正确的是()A.数组a为2*4的二维数组 B.定义错误 C.a0的值为“123”的首地址 D.可以用puts(*a0);输出“123”,C,8.6 指向函数的指针,一、函数指针,程序在编译时,系统会为函数代码分配一段存储空间,这段存储空间的起始地址(又称入口地址),称为这个函数的指针。,函数名称代表函数的首地址。,二、用函数指针变量调用函数,1、指向函数的指针变量的定义形式:,类型名(*指针变量名)(函数参数列表),例如:int(*p)(int,int);表示定义了一个指向函数的指针变量p,它可以指向这样的函数:返回值是int型,有2个参数,每个参数都是int型。,2、函数指针变量的赋值,即使其指向一个具体的函数。,指针名称=函数名称,注:在给函数指针赋值时,只须给出函数名而不必给出参数。,例如:若有函数的定义如下:float max(float x,float y)return xy?x:y float min(float x,float y)return xy?x:y,定义一个可以指向max函数的指针变量:,float(*p)(float,float),若使p指向max函数应使用语句:,p=max;,若使p指向min函数应使用语句:,p=min;,3、用函数指针变量调用函数,(*指针变量)(实参列表),例如:若有函数的定义如下:float max(float x,float y)return xy?x:y,再有:float(*p)(float,float);p=max;,则对max函数调用形式有:,max(3.6,10.5),或者:,(*p)(3.6,10.5),注:用函数指针变量调用函数的主要作用:用函数名调用函数,只能调用所指定的一个函数,而通过指针变量调用函数比较灵活,可以根据不同情况调用不同的函数。,练习:请按要求填空:#include int add(int x,int y)return x+y;int sub(int x,int y)return x-y;int mul(int x,int y)return x*y;int div(int x,int y)return x/y;,void main()int a,b,z;char c;int(*p)(int,int);printf(input two numbers:n);scanf(%d%d,请大家课后阅读课本229页例题8.21,定义一个可以指向以上4个函数的指针变量p,根据输入的运算符不同,分别使p指向不同的函数,调用p所指向的函数,并将结果赋值给z,作业,课本247页第15题,9.6指向结构体的指针,一、定义形式:struct 结构体名*指针变量名,例如:struct student int num;char name10;char sex;stu;struct student*p;,二、赋值:把结构体变量的首地址赋值给指针变量。,例如:p=,p=正确与否?,三、用指针访问结构体成员形式:(*指针变量).成员名(注意:括号不可省)或者 指针变量-成员名,例如:struct student int num;char name10;char sex;stu;struct student*p=,若引用stu变量的成员:(*p).num p-name p-sex,例如:用指针方式输出结构体的各个成员。,Main()struct student int num;char name10;char sex;stu=1001,”张红”,F;struct student*p=,p-num,p-name,p-sex,9.7链表,链表是动态地进行存储空间分配的一种结构,可以适应数据动态地增减的情况,且可以方便地插入、删除数据项。,链表中有一个“头指针”变量,它存放一个地址。该地址指向一个元素。链表中的每一个元素成为“节点”,每个节点都应包括两个部分:一是用户需要用的实际数据,二是下一个节点的地址。每个链表中有最后一个元素,该元素不再指向其他元素,成为“表尾”,它的地址部分存放一个“NULL”(表示“空地址”),链表到此结束。链表中各个元素在内存中可以不是连续存放的。,例如:struct studentint num;float score;struct student*next;,上例中成员num和score用来存放节点中的有用数据,next是指针类型的成员,它指向struct student类型数据。一个指针类型的成员既可以指向其他类型的结构体数据,也可以指向自己所在的结构体类型的数据。用这种方法就可以建立链表。,例题:简单链表的建立#define NULL 0struct student long num;float score;struct student*next;main()struct student a,b,c,*head,*p;a.num=99101;a.score=88.5;b.num=99103;b.score=90;c.num=99107;c.score=85;head=,本例中所有节点都是在程序中定义的,不是临时开辟的,用完后也不能释放,这种链表称为“静态链表”。,一、动态存储分配,链表结构是动态地分配存储的,即在需要时才开辟一个节点的存储单元。C语言编译系统的库函数提供了几个实现动态存储分配的函数。,1、malloc函数,函数原型:void*malloc(unsigned int size);,作用:在内存的动态存储区中分配一个长度为size的连续空间。此函数的返回值是一个指向分配域起始地址的指针(基类型为void)。如果此函数未能成功地执行,则返回空指针(NULL)。,例如:假如一个节点的类型是struct student,则使用此函数返回的指针应做如下转换:(struct student*)malloc(sizeof(struct student),2、calloc函数,函数原型:void*malloc(unsigned n,unsigned size);,作用:在内存的动态存储区中分配n个长度为size的连续空间。此函数的返回值是一个指向分配域起始地址的指针。如果此函数未能成功地执行,则返回空指针(NULL)。用calloc函数可以为一维数组开辟动态存储空间,n为数组元素的个数,每个元素长度为size。,3、free函数,函数原型:void free(void*p);,作用:释放由p指向的内存区,使这部分内存区能被其他变量使用。P是调用calloc或malloc函数时返回的值。Free函数无返回值。,二、单链表的建立,所谓建立动态链表是指在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟节点和输入各个节点的数据,并建立起前后相链的关系。,例题:建立一个有3个学生数据的单向动态链表。(creat.c),#define NULL 0#define Len sizeof(struct student)struct studentlong num;float score;struct student*next;main()struct student*head;long int num;float score;struct student*p1,*p2;p1=p2=(struct student*)malloc(Len);head=p1;head-next=NULL;scanf(%ld,%f,三、从单链表中删除节点,从一个动态链表中删去一个节点,并不是真正从内存中把它删除,而是把它从链表中分离开来,只要撤销原来的链接关系即可。,A,B,C,D,E,对于被删除的结点在链表中的位置只有三种情况,对应的修改结点指针的方法也有三种:,若有:struct nodeint n;struct node*next;假设已经建立好链表,其中s为要删除的结点,p为s的前结点,t为s的后结点。则:,1)s位于链表的表头 head=s-next,若有:struct nodeint n;struct node*next;假设已经建立好链表,其中s为要删除的结点,p为s的前结点,t为s的后结点。则:,2)s在链表的中间 p-next=s-next,3)s位于链表的表尾 p-next=NULL,p-next=s-next,struct student*del(struct student*head,long num)struct student*p1,*p2;if(head=NULL)print(nthis list isnull!n);return(head);p1=head;while(num!=p1-num,四、向链表中插入结点,同删除结点一样,也可以像链表中插入结点,而不破坏原来链表的结构。其方法同删除结点类似也是通过修改结点指针的值来完成。,依据要出入的结点在链表中的位置的三种情况,对应的修改结点指针的方法也有三种:,若有:struct nodeint n;struct node*next;假设已经建立好链表,其中s为要插入的结点,p为s的前结点,t为s的后结点。则:,1)s在链表的中间 p-next=s s-next=t,若有:struct nodeint n;struct node*next;假设已经建立好链表,其中s为要插入的结点,p为s的前结点,t为s的后结点。则:,2)s插入到链表的表头 head=s-next s-next=t,3)s插入到链表的表尾 p-next=s s-next=NULL,struct student*insert(struct student*head,struct student stu)struct student*p0,*p1,*p2;p1=head;p0=stu;if(head=NULL)head=p0;p0-next=NULL;else while(p0-nump1-num),