首页计算机计算机软件C语言程序设计 08 第7章 指针.pptx

08 第7章 指针.pptx

页数:108页文件大小:467.0 KB来源: C语言程序设计ppt课件

本课件从地址与指针的概念入手,说明指针变量的定义、引用与作函数参数的用法;随后讲解指向数组元素的指针与指针运算、指向字符串的指针及其与字符数组的区别,并介绍指向函数的指针、返回指针值的函数、指针数组与指向指针的指针。

第7章 指针,讲解的概念。、掌握指针变量的定义、应用及作为参数的用法、掌握指向数组的指针与等内容
教学内容1.指针的定义2.指针,讲解的操作3.针变量的初始化1.指针作
7.1 地址和指针的概念,列举内存地址、数据的存取是在地址所标识、存单元的地址与内等内容
查看本课件的文字版(共 108 页,供检索与复制)

第1页:第7章 指针

第7章 指针

的概念。

2.掌握指针变量的定义、应用及作为参数的用法。

3.掌握指向数组的指针与指向数组的指针变量的概念、定义和应用。

4.掌握指向字符串的指针的定义和应用。

5.理解指向函数的指针的定义和用法。

6.了解返回指针值的函数的定义和应用,了解它与指向函数的指针变量的区别。

7.了解指针数组的定义和应用,掌握指针的指针的定义和应用,了解它指针数组与指向数组的指针变量的区别。

第2页:教学内容1.指针的定义2.指针

教学内容1.指针的定义2.指针

的操作3.针变量的初始化1.指针作为参数2.返回指针的函数3.函数指针4.函数体内的指针1.存储管理函数2.函数的使用1.一维数组和指针2.多维数组和指针3.用指针处理串4.指针数组

第3页:7.1 地址和指针的概念

7.1 地址和指针的概念

计算机把内存的所有单元顺序排列,每个单元(字节)有一个顺序编号,称单元的地址或称为指针。

  • 内存地址(指针)
  • 数据的存取是在地址所标识的存储单元中进行的。
  • 内存单元的地址与内存单元中的数据是两个完全不同的概念。
  • 变量地址系统分配给变量所需的内存单元的起始地址。

第4页:变量是对程序中数据存储空间的抽象

变量是对程序中数据存储空间的抽象

任何变量在其存在期间总有一个固定的地址。

变量地址可作为数据来操作。

7.1地址和指针的概念内存…………程序中:shorti;floatk;......每个字节有一个编号编译或调用时分配内存ki地址0000……20002001200220032004200520062007……

  • 变量建立后意味着为其指定了一个存储位置,分配内存。
  • 变量值的存取通过变量的地址进行。

第5页:………二

………二

指针变量专门存放变量地址的变量7.1地址和指针的概念变量p变量p的内容指针变量地址20002001…2013201420152016…变量i的内容短整型变量i变量i的地址指针20002000i内存

  • 指针与指针变量
  • 指针一个变量的地址(VC中占四个字节)

第6页:变量值的存取方式

变量值的存取方式

直接存取直接按变量地址存取变量值的方式。

在程序中对变量进行存取操作,实际上是对某个地址的存储单元进行操作,变量和地址的联系由系统完成,用户无须知道变量的具体地址。

例

scanf("%d",&i)的执行过程是这样的:找到变量i的起始地址2000;然后将键盘输入的值10送到内存单元2000和2001中。printf("%d", i)的执行过程与scanf()很相似:首先找到变量i的起始地址2000,然后从2000和2001中取出其值,最后将它输出。

第7页:间接存取指针变量

间接存取指针变量

也是变量,也有自己的存储地址,设指针变量p中放的是变量i的地址,这时要访问i,可先找到p的地址,从中取出i的地址,再去访问i的内容,这种通过变量p间接得到变量i的地址,然后再存取i的值的方式称“间接存取”。

指针机制是一种间接访问其他对象的手段,目的是为了更灵活方便地对数据进行操作。

7.1地址和指针的概念指针变量p:一般变量i:2000(i的地址-指针)5(变量i的值)指向地址存入P中2000:

第8页:7.1 地址和指针的概念

7.1 地址和指针的概念

指针变量的值只能是其他对象的地址,指针变量赋值就是把某个变量的地址赋给指针(这个过程称指针指向变量),因此,在程序运行的不同时刻,指针可以指向不同的变量。

指针的应用使程序代码更简洁、更高效。但使用指针会降低程序的可读性,使用不当,可能造成严重的错误甚至引起系统崩溃。

  • C语言编译器对指针的检查较弱,查错比较困难,要求编程者控制指针的有效性。
  • 从程序设计角度讲,更该注意用指针才能实现的功能和机制,如改变调用函数环境的值等。

第9页:7.2 指针的定义

7.2 指针的定义

  • 使用和运算一、指针的定义1.一般形式
  • 定义指针变量的一般形式类型名*指针变量1,*指针变量2,…

第10页:7.2 指针的定义

7.2 指针的定义

指针变量的值为某个内存单元的地址值(地址编号)。值的类型均为整型。(VC中占4个字节)

通过指针访问的对象有类型C语言规定,任何一个指针变量,只能指向具有某种特定类型的变量。定义中的类型名限定了指针变量可以关联的对象的范围。

指针变量也是变量像普通变量一样可以赋值、取值等。但要满足类型约束。7.2指针的定义、使用和运算

第11页:int*p1

int*p1

//定义整型指针变量p1,用于指向整型变量。

float*p2;//定义浮点指针变量p2,用于指向实型变量。

char*s;//定义指向字符的指针变量s,也叫字符指针。

int*p, n; a[10];//指针变量可和其他变量一起定义。

'*'不可省略,否则变成普通变量的定义,如:int*p1,*p2;与int*p1,p2;//p2是普通变量

  • 注意
  • 指针变量名是p1、p2,不是*p1、*p2
  • 指针变量只能指向定义时所规定类型的变量
  • 指针变量定义后,值不确定,用前须先赋值。7.2指针的定义、使用和运算

第12页:空指针

空指针

  • (NULL)
  • 是特殊的指针,它的值是0。C语言中用符号常量NULL(在stdio.h中定义)表示
  • 系统保证NULL不会是任何变量的地址
  • 对任何指针类型赋值都是合法的
  • 一个指针变量具有空指针值(NULL),表示当前它没有指向任何有意义的值
  • 用p=NULL(比p=0)的形式为好
  • p=NULL与未对p赋值不同
  • 避免指针变量的非法引用,常作为状态比较。7.2指针的定义、使用和运算

第13页:void指针

void指针

(void*)类型的指针叫通用指针,它可以指向任何变量,C语言允许直接把任何变量的地址作为指针赋给通用指针。

使用通用指针需要进行类型强制转换。

如:(void*)gp所指空间的数据是整型数据,p是整型指针,用下式转换:p=(int*)gp;7.2指针的定义、使用和运算

  • 通用指针不能做间接运算。因为编译系统无法确定它所指的变量的类型。

第14页:指针转换实际上没有带来指针值的任何变化

指针转换实际上没有带来指针值的任何变化

通用指针对被指的内容不提供任何有意义的类型信息,所以不能通过这种指针间接使用被指的内容。

通用指针的唯一用途就是提供一个指针值。可看成内存中每个字节的原始地址,无具体类型。7.2指针的定义、使用和运算

  • 一个指针类型代表一种观点。如通过整型指针的间接使用,永远把被指的东西看成整型。
  • 指针转换是一种观点转换,转换成哪种类型的指针,就用哪种类型去解释被指的变量。

第15页:指针的操作

指针的操作

&放在变量名前面,取得该变量的地址;例如:若有定义intx,*p;把p=&x;把x的地址赋予p,即p指向了变量x。

scanf("%d", &x)
scanf("%d", p)7.2指针的定义、使用和运算
  • 指针赋值一个指针变量可以通过不同的方法获得一个确定的地址值,从而指向一个具体的对象。
  • 取地址运算(一元运算符&)和指针赋值
  • &运算符只能应用于变量和数组元素,不可用于表达式、常量或register变量。
  • 若p=&x;则

第16页:指针变量赋值通过

指针变量赋值通过

指针变量赋值,把一个指针变量的地址值赋给另一个指针变量,使这两个指针变量指向同一地址。

赋值号两边的指针变量的基类型必须一样。

例如:p和q都是整型指针,p指向整型变量,则执行q=p以后,q也指向变量x。

通过标准函数获得地址值可以通过调用库函数malloc和calloc在内存中开辟动态存储单元,并把单元地址赋值给指针变量。7.2指针的定义、使用和运算

第17页:间接运算

间接运算

将一元运算符"*"放在指针变量名前(也可是地址前),效果是由一个指针得到被它指向的变量,可以像使用普通变量一样使用该表达式。

如:intm,*p,*q,n;p=&n;q=&m;

则:*q相当于n,*q相当于m。

间接使用:m=*p+*q作用与m=n+m相同。

间接赋值:*p=5,作用与n=5相同。

显然:*p出现在赋值号左边,代表指针所指的存储单元,*p出现在赋值号右边,代表指针所指的存储单元的内容。

7.2指针的定义、使用和运算

  • (一元运算符"*")

第18页:例1设int*p,k=0

例1设int*p,k=0

p=&k;分析下面几行程序执行的过程和结果。

*p=100;//把整数100赋给k变量*p =*p+1;//取p所指单元的值,加1后//赋给p所指的存储单元k,//k变为101*p+=1;

//等价于k+=1;k变为102++*p;

//等价于++k,k变为103(*p)++;

//等价于(k)++,k变为1047.2指针的定义、使用和运算k0p→

第19页:移动指针

移动指针

将移动指针就是对指针变量加上或减去一个整数,或通过赋值运算使指针变量指向相邻的存储单元。因此,只有当指针指向一串连续的存储单元时,指针移动才有意义。

对指针进行+、-运算中,数字“1”不再代表十进制数“1”,而是1个存储单元长度,如果整型变量存储单元长度是4个字节,整型指针移动1个存储单元就是移动4个字节,双精度型指针加1就是移动8个字节,依此类推。

7.2指针的定义、使用和运算

第20页:程序中移动指针时

程序中移动指针时

不论指针的基类型是什么,只需简单地加、减一个数而不必去管它的具体长度,系统将会根据指针的基类型自动确定位移的字节数。

最常用的移动操作就是加一(++)和减一(--)操作。它们分别代表指针向地址值增大的方向移动一个存储单元和指针向地址值减少的方向移动一个存储单元。

两个指向同一串连续单元的指针可以进行相减的运算,结果是两个指针之间元素的个数,可以通过赋值使两个指针指向同一个单元。7.2指针的定义、使用和运算

第21页:例2顺序执行下面的操作

例2顺序执行下面的操作

分析其意义和结果。

设int*p,*q,a;且p、q分别指向一片连续空间的第一个整数和最后一个整数。

++p;//p后移1个单元,指向第二个整数q--;//q前移1个单元,指向倒数第二个数。

a=*p++;//取出p所指单元内容赋给a,p后移a=q-p;//计算q和p间整型数个数将它赋给ap=q--;//将p指向q所指单元,指针q前移*p=10/2;//计算10/2的值,赋给p所指单元。

7.2指针的定义、使用和运算24……789qa:q-p538p

第22页:指针比较两个指针指向同一连续的存储单元时

指针比较两个指针指向同一连续的存储单元时

可以在关系表达式中对其进行比较,判断指针的位置关系。

如果两个指针变量的值相等,表示它们指向同一个存储单元。

另外,还可进行是否是空(NULL)指针的判断。

指针基类型对指针的相关操作有一定的约束和限制,主要有以下几方面:

  • 基类型使指针只能指向基类型定义的一类变量。(如:整型的指针只能指向整型变量)
  • 限制引用满足基类型的约束。
  • 限制指针移动的跨度。7.2指针的定义、使用和运算

第23页:指针变量的初始化

指针变量的初始化

指针变量在定义时可以用任何合法的指针(地址)值进行初始化。如:inta,*p=&a,*q=NULL包含了两个指针初始化部分。

局部自动变量、寄存器变量的值不确定,要有明确的变量关联后才能使用这些变量。7.2指针的定义、使用和运算

  • 一般形式[存储类型]数据类型*指针名=初始地址值
  • 说明
  • 默认值(在定义指针变量时没有进行初始化):
  • 全局变量和局部静态变量被初始化为NULL。

第24页:初始值是赋给指针变量

初始值是赋给指针变量

变量必须已说明过,类型应一致。如:inta,*p=&a;√是正确的。而int*p=&a;inta;×是错误的。

不能用auto变量的地址去初始化static型指针。例:inti;staticint*p=&i;×是错误的。7.2指针的定义、使用和运算

  • 而不是赋给目标变量。
  • 可以用已初始化指针变量作初值。例:inti,*p=&i;int*q=p

第25页:例3用指针指向变量

例3用指针指向变量

main(){ inta,b,min,*pa,*pb,*pmin; pa=&a; pb=&b; pmin=&min; scanf("%d%d",pa,pb); printf("a=%d,b=%d\n",a,b); if(*pa<*pb)*pmin=*pa; else*pmin=*pb; printf("min=%d\n",min); } 7.2指针的定义、使用和运算运行结果:23 67
  • 通过指针运算,选出较小的。
  • 注意:指针没有初始化情况下,如何开始使用。
  • a=23, b=67min=23a:pamin:pminb:pb672323

第26页:7.3 函数与指针

7.3 函数与指针

概述已知C语言中函数的一般形式为:类型名函数名([形参表])//头部{说明部分//函数体语句部}

第27页:C语言函数参数的传递机制是值传递

C语言函数参数的传递机制是值传递

函数中形参的改变并不能改变对应实参的值,把数据从被调函数返回到调用函数的唯一途径是通过return语句返回函数值,限定了函数只能返回一个数据。

在函数中使用指针,可以突破这些限制,函数定义中的各部分:参数、函数名、返回值及函数体内,都可以使用指针。

本节讨论这方面的情况。

第28页:指针作为函数参数

指针作为函数参数

函数中,通过形参操作的存储单元与实参所指的是同一单元,因此实参的值发生了改变。利用此形式,可以把两个或两个以上的数据从被调用函数中返回到调用函数。

  • 说明
  • 若形参为指针类型,调用函数时,对应实参必须是基类型相同的地址值或已有指向的指针变量。
  • 虽然实参和形参之间还是值传递,但由于传递的是地址值,所以它们指到了同一个存储单元。
  • 注意:被调用函数不能改变实参指针变量的值,但可改变实参指针变量所指的变量的值。

第29页:例4*交换两个变量值

例4*交换两个变量值

的函数voidswap(int*p,int*q){intt;//t非指针t=*p;*p=*q;*q=t;/int(*p1)[4]=a;int*p2=a[0];7.4数组和指针形参实参数组名intx[][4]数组名a指针变量int(*q)[4]数组名a数组名intx[][4]指针变量p1指针变量int(*q)[4]指针变量p1指针变量int*q指针变量p2

第62页:13*编写函数输出二维数组a中最大值及所

13*编写函数输出二维数组a中最大值及所

在的行号和列号。

分析:设a为整型数组,依题意,函数需返回多个值,从return返回最大值,行号和列号通过指针修改主程序保存行号和列号的变量值得到。

使用行指针引用二维数组元素的方法编写程序。

第63页:#defineM3

#defineM3

#defineN4intmax(p,prow,pcol)int(*p)[N],*prow,*pcol;{inti,j,mx=*(p[0]);*prow=0;*pcol=0;for(i=0;i<M;i++)for(j=0;j<N;j++)if(*(p[i]+j)>mx){mx=*(p[i]+j);*prow=i;*pcol=j;}return(mx);}7.4数组和指针

#include<stdio.h>main(){ inta[M][N]={ 1,2,3,4,5,6,7,8,9,0,1,2 } ; introw,col,mx; mx=max(a,&row,&col); printf("max=%d,",mx); printf("row=%d,",row); printf("col=%d\n",col); } 运行结果:max=9, row=2, col=0

第64页:使用指针处理字符串

使用指针处理字符串

  • 字符指针
  • 定义形式char*变量名
  • 用途
  • 经常用来指向字符数组的元素,访问字符数组里的字符内容。
  • 最常见的情况是用字符指针指向一个字符串或字符数组。

第65页:初始化方式使字符指针指向字符串如

初始化方式使字符指针指向字符串如

用赋值运算使指针指向一个字符串如:char*str;str="stringone";与第一种初始化方法完全等价。

  • char*str="Programming";含义有三点:
  • 定义一个字符指针str
  • 建立一个字符串常量
  • 确定指针初值,使它指向定义的串常量。

第66页:用字符数组指向字符串

用字符数组指向字符串

str是指针变量,可多次赋值;a是数组名,表示地址常量,不能赋值,且a的大小固定,预先分配存储单元。

类型、大小不同。str是指针,a是数组。它们的存储表示如图所示。7.4数组和指针OKstr:a:OK

  • 和用字符指针指向的字符串的区别如:char*str="OK";与chara[]="OK"
  • a的元素可重新赋值,不能通过str间接修改字符串常量的值。

第67页:例14*分析

例14*分析

下面一段程序的输出本题是一组关于++和*运算符的练习,目的是熟悉字符指针对字符串的控制操作。

main(){ chars[]="ABCDEF"; char*str=s; printf("%c",*str); printf("%c",*str++); 7.4数组和指针//取str的内容,str指向'A'运行结果:AACCEABEDEF\0FEDCBAAAstrs

第68页:printf

printf

printf("%c",(*str)++); printf("%c\n",++*str); printf("%s\n",s); } 运行结果:AACCEABEDEF7.4数组和指针ABEDEF\0FEDCBAstrsC++str运算,指向'C',再取str的内容取str的内容,然后str的内容加1,'C'修改为'D'ECD先对str的内容运算加1操作,'D'修改为'E',然后,取str的内容E取s的内容,s指向'A'AACCEABEDEF
  • ("%c",*++str)

第69页:使用字符指针处理字符串和字符数组

使用字符指针处理字符串和字符数组

字符串输入时,输入项可以是字符数组,也可以是字符指针。字符指针必须已经指向确切的、足够大的存储空间,以便输入字符能放在它所指的具体单元中。

例15*计算字符指针所指字符串的长度。分析:逐个统计串中的字符个数,直到遇到串结束符'\0'为止。7.4数组和指针

  • 字符指针用于输入输出
  • 字符串输出时,输出项可以是字符串或字符数组,也可以是指向字符串的字符指针
  • 常规字符串处理的指针实现

第70页:#include

#include

<stdio.h>intlength(char*str){intn=0;while(*str++!='\0')n++;returnn;}

main(){ char*str1="goodMorning!"; charstr2[]="goodAfternoon!",*str3=""; printf("%slen:%d\n",str1,length(str1)); printf("%slen:%d\n",str2,length(str2)); printf("str3len:%d\n",length(str3)); } 7.4数组和指针7.4数组和指针运行结果:Good Morning! len: 13Good Afternoon! len: 15str3 len: 0

第71页:例16*编写函数

例16*编写函数

实现字符串反转的操作分析:本例实现的方法是利用两个字符指针s和p,分别指向应该进行交换的两个字符,s从字符串的首字符向末字符移动,p从字符串的末字符向首字符移动,直到两个指针相遇,如果原字符串长度是奇数,结束时s=p,如果原字符串长度是偶数,结束时s>p。

如下图所示。

7.4数组和指针7.4数组和指针\0sp

第72页:#include

#include

<stdio.h>voidrevstr(char*s){char*p=s,c;while(*p)p++;//到结束符停止p--;//退回最后一个有效字符while(s<p)//用交换并移动指针{c=*s;*s++=*p;*p--=c;}}

main(){ charstr[]="goodMorning!"; revstr(str); printf("str=%s\n",str); } 7.4数组和指针7.4数组和指针运行结果:str = Good Morning!str = !gninroM dooG

第73页:例17*编写函数

例17*编写函数

实现字符串连接的操作分析:scat(char*dest,char*src);函数将src所指字符串的内容连接到dest所指字符串后面,覆盖dest串末的结束符'\0',要求dest所指字符串的空间足够容纳合并后的字符串。

7.4数组和指针

第74页:#include

#include

<stdio.h>char*scat(char*dest,char*src){char*p=dest;while(*p)p++;//移到第一串的结束符处while(*p++=*src++);//接在结束符处return(dest);}

main(){ char*str,*s2="abcde"; chars1[20]="12345"; str=scat(s1,s2); printf("2:%s\n",str); } 7.4数组和指针7.4数组和指针运行结果:1:12345, abcde2:12345abcde

第75页:例18*编写函数

例18*编写函数

实现字符串比较的操作分析:函数为scomp(char*s1,char*s2)将s1和s2进行比较:

若s1串<s2串,函数返回负数。

从两个字符串的初始位置开始,将对应位置上的字符进行比较,直到遇到对应位置上有不等的字符或其中的一个串到达了串尾,将两串当前字符的值相减,作为函数值返回。

7.4数组和指针

  • 若s1串>s2串,函数返回正数
  • 若s1串=s2串,函数返回0

第76页:charscomp

charscomp

(char*s1,char*s2){while((*s1==*s2)&&(*s1)&&(*s2)){s1++;s2++;}return(*s1-*s2);}

main(){ chars1[20]="comparestring",s2[20]; intresult; gets(s2); result=scomp(s1,s2); if(result>0)printf("%s>%s\n",s1,s2); elseif(result==0)printf("%s=%s\n",s1,s2); elseprintf("%s<%s\n",s1,s2); } 7.4数组和指针

第77页:指针数组指针本身

指针数组指针本身

也是数据,也可以作为数组的元素,如果数组中的元素均为指针类型数据,则称这个数组为指针数组。

指针数组中每一个元素都相当于一个指针变量。

一维指针数组的定义形式:类型名*数组名[数组长度];

例如,int*pa[5];

定义一个有5个整型指针为数组元素的一维数组。

用它表示另一个整型数组元素大小关系,如图。

7.4数组和指针7.4数组和指针pa&a[1]&a[4]&a[2]&a[3]&a[0]a45613367

第78页:字符指针数组表示的字符串数组

字符指针数组表示的字符串数组

第6章中介绍了用二维字符数组表示字符串数组的方法,包括它在定义时的初始化方法,现在,我们可以定义字符型指针数组并通过赋初值来构成字符串数组。

例如:char*pa[10];

pa是一个字符指针数组,类型是(char*)。

指针数组最多的用途是用来表示一组字符串,它使字符串的处理更加灵活。

例如用字符指针数组pa组织大型程序的错误信息,可将错误号与pa下标对应,方便组织错误信息的输出。

7.4数组和指针

第79页:字符指针数组的初始化

字符指针数组的初始化

*day[]定义7个元素的字符指针数组,建立7个字符串常量,对数组元素进行了初始化。

7.4数组和指针7.4数组和指针day0123456\0nuS\0noM\0euT\0deW\0uhT\0irF\0atS

  • 以下面字符指针数组为例:
  • char*day[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sta"}

第80页:字符指针数组与二维字符数组比较如

字符指针数组与二维字符数组比较如

charc1[][6]={"red","green","blue"};char*c[]={"red","green","blue"};7.4数组和指针7.4数组和指针指针数组表示的字符串c[0]c[1]c[2]连续存储可能有很多空的单元。

\0der\0neerg\0eulb分散存储靠指针联系,可能出现字符串丢失。

二维数组表示的字符串\0derc1[0]\0neergc1[1]\0eulbc1[2]

第81页:例19编写程序比较若干种高级语言的名字

例19编写程序比较若干种高级语言的名字

分析如果想避免排序过程中过多的数据交换,本例的思路应该对你会有启发。排序过程中,交换指针变量的值,这种方法比交换数组元素的值效率要高。

  • 并将它们按字典顺序排序后输出。
  • 程序*7.4数组和指针

第82页:charsort

charsort

(char*a[],intn ){char* temp ;inti, j, k ;for(i=0; i<n-1;i++){k = i;for(j=i+1; j<n; j++)if(strcmp(a[k],a[j])>0)k = j;if(k != i){temp = a[i];a[i] = a[k];a[k] = temp;}}}7.4数组和指针7.4数组和指针# include<stdio.h>

main(){ char*ln[]={ "PAS","BAS","FOR","VC","ADA" } ; inti, m ; m=sizeof(ln)/sizeof(char*); sort(ln, m) ; for( i=0; i<m; i++ )printf ("%s ",ln[i]) ; } 运行结果:ADA BASFORPAS VC

第83页:7.4 数组和指针

7.4 数组和指针

4数组和指针ln01234\0SAP\0SAB\0ROF\0CV\0ADA排序前指针数组ln01234\0SAP\0SAB\0ROF\0CV\0ADA排序后指针数组

第84页:指向指针的指针

指向指针的指针

指针变量的内容是数据地址,如果数据本身是个指针,该指针变量就是指针的指针。如:每个指针数组元素都是其他数据的地址,指向指针数组元素的指针就是指向指针的指针。

变量的定义形式char**p;

p的前面有两个*号,根据*运算符的结合性,**p相当于*(*p),根据指针变量的定义形式,*p是一个字符指针,p是指向这个指针的变量。

7.4数组和指针7.4数组和指针stringp*p

第85页:20*编写程序使用指向指针

20*编写程序使用指向指针

main(){ char*name[]={ "PAS", "BAS", "FOR", "VC", "ADA" } ; char**p; inti,m; m=sizeof(name)/sizeof(char*); p<name+m; p++)printf("%s\n",*p); } 7.4数组和指针运行结果:PASBASFORVCADAname01234\0SAP\0SAB\0ROF\0CV\0ADAp
  • 的指针打印字符串数组的字符串。

第86页:命令行参数

命令行参数

main()都使用其无参形式,实际上,main()函数可以有参数,指针数组的一个重要应用是作为main()函数的形参。main函数是由系统调用的,调用的方法是在操作系统命令状态下输入main所在的执行文件的名字(命令),也可在Windows中通过点击图标进行,但也等价于在命令状态下发出一条命令。main函数的参数跟在调用命令后,由操作系统传递给主函数,这种机制叫命令行参数。如type abc.txt命令中,abc.txt是type的参数;
  • (时间紧不讲)转下一部分以往的程序中,主函数

第87页:在VC环境

在VC环境

中,调试带有命令行参数的程序时,可以通过选择“过程”/“设置”/“调试”菜单中的“程序变量”选项,输入参数。

C语言如何看待命令行看作由空格分隔的若干字符串,每个字符串看作是一个命令行参数。

由第一个字符串(命令本身)开始从0编号。

程序执行时,每个参数被处理成字符串,按照规定方式使用它们。

C语言通过主函数的参数获取命令行参数。

  • 命令行的一般形式命令名
  • 参数1
  • 参数2
  • …
  • 参数n

第88页:主函数原型main

主函数原型main

argv[]:字符指针数组,存储命令行的每个字符串,argv[0]是命令名,argv[1]是第一个参数串,argv[2]是第二个参数串,依此类推。

  • (intargc,char*argv[])形参说明
  • argc:命令行上字符串总数(包括命令名本身)
  • argc,argv只是形参名称,可以是其他名称,但类型一定要正确。

第89页:例21*打印命令行参数及命令本身main

例21*打印命令行参数及命令本身main

(intargc,char*argv[]){inti;for(i=0;i<argc;i++)

在VC环境中:选择“过程”/“设置”/调试”菜单中的“程序变量”选项,输入“aaabbb”,再运行程序。

在DOS环境中:直接执行文件名为test.exe7.4数组和指针argvtest0aaa1bbb23运行结果:test

printf("%s%c",argv[i],i<argc-1?',':'\n'); } 设程序名为test.c
  • aaa
  • bbb
  • (DOS下命令行)…(路径)\test.exe, aaa, bbb

第90页:例22*从命令行输入三个数

例22*从命令行输入三个数

  • 分别是整型数、实型数和字符串。
  • 分析使用命令行输入参数,要注意输入值类型应与程序中的类型要求一致。
  • 程序*(设程序名为test1.c)
  • 在DOS环境下输入命令行:test1
  • 123
  • abc
  • 在VC环境中:选择“过程”/“设置”/“调试”菜单中的“程序变量”选项,输入“123
  • abc”。

第91页:main

main

(intargc,char*argv[]){intd;floatf;charstr[10];if(argc<4){

printf("参数不够"); exit(0);} sscanf(argv[1],"%d",&d); sscanf(argv[2],"%f",&f); sscanf(argv[3],"%s",&str); printf("%s,%.2f,%d\n",str,f,d); } 

第92页:7.5 动态存储管理

7.5 动态存储管理

在任何一个变量使用前,都必须完成关于存储方面的有关安排,包括存放位置、占据多少存储单元,这个工作叫存储分配。

存储空间的静态分配方法是根据程序提供的信息,在变量定义时即可静态计算出需要的空间,预先分配好空间。

如外部变量、局部静态变量在编译时即可决定。

局部变量的大小也是静态确定的(函数在被调用时所需的空间在编译时可确定)。

  • 静态分配的好处是处理、实现方便简单,执行效率高

第93页:但存在问题是对某些问题

但存在问题是对某些问题

如数组排序程序中,定义的数组空间可以存储500个数组元素,实际问题也许只有10个元素。

对在写函数时无法预知的空间需求,如果能根据运行中的动态信息,确定实际需求空间,分配适当大小的空间,就可以提高内存空间利用率。

C语言提供了动态分配的机制,通过指针掌握对动态分配块的操作。

存储空间的动态管理包括分配、释放回收两方面的工作,由操作系统的“动态存储管理系统”完成。

C语言提供几个标准函数完成与该系统的交互工作。

  • 的空间要求预估不准确,可能引起空间浪费或空间不足的情况出现。

第94页:C语言标准动态存储管理函数标准动态存

C语言标准动态存储管理函数标准动态存

储管理函数原型在标准头文件“stdlib.h”中描述。1.存储分配函数malloc()

功能分配一大小为size个字节的存储块,返回指向这个块的指针,若申请失败,返回空指针。

  • 形式void*malloc(unsignedsize)
  • size:无符号整数
  • (void*):返回值类型,为通用指针,需要通过类型强制转化成特定的指针类型。

第95页:例23对数组进行排序时

例23对数组进行排序时

scanf("%d",&n); data=(int*)malloc(n*sizeof(int)); if(data==NULL){ … } 

第96页:带初始化的存储分配函数calloc

带初始化的存储分配函数calloc

size个字节的存储块,存储块的全部内容清0,返回指向这个块的指针,如果存储申请不能满足,返回空指针。

  • ()
  • 形式void*calloc(unsignedsize,unsignedn)
  • size:无符号整数
  • n:无符号整数
  • (void*):返回值类型,为通用指针,需要通过类型强制转化成特定的指针类型。
  • 功能分配一块大小为n

第97页:动态存储释放函数free

动态存储释放函数free

功能释放指针p(为调用前两个函数所得到的指针)所指的存储块。如果p的值为空,什么也不做。

调用free(p)后,p的指向没有改变,但不能再使用它的值,除非p重新指向新的数据单元。

  • ()
  • 形式voidfree(*p)
  • 注意
  • 编写程序中,应养成对不再使用的存储块立刻释放的习惯,避免造成存储块丢失。

第98页:分配调整函数realloc

分配调整函数realloc

如果新的分配要求可以满足,返回新存储块的指针,内容与原来块中的一样,其余部分不进行初始化。不能再通过p指针使用原来的存储块

  • ()
  • 形式void*realloc(void*p,unsignedn)
  • 功能更改前面做过的存储分配,指针p指向一个过去分配的存储块,n表示现在希望的存储块大小
  • 如果新的要求不能满足,返回NULL,p仍指向原来的位置

第99页:C语言标准动态存储管理

C语言标准动态存储管理

的使用C语言标准动态存储管理函数的使用,是后继课程中进行算法设计的基本操作,要求掌握概念及基本程序框架,下面对使用中的注意事项做个总结。

1.一定要检查空间分配成功与否常用下面的结构:if((p=(…*)malloc(…))==NULL){……}//对分配不成功的处理2.分配空间的大小一定要用运算符sizeof来计算。

第100页:关于存储块的管理

关于存储块的管理

系统完全不进行检查。

分配成功后,程序要控制分配空间块使用的正确性,一方面不可超出实际存储块的范围,另一方面,要在使用中保持和存储块的连接关系,避免因指针误操作引起存储块丢失。

同时,已分配的存储块不再使用时,应该及时释放。

4.动态存储块的存在期从其分配成功时开始,只有用free函数释放后才能结束其存储期。

如果某个函数得到了一块动态存储空间,由一个临时指针连接,函数结束时没有进行释放,由于函数结束时临时变量没有了定义,会出现与它连接的存储块丢失的情况。

第101页:7.6 指针实例

7.6 指针实例

scanf("%s",str);或:int*pa; *pa=10;str和pa没有指向具体的存储单元就执行输入和赋值操作,结果可能非常严重。
  • 程序中使用指针可能出现的问题归纳1.间接引用数组元素的指针出界。2.没有定义指针变量的初值就使用指针。例如:char*str

第102页:错误赋值错误的指针变量赋值可能引起问题

错误赋值错误的指针变量赋值可能引起问题

例如1:char*str="abcd";s[8]="12345";如果执行了str=s,指针将指向字符数组s,存储字符串"abcde"的存储空间就会丢失。

例如2:如果指针变量p指向由malloc分配的空间,执行p=NULL,则p指的空间丢失。

4.错误操作。

例如:指针变量p和q指向同一片空间,如果执行了free(p),则·q指针会变成悬空状态。

q变量的值失去了意义。

第103页:7.6 指针实例

7.6 指针实例

分析程序需要完成从整数到字符串的一个转换过程,输入是1~7内的整型数,用指针数组存储一周的英文名称,第一个元素不保存有效的数据,用来实现指针数组下标和星期几的对应。

  • 例24*编写程序用户输入一周内的第几天,输出相应的英文星期几的名称。
  • 程序分为三部分定义数据类型和结构、接受数字并进行转换和接受字符决定是否继续。

第104页:main(){char*week[]={

main(){char*week[]={

0,"Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"};intday_num;while(1){

printf("天数(1~7),退出(0),请输入:"); if(scanf("%d",&day_num)<1)day_num=-1;//退出程序if(day_num<1||day_num>7)printf("输入错误!\n"); elseprintf("星期:%s\n",week[day_num]); while(getchar()!='\n');} } 7.6指针实例可以看出,使用指针数组时,通过指针间接对元素的存取,不需进行指针的运算,这种方法效率更高。

第105页:25*编写判别回文的函数回文是顺读

25*编写判别回文的函数回文是顺读

和倒读都一样的字符串,编写函数,判断一字符串是否是回文。若是回文,函数返回1;否则返回0。

分析最直接的方法,根据回文的定义,依次判断字符串的第一个字符是否等于最后一个字符,第二个字符是否等于倒数第二个字符,……用两个指针变量分别指向待比较的一对字符。

  • 函数

第106页:intpalind

intpalind

(char*s){char*p=s,c;intresult=1;while(*p)p++;p--;while(s<p)if(*s==*p){p--;s++;}else{result=0;break;}returnresult;}7.6指针实例

main(){ chars[50]; printf("输入串:"); gets(s); printf("%s",s); if(palind(s))printf("是回文!\n"); elseprintf("不是回文\n"); } 运行结果:输入串:wxyzzyxw
  • wxyzzyxw是回文!输入串:abcdef
  • abcdef不是回文

第107页:7.7 小结本章的内容主要

7.7 小结本章的内容主要

指针基本概念包括变量的地址和变量的值、指针变量的说明、指针变量初始化、指针的内容、指针基本运算(取变量地址、取指针内容、指针移动、指针比较)和变量与指针的关系。

指针与函数的关系指针可作为函数的参数在函数之间传递,通过指针改变调用函数中的变量,函数返回值为指针类型,指向函数的指针。

  • 包括下面一些内容:

第108页:指针与数组的关系

指针与数组的关系

包括数组名与地址的关系,如何使用指针操作数组,二维数组下标与指针的关系,函数之间传递数组的指针操作,数组指针与指针数组的概念及两者的区别和main函数参数。

使用指针处理字符串包括关于字符串的基本规定、字符串的结束标记、使用指针操作字符串的基本算法和常用字符串库函数。