语言课件第6章指针_第1页
语言课件第6章指针_第2页
语言课件第6章指针_第3页
语言课件第6章指针_第4页
语言课件第6章指针_第5页
已阅读5页,还剩56页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第六章指针6.1指针定义与使用6.2指针与函数6.3指针与数组6.4指针与字符串6.5指针数组与多级指针6.6指针与动态内存分配指针类型是C语言的一种特殊数据类型。正确而灵活地应用指针,可以有效地表示复杂的数据类型、有效地处理字符串和数组,动态地分配内存、处理内存地址,实现主调函数和被调函数之间共享变量等。6.1指针定义与使用6.1.1指针的引出C语言中的指针是一种数据类型,指针类型和int,float等数据类型没什么大区别,需要特别关注的是指针这种数据类型所存储的数据的属性。学习指针应该充分地理解变量名、变量的值、变量的地址这三个概念的含义,理解三者之间的关系。6.1指针定义与使用6.1.1指针的引出1.变量在内存中的存储在存取数据时,变量的地址是第一个存储单元(字节)的地址,系统根据变量的类型确定存取的内存单元数。计算机内存是由一片连续的存储单元组成,操作系统给每个内存单元一个编号,这个编号称为内存单元的地址。:0012FF7C0012FF7B0012FF7A0012FF790012FF780012FF770012FF76charc=‘W’;intx=123;W123cx6.1指针定义与使用6.1.1指针的引出2.指针的引出【问题1】利用函数实现三个数按从小到大的顺序输出。分析:3个数排序最多需要进行3次比较和交换1,2,32,1,33,1,23,2,10次交换1次交换2次交换3次交换解题方法:编写swap函数实现数据的交换,通过在main函数中3次调用swap函数来实现3个数排序#include<stdio.h>intswap(inta,intb){inttemp;temp=a;a=b;b=temp;

return;

}voidmain(){intx1,x2,x3;

scanf("%d%d%d",&x1,&x2,&x3);

if(x1>x2)swap(x1,x2);if(x1>x3)swap(x1,x3);if(x2>x3)swap(x2,x3);printf("%d,%d,%d",x1,x2,x3);}【问题1】参考程序(未使用指针变量)

程序存在的问题程序运行后,数据并没有排序,因为swap函数中的参数a和b与main函数中的变量x1,x2,x3存储在不同的内存空间。swap函数中a、b的交换并不能使main函数中的x1,x2,x3进行交换。解决方法:如果main函数传递给swap函数的不是数据本身,而是存放数据的地址,那么就可以对main中的数据进行交换了。6.1指针定义与使用C语言系统定义了称为指针的数据类型,专门用于存放其他数据类型的变量的地址。0012FF7C变量的“直接访问”:通过变量名访问该内存单元值的方法。变量的“间接访问”:通过指针变量访问某内存单元值的方法。变量的地址就是变量的指针指针变量:存放其他变量或函数的地址的变量。6.1指针定义与使用6.1.2指针变量的定义指针变量的定义形式:类型标识符

*指针变量名;

说明:①*表示这是定义一个指针变量。②变量名即为定义的指针变量名。③类型标识符表示本指针变量所指向的变量的数据类型,也称为指针变量的基类型。注意:

一个指针变量只能指向同类型的变量。例:int*p1;double*p2;

float*p3;char*p4;//p1是一个指向整型变量的指针变量6.1指针定义与使用6.1.3指针变量的使用1.指针变量的赋值⑴通过地址运算“&”赋值p15x0012FF800012FF780012FF78例:intx=15,*p;p=&x;⑵指针变量的初始化定义一个指针变量时给指针变量赋初值例:intx=15,*p=&x;6.1指针定义与使用1.指针变量的赋值⑶通过其它指针变量赋值把一个指针变量的值赋给另一个指针变量,这样两个指针变量均指向同一个地址例:intx=15,*p1=&x,*p2;

p2=p1;0012FF78p115x0012FF800012FF78p20012FF840012FF78注意:当把一个指针变量的地址值赋给另一个指针变量时,赋值号两边指针变量所指的数据类型必须相同。intx,*pi=&x;float*pf;pf=pi;将整型指针变量的地址值赋给指向float型的指针变量是错误的6.1指针定义与使用1.指针变量的赋值⑷用NULL给指针变量赋空值NULL是在stdio.h头文件中定义的预定义标识符,在C语言中当指针值为NULL时,指针不指向任何有效数据,因此在程序中为了防止错误地使用指针来存取数据,常在指针未使用之前先赋初值为NULL。例:intx=15,*p;p=NULL;注:NULL可以赋值给指向任何类型的指针变量。6.1指针定义与使用2.指针运算符指针运算符“*”是单目运算符,运算对象只能是指针变量或地址,可以用指针运算符来存取相应的存储单元中的数据。例:intx,*p;p=&x;

*p=6;//定义时,*号表示该变量是指针变量//对指针变量赋值,令p指向变量x//使用时,*p表示该指针变量所指向的变量即:*p=6;与x=6;等价scanf(“%d”,p);和scanf(“%d”,&x);等价注:指针运算与取地址运算互为逆运算inta,*p;p=&a;

*&a*(&a)*pa&*p&(*p)&ap6.1指针定义与使用【例6.1】由键盘输入一个正整数,求出其最高位数字。#include<stdio.h>voidmain(){inti,*p;

p=&i;//指针变量指向变量iprintf("请输入一个正整数:");scanf("%d",p);//等价于scanf("%d",&i);while(*p>=10)//用循环求出该正整数的最高位数字

*p=*p/10;

printf("最高位数字是:%d\n",*p);}分析:若输入258,则258/100=2;若输入3486,则3486/1000=3;由于输入的正整数可以是任意位数,每次整除的数不一样,所以采用另一种方法,258/10=25,25/10=2,即对输入的正整数整除10,当结果大于等于10时重复进行整除10的操作。6.1指针定义与使用2abcd5补充:指针运算与自加自减运算

inta=2,b=5,c,d,*p;p的值不变,*p的值加1变为3(2)c=*p++;先将*p的值赋给c,(即c的值为3),指针变量p的值加1(即p指向下一个存储区,指向b)(3)d=*++p;先将指针变量p的值加1(即p指向变量c),再将*p的值赋给d,(即d的值为3)p0012FF80

0012FF70

0012FF70(1)p=&a;(*p)++;

a++;

0012FF7433

0012FF783d=*(++p);{++p;d=*p;}c=*(p++);{c=*p;p++;}6.2.1指针作为函数参数例:用函数实现交换2个变量的值#include<stdio.h>voidswap(intx,inty){inttemp;temp=x;x=y;y=temp;}voidmain(){intx1,x2;scanf(“%d%d”,&x1,&x2);

swap(x1,x2);

printf(“x1=%d,x2=%d\n”,x1,x2);}x1x2xytemp5说明:该程序不能实现x1和x2的交换,因为实参x1,x2对形参x,y是“值传递”,x和y的变化不会影响x1和x2,所以输出为:x1=5,x2=99mainswap559956.2指针与函数6.2指针与函数6.2.1指针作为函数参数#include<stdio.h>voidswap(int*p,int*q){inttemp;

temp=*p;*p=*q;*q=temp;}voidmain(){intx1,x2;scanf(“%d%d”,&x1,&x2);

swap(&x1,&x2);

printf(“x1=%d,x2=%d\n”,x1,x2);}x1x2pqtemp5说明:该方法是交换p和q所指向的变量的值,即交换main函数中x1和x2的值,所以输出为:x1=9,x2=5&x2mainswap5&x1995【例6.2】编写一个函数实现main函数中两个变量的值的交换。6.2指针与函数例:求某班成绩的平均分,最高分和最低分分析:编写main函数和一个求平均分、最高分和最低分的函数func平均分由函数的返回值带回最高分和最低分通过应用指针变量作形参把值带回主函数将main函数中的变量的地址传给func函数的形参,就实现了func函数的形参指向了main函数中的变量在func函数中通过形参指针变量可以改变main中变量的值6.2指针与函数floatfunc(intn,

float*max,float*min){inti;floats,sum=0,aver;for(i=1;i<=n;i++){printf("inputs:");scanf("%f",&s);

if(s>*max)*max=s;if(s<*min)*min=s;

sum=sum+s;}

aver=sum/n;

return(aver);}voidmain(){intn;floatx=0,y=100,aver1;printf("inputn:");scanf("%d",&n);aver1=func(n,&x,&y);

printf("ave=%6.2f,",aver1);printf("max=%6.2f,",x);printf("min=%6.2f\n",y);}例:参考程序6.2指针与函数

程序执行过程演示maxminnfunc&x&y82voidmain(){intn;floatx=0,y=100,aver1;:scanf("%d",&n);aver1=func(n,&x,&y);

:}0100mainaver1xyn假设输入n为333floatfunc(intn,

float*max,…){inti;floats,sum=0,aver;for(i=1;i<=n;i++){printf("inputs:");scanf("%f",&s);

if(s>*max)*max=s;if(s<*min)*min=s;

sum=sum+s;}

aver=sum/n;return(aver);

}averssum0956682828217795243668181输入3个成绩:82,95,666.2指针与函数6.2.2函数返回指针函数的返回值可以是一个指针类型的数据(即地址)返回指针的函数定义格式:类型标识符

*函数名(形参列表){函数体语句;}

说明:在函数名前加*

,表明这是一个指针型函数,函数的返回值是一个指针(即函数返回一个地址)例:int*fun(inta,intb){函数体;}【例6.3】利用指针函数求两个数中的最大值。#include<stdio.h>int*max(int,int);int*maxp(int*,int*);voidmain(){intx,y,*p;scanf("%d%d",&x,&y);

p=max(x,y);printf("\nmax=%d",*p);

p=maxp(&x,&y);printf("\nmaxp=%d",*p);}int*max(inta,intb){if(a>b)return(&a);elsereturn(&b);}int*maxp(int*a,int*b){return*a>*b?a:b;}xymainpmaxab5959&b注意:在max调用结束后b的存储空间被释放,用p指向b可能会出现问题,在实际编程中应尽量避免这种情况。xymainpmaxpab59&x&y&y6.3.1一维数组与指针1.一维数组及元素的地址表示

inta[5]={1,2,3,4,5};

数组的首地址用数组名表示

元素地址*aa[0]&a[0]a*(a+1)a[1]&a[1]

a+1*(a+2)a[2]&a[2]

a+2*(a+3)a[3]&a[3]

a+3*(a+4)a[4]&a[4]

a+46.3指针与数组2.定义一个指向一维数组元素的指针变量

inta[5]={1,2,3,4,5};int*p;p=&a[0];p=a;int*p=&a[0];int*p=a;//把元素a[0]的地址赋给指针变量p//数组名代表数组的首地址,p指向元素a[0]对指针变量进行初始化6.3.1一维数组与指针3.通过指针引用数组元素例:int*p,a[5]={1,2,3,4,5};

p=a;*p=8;p=p+1;*p=9;12345pa[0]a[1]a[2]a[3]a[4]89C语言规定若p指向数组中的一个元素,则p+1指向下一个数组元素若p=a,或p=&a[0];则p+i和a+i是元素a[i]的地址,而*(p+i)和*(a+i)就是数组元素a[i]数组元素的访问方法下标法:数组名[下标]指针法:*(数组名+下标)或*指针变量

for(p=a;p<(a+5);p++)printf(“%d”,*p);for(i=0;i<5;i++)printf(“%d”,*(a+i));6.3.1一维数组与指针例:将数组a中全部元素加1,再输出a#include<stdio.h>voidmain(){inta[5]={1,3,5,7,9},*p,j;

for(

p=a;p<a+5;p++

)printf(“%3d”,*p);printf(“\n”);for(j=0;j<5;j++)a[j]=a[j]+1;for(j=0;j<5;j++)

printf(“%3d”,

*(p+j)

);printf(“\n”);}

p=a;13579aa+1a+2a+3a+4246810p可以用p++,但不能用a++因为a代表数组的起始地址它是地址常量,不能改变,而p是一个指针变量使用指针变量要注意它的当前值4.指向数组的指针变量作函数参数例:编写函数实现数组元素逆序①实参和形参都用数组名#include<stdio.h>voidinv1(int

x[]

,intn){inttemp,i,j,

m=(n-1)/2;

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

{

j=n-1-i;

temp=x[i];x[i]=x[j];x[j]=temp;}}voidmain(){inti,a[6]={1,3,4,6,7,9};

inv1(a,6);

for(i=0;i<6;i++)printf(“%3d”,a[i]);printf(“\n”);}a[0]a[1]a[2]a[3]a[4]a[5]x[0]x[1]x[2]x[3]x[4]x[5]134679976431maininv16.3.1一维数组与指针例②实参用数组名,形参用指针变量#include<stdio.h>voidinv2(int

*x,intn){inttemp,m=(n-1)/2;int

*p,*i,*j;

j=x+n-1;p=x+m;for(i=x;

i<=p;

i++,j--

){temp=*i;*i=*j;*j=temp;}}voidmain(){inti,a[6]={1,3,4,6,7,9};

inv2(a,6);

for(i=0;i<6;i++)printf(“%3d”,a[i]);printf(“\n”);}134679a[0]a[1]a[2]a[3]a[4]a[5]axai6na+5ja+2pinv29173642mtemp1a+1a+4a+2a+334a+3a+26.3.1一维数组与指针例

④实参和形参都用指针变量#include<stdio.h>voidinv4(int*x,intn);voidmain(){int

*p,a[6]={1,3,4,6,7,9};

p=a;

inv4(p,6);

for(

p=a;p<a+6;p++

)

printf(“%3d”,

*p

);printf(“\n”);}voidinv4(int

*x

,intn){inttemp,m=(n-1)/2;int*p,*i,*j;j=x+n-1;p=x+m;for(i=x;i<=p;i++,j--){temp=*i;*i=*j;*j=temp;}}例③实参用指针变量,形参用数组名#include<stdio.h>voidinv3(intx[],intn);voidmain(){int

*p,a[6]={1,3,4,6,7,9};

p=a;

inv3(p,6);

for(p=a;p<a+6;p++)printf(“%3d”,*p);printf(“\n”);}voidinv3(int

x[],intn){inttemp,i,j,m=(n-1)/2;for(i=0;i<=m;i++){j=n-1-i;temp=x[i];x[i]=x[j];x[j]=temp;}}实参形参1数组名数组名2数组名指针变量3指针变量数组名4指针变量指针变量小结:如果有一个实参数组,想在函数中改变此数组的元素的值,实参与形参的对应关系有四种6.3.1一维数组与指针6.3指针与数组6.3.2二维数组与指针1.二维数组的地址关系a[0]a[1]a[2]a[0][0]a[0][1]a[0][2]a[0][3]a[1][0]a[1][1]a[1][2]a[1][3]a[2][0]a[2][1]a[2][2]a[2][3]inta[3][4];可以把二维数组a理解成一个一维数组,它有3个元素:a[0],a[1],a[2],而a[0],a[1],a[2]又是一个一维数组,包含4个元素,如a[0]有4个元素:a[0][0],a[0][1],a[0][2],a[0][3]一维数组a一维数组a[0]

a[0]

a[1]

a[2]二维数组名a表示二维数组的首地址,

也是第0行的首地址,a

&a[0]

a,&a[0]a+1,&a[1]a+2,&a[2]a+1代表第1行的首地址,a+1

&a[1]a+2代表第2行的首地址,a+2

&a[2]a[2]a[1]a[0]元素&a[2]&a[1]

&a[0]地址a+2a+1a地址inta[3];1.二维数组的地址关系6.3.2二维数组与指针a[0]a[1]a[2]a[0][0]a[0][1]a[0][2]a[0][3]a[1][0]a[1][1]a[1][2]a[1][3]a[2][0]a[2][1]a[2][2]a[2][3]a+2&a[2]a+1&a[1]a&a[0]行地址a[0]&a[0][0]a[0]+1&a[0][1]a[0]+2&a[0][2]a[0]+3&a[0][3]a[2]&a[2][0]a[2]+1&a[2][1]a[2]+2&a[2][2]a[2]+3&a[2][3]列地址a[0],a[1],a[2]是一维数组名,它们就代表了一维数组的首地址,

因此a[0]代表了第0行第0列元素的地址,即a[0]

&a[0][0]

1.二维数组的地址关系6.3.2二维数组与指针6.3.2二维数组与指针a[0][0]a[0][1]a[0][2]a[0][3]a[1][0]a[1][1]a[1][2]a[1][3]a[2][0]a[2][1]a[2][2]a[2][3]a,&a[0]a+1,&a[1]a+2,&a[2]a[0]&a[0][0]*(a+2)+3a[2]+3&a[2][3]因a

&a[0],所以*a

*(&a[0])a[0]

&a[0][0]*a表示元素a[0][0]的地址*a*a+1表示元素a[0][1]的地址*(a+1)表示元素a[1][0]的地址*(a+2)+3表示元素a[2][3]的地址*(a+1)a[1]&a[1][0]*a+1a[0]+1&a[0][1]即:*a

a[0]

&a[0][0]思考:*a,*a+1,*(a+1),*(a+2)+3表示什么?*(a+1)+2a[1]+2&a[1][2]小结:二维数组的地址分为行地址和列地址二维数组名a为行地址,代表二维数组的首地址,

即:第0行的地址为a

&a[0]第1行的地址为a+1

&a[1]第2行的地址为a+2

&a[2]二维数组的列地址即元素的地址元素a[0][0]a[0][1]a[1][0]a[1][2]a[2][3]地址&a[0][0]&a[0][1]&a[1][0]&a[1][2]&a[2][3]地址a[0]a[0]+1a[1]a[1]+2a[2]+3地址*a*a+1*(a+1)*(a+1)+2*(a+2)+3元素*a[0]*(a[0]+1)*a[1]*(a[1]+2)*(a[2]+3)元素**a*(*a+1)*(*(a+1))*(*(a+1)+2)*(*(a+2)+3)6.3.2二维数组与指针6.3.2二维数组与指针例:用指针变量输出二维数组中的元素#include<stdio.h>voidmain(){inta[3][4]={{1,3,5,7},{2,4,6,8},{9,10,11,12}};

int*p;for(p=a[0];

p<a[0]+12;p++){if((p-a[0])%4==0

)printf(“\n”);printf(“%4d”,*p);}}思考:p=a;p=&a[0][0];p=*a;p=*a[0];对对错错6.3.2二维数组与指针定义格式:类型标识符(*指针变量名)[长度];inta[3][4];p指向了数组a的第0行a[0]a[1]a[2]这不是一个真正存在的数组元素,只是一种地址表示方法,a实际指向了一行整型变量,它包含4个元素aa[0][0]a[0][1]a[0][2]a[0][3]int(*p)[4];p=a;2.行指针变量注意(*指针变量名)两边的小括号不可少长度为二维数组的列数6.3.2二维数组与指针【例6.8】利用行指针输出二维数组中的元素#include<stdio.h>voidmain(){inta[3][4]={{1,3,5,7},{2,4,6,8},{9,10,11,12}};

int(*p)[4],i,j;p=a;for(i=0;i<3;i++){for(j=0;j<4;j++)printf(“%2d”,*(*(p+i)+j));printf(“\n”);}}6.4指针与字符串C语言中字符串是存放在字符数组中,并以‘\0’作为结束标志。例:字符串的输出方式#include<stdio.h>voidmain(){charstr[10]="Hello";

inti;printf("\n方式1:");printf("%s",str);printf("\n方式2:");

puts(str);printf(“方式3:");

for(i=0;str[i]!='\0';i++) printf("%c",str[i]);}//字符串初始化Hello\0//用格式字符s输出字符串//用字符串输出函数输出字符串//用循环逐个输出每个字符6.4指针与字符串指向字符串的指针实际上就是指向一个字符数组的指针。【例6.9】利用指针的不同方式,输出字符串。#include<stdio.h>voidmain(){charstr[]="Hello",*p=str;inti;printf("\n1:");printf("%s",p);printf("\n2:");puts(p);printf("3:");for(i=0;*(p+i)!='\0';i++) printf("%c",*(p+i));printf("\n4:");for(i=0;*p!='\0';i++,p++) printf("%c",*p);}定义字符指针变量p,并进行初始化,令p指向字符数组str注意这两种输出方式的区别字符数组与字符指针变量的区别1.存储方式不同字符数组——存放的是字符串中的字符和‘\0’字符指针变量——存放的是字符串的首地址char

s[8]

=“abcd”,*p

=“abcd”;6.4指针与字符串abcd\0sabcd\0p0x0042201c注意:C语言中字符串常量是按照字符数组来处理的。对程序中的字符串常量,系统会自动在内存中创建一个字符数组,将字符串的内容及‘\0’保存在字符数组中。6.4指针与字符串char*p1,*p2=“abcd”;p1=“China”;

chara[12],b[]=“good”;a[12]=“China”;a=“China”;2.赋值方式不同字符指针既可以初始化,也可以赋值。错字符数组可以初始化,但不能赋值,赋值操作需借助strcpy()函数实现。应该用:strcpy(a,“China”);//可以将字符串常量直接赋给字符指针变量6.4指针与字符串3.字符数组具有一片连续的存储空间,数组名即为该存储空间的首地址;字符指针变量的存储单元是用来存放字符串首地址的,但是在对字符指针变量赋值之前,该指针变量的值是不确定的,

此时不应该对字符指针变量进行操作,否则可能出现异常。chars1[5],s2[10];scanf(“%s”,s1);strcpy(s2,“Hello”);char*p1,*p2;scanf(“%s”,p1);strcpy(p2,“Hello”);这种用法完全正确这种用法危险,因为p1,p2未赋值,它们都是随机值,无法确定它们指向内存中的具体位置,执行操作后可能导致异常。6.4指针与字符串【例6.10】利用字符指针编写程序实现strcat的功能。分析:定义两个字符数组s1和s2,接受用户输入的字符串;目标是实现将s2连接到s1的后面;定义两个字符指针变量p1和p2,分别指向s1和s2;想办法让p1指向字符串s1的末尾,即指向s1最后的结束符’\0’;利用循环逐一将s2中的字符复制到s1的后面。abcd\0s1efg\0s2p1p2p1efg\0p1p26.4指针与字符串【例6.10】参考程序#include<stdio.h>voidmain(){chars1[200],s2[100],*p1,*p2;p1=s1; p2=s2;//p1和p2分别指向s1和s2

printf("Inputfirststring:"); gets(s1);printf("Inputsecondstring:"); gets(s2);while(*p1!=‘\0’) //将p1移动到s1的末尾p1++;while(*p1=*p2)//将s2的内容接到s1后面{p1++;p2++;}printf("Catenatedstring:%s\n",s1);//输出连接后的内容}while(*p1++=*p2++);//注意:循环体为空语句6.5指针数组与多级指针6.5.1指针数组的定义和引用指针数组也是一种数组,只是它的数组元素都是指针变量。指针数组的定义格式:类型标识符

*数组名[数组长度];p是一个指针数组,它有3个元素,每个元素是一个指针变量int*p[3];intx,y,a[4];p[0]=&x;p[1]=&y;p[2]=a;xya[0]a[1]a[2]a[3]数组ap[0]p[1]p[2]指针数组p6.5.1指针数组的定义和引用指针数组用得最多的是“字符型指针数组”,利用字符指针数组可以指向多个长度不等的字符串,使字符串处理起来更方便、灵活,节省内存空间。char*p[4]={“Pascal”,“VC”,“Basic”,“Java”};p[0]p[1]p[2]p[3]Pascal\0定义字符指针数组,它包含4个元素,其中每个元素是一个字符指针,可以指向一个字符串VC\0Basic\0Java\06.5.1指针数组的定义和引用例:编程将书名按字母顺序排序后输出方法1:用二维字符数组编程实现Pascal\0VC\0Basic\0Java\0Basic\0Java\0Pascal\0VC\0排序思考:①二维字符数组定义成多大合适?②采用什么方法进行排序?③字符串怎样比较和交换?①第一维的长度取决于有几本书第二维的长度由最长的书名决定②可使用冒泡排序或选择排序③字符串的比较和交换应使用相应的字符串函数//输出排序前的书名#include<stdio.h>#include<string.h>#defineMAXLEN7#defineN4voidmain(){inti,j;chartemp[MAXLEN];

charname[N][MAXLEN]={"Pascal","VC","Basic","Java"};printf("beforesorted:\n");for(i=0;i<N;i++)puts(name[i]);

for(i=0;i<N-1;i++)for(j=i+1;j<N;j++)

if(strcmp(name[i],name[j])>0) {strcpy(temp,name[i]); strcpy(name[i],name[j]); strcpy(name[j],temp); }printf("\naftersorted:\n");for(i=0;i<N;i++)puts(name[i]);}//书名的最大长度+1//书的数量选择排序//输出排序后的书名方法1:用二维字符数组编程实现的参考程序6.5.1指针数组的定义和引用例:编程将书名按字母顺序排序后输出方法2:用指针数组编程实现p[0]p[1]p[2]p[3]p[0]p[1]p[2]p[3]注意:排序时是交换指针变量的指向排序后Pascal\0VC\0Basic\0Java\0Pascal\0VC\0Basic\0Java\0#include<stdio.h>#include<string.h>#defineN4voidmain(){inti,j;char*temp=NULL;char*p[N]={"Pascal","VC","Basic","Java"};printf("\nBeforesorted:\n");for(i=0;i<N;i++)puts(p[i]);for(i=0;i<N-1;i++)for(j=i+1;j<N;j++) if(strcmp(p[i],p[j])>0)

{temp=p[i];p[i]=p[j];p[j]=temp;}printf("\nAftersorted:\n");for(i=0;i<N;i++)puts(p[i]);}交换的是字符串的起始地址方法2:用指针数组编程实现的参考程序6.5指针数组与多级指针6.5.2多级指针如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为二级的指针变量,或指向指针的指针。二级指针的定义形式:类型标识符**指针变量名;intx=36,*q,**t;q=&x;t=&q;360x0012ff7cx思考:q=45;*q=45;*t=56;**t=56;对错,因为q是指针变量,赋值号右侧必须是地址错,因为t是二级指针变量,*t等价于q对0x0012ff78q0x0012ff74t0x0012ff7c0x0012ff78【例6.13】使用二级指针处理指针数组。6.5.2多级指针#include<stdio.h>voidmain(){char*name[4]={"Pascal","VC","Basic","Java"};char**p;//定义p为二级指针变量

inti;for(i=0;i<4;i++){p=name+i;//把第i行的指针赋值给pprintf("%s\n",*p);}}name[3]name[2]name[1]name[0]Pascal\0VC\0Basic\0Java\0pname+0name+1另一种输出方式:for(p=name;p<name+4;p++)puts(*p);6.5.2多级指针思考:以下赋值操作是否正确?inta[3][4];int**p;p=a;inta[3][4];int(*q)[4];q=a;//赋值操作是错的错误原因:虽然a是二级地址,p是二级指针变量,但它们的含义不同,a指向的是一行数据,它包含4个元素,而p指向的是一个整型指针变量。//赋值操作是正确的注意:q是一个行指针变量,虽然定义时只用了一个‘*’,但q实际上是一个二级指针。6.6指针与动态内存分配动态内存分配(DynamicMemoryAllocation)在程序运行时为程序分配内存的一种方法什么时候需要使用动态内存分配?例:计算某班英语成绩的平均分,要求保存每个学生的成绩,学生人数由键盘输入。inta[60];intn,i;scanf(“%d”,&n);for(i=0;i<n;i++)scanf(“%d”,&a[i]);以前的方法是将数组定义的足够大!如果输入的n较小(15),那么数组有多数以上的存储空间被浪费了我们希望在输入n后,根据实际的人数定义一个动态数组,这样不会浪费存储空间6.6.1void类型指针void是一种特殊的类型,表示“无类型”。注意,C语言中的变量不能定义为void类型,但允许定义void类型的指针变量,称为无类型指针变量,初始值通常设为NULL。void类型指针的使用1.一些标准函数的返回值是无类型指针,这种类型的指针不能直接赋给其他类型的指针变量,在使用时需要根据情况将无类型指针强制转换为其他类型的指针,2.函数的形式参数也可以定义为无类型指针,但在调用该函数时,不需要对实际参数进行强制转换。6.6.2动态内存分配和释放函数使用动态内存分配函数必须使用#include<stdlib.h>文件包含命令常用的动态内存分配函数

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论