在这一章中将介绍C语言程序的指针.ppt_第1页
在这一章中将介绍C语言程序的指针.ppt_第2页
在这一章中将介绍C语言程序的指针.ppt_第3页
在这一章中将介绍C语言程序的指针.ppt_第4页
在这一章中将介绍C语言程序的指针.ppt_第5页
已阅读5页,还剩36页未读 继续免费阅读

下载本文档

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

文档简介

第7章 指针,在这一章中将介绍C语言程序的指针,指针是一内存中的地址,任何一个变量在内存中都有一个空间,这个空间有一个地址,这个地址就是变量的指针,通过指针可以实现对内存的直接访问。,7.1 指针概述 7.2 指针与函数参数 7.3 指针与数组 7.4 数组与函数参数 7.5 字符串与指针 7.6 指针与二维数组 7.7 动态数组,7.1 指针概述,在计算机中,所有的数据都是存放在存储器中的,不同的数据类型所占用的内存单元数不等,如int整型量占4个字节,字符量占1个字节。为了正确地访问这些内存单元, 必须为每个内存单元编上号,根据一个内存单元的编号即可准确地找到该内存单元。内存单元的编号也叫做地址。 既然根据内存单元的编号或地址就可以找到所需的内存单元,所以通常也把这个地址称为指针。,7.1.2 变量的指针与指针变量,1 指针变量 系统的指针地址可以用一个变量来存储,这个变量就是指针变量。指针变量的定义规则是: 数据类型 * 变量名称; 指针变量的定义与普通变量十分相似,只是在其中插入了一个“*”号,例如: int *p; p是指针变量,可以用来存储一个整数变量的地址,或称它指向一个整数变量。严格地说,一个指针是一个地址,是一个常量。而一个指针变量却可以被赋予不同的指针值,是变量,但通常把指针变量简称为指针。,2 指针变量的赋值 指针变量是一个可以存储指针值的变量,在32位系统中它占4个字节,可以把一个变量用 此时p存储了变量a的地址。注意变量p本身也是一个变量,它自己也有一个存储单元,这个存储单元显然与变量a的存储单元是不同的,变量a的存储单元存储的是变量a的值,而变量p存储单元存储的是变量a单元的地址,如图7-3所示。,图7-3 变量指针与指针变量,指针变量是有类型的,例如: int *p; char *q; 则p是一个指向整数变量的指针变量,q是一个指向字符变量的指针变量,在对它们赋值时要注意类型匹配,例如: int *p,a; char *q,c; p= / 错误,一般要保证变量类型与指针类型一致,不能把一种类型的变量的指针赋值给另外一种不同类型的指针变量。但是由于指针毕竟是一个内存地址,从物理上来说,p与q都是内存地址,在32位系统中都是32位二进制地址值,没有什么本质区别,因此经过转化后还是可以交叉赋值的,通过指针的类型转换可以实现下列赋值:,p=(int*) / p指向a4变量 关于数组与指针的关系在后面章节中再进一步讲解。,3通过指针访问变量 既然指针变量指向一个变量,因此通过指针变量也就知道变量的位置,知道位置也就能访问到变量,可以通过指针变量存取变量的值。,C中规定通过: *指针变量 来访问对应变量的值,例如: int a=1,b,*p; p= / 把p指向的变量的值赋予b,既b=2 在C语言中,系统对“*指针变量”的解释是根据指针变量的类型计算出对应变量所占字节数,之后把指针变量所指的连续的几个字节的二进制数据看成是与指针变量同类型的数据并存取这一数据。,7.2 指针与函数参数,7.2.1 指针作为函数参数 指针变量与普通变量一样也可以作为函数参数来传递,实际参数是一个变量的指针,该变量的指针传递到函数的形式参数指针变量,这样形式参数的指针变量仍然指向实际参数,换句话说就是在函数中可以访问主函数的实际参数。 但要注意函数如返回一个指针,则这个指针指向的变量必须有效,不能返回一个函数局部变量的指针,这个指针是无意义的,因为函数的局部变量在函数退出时已经销毁了。,7.2.2 值传递与地址传递,在前面章节中曾经介绍过当变量作为函数参数时,它是函数的一个局部变量,它在函数内的改变不会影响到主函数的对应实参数变量。但如把指针变量作为函数参数来传递情况有不同,通过该指针变量去改变对应变量的值会影响到主函数对应的变量。,例7_5:值传递与地址传递规则。 #include void fun(int *p,int b) printf(“fun中: p=%p *p=%d ,C语言中把函数参数是指针变量的传递方法称为地址传递,它传递的是变量的地址,因此在函数中用此地址改变对应变量的值时,实际上改变的是主函数中的变量的值。而把函数参数是普通变量的传递称为值传递,它传递的是实际参数的值,而且它是函数的局部变量,因此它的值在函数中改变时不会影响到主函数中实际参数的值。,7.3 指针与数组,7.3.1 指向数组的指针 int a5; 则a0、a1、a2、a3、a4都是整数变量,既然是变量它们在内存中有对应的存储空间,也就可以取出其指针地址,而且这些地址是连续的,因为数组单元是连续的。,既然数组的单元是连续存放的,因此只要知道数组第一个单元的地址,那么整个数组中任何一个单元的地址也就可以计算出来,或者说只要掌握了数组的第一个单元的指针,整个数组就掌握在手中了。 数组第一个单元的指针称为数组的首地址,也称为数组的地址,在C语言中数组的首地址直接用数组名称得到,例如数组 int a5; 则a就是数组的首地址,也就是说,a就是&a0,a就是指向数组的指针。实际上这一规则对于任何类型的数组都是一样的。,图7-11 int a5数组指针,7.3.2 通过数组指针访问数组,既然数组名称就是数组的首地址,也就可以通过数组指针去访问数组的任何一个单元了,方法是把数组的地址指针加上一个作为数组下标的整数就是数组的对应单元的地址。例如: int a5; a是数组的首地址,既&a0,而a+1是a1的地址,既&a1,*(a+1)是对应的单元变量,既a1。一般如i是数组的整数下标,则a+i是第i个单元的地址,既a+i就是&ai,同时*(a+1)就是ai,通过*(a+i)去存取数组单元的值与用ai去存取是完全一样的。,值得注意的是,a+i不是简单把a的二进制地址值加了一个整数i,对于整数数组实际上a+i从二进制值上来说比a地址多了sizeof(int)*i的值。,7.3.3 指针移动与指针比较,1 指针移动 数组单元的指针可以通过数组指针加上一个数组下标整数变量来得到,这种指针运算称为指针移动运算。当指针加上一个正整数时,指针值变大了,它指向了存储器的后面,称指针后移,或向下移动。实际上指针不但可以下移,也可以上移。如指针加上一个负整数,指针值变小了,它指向了存储器的前面,称指针前移,或向上移动。,如指针的移动仅仅是一个单元,则常用+ 或的运算符来实现。通过指针在数组范围内的上下或前后移动可以随意地存取数组的任何一个单元。,2 指针比较 指针在数组中移动之后有前后之分,体现在它的二进制值有大小之分,因此指针可以通过其二进制值来比较大小。指针指向后面的,其二进制值大,这样的指针大;指针指向前面的,其二进制值小,这样的指针小。指针比较主要运算有: 大于 = 大于等于 = 小于等于 = 相等 !=; 不等于 比较运算的结果是一个逻辑值,通过比较两个指针的值可以知道它们在内存中的相对位置。,3 指针的减法运算 通过比较运算可以知道两个指针的前后关系,但怎样知道它们之间的相对距离呢?要知道它们的相对距离可以通过计算两个指针的差来得到,两个指针的差是一个整数,表示它们之间间隔的单元数(注意不是相差的字节数)。,7.4 数组与函数参数,7.4.1 数组作为函数参数 前面已经讲到过指针可以作为函数参数,而数组与是指针密切相关,因此数组也可以作为函数参数,数组作为函数参数实际上就是数组指针作为函数参数,其规则是: 函数类型 函数名称(数组类型 数组名称); 或 函数类型 函数名称(数组类型 *数组名称);,例如: void fun(int a); void fun(int *a); 这两种方式是等价的,注意在用第一种方式时不必在中写数组的大小。在调用函数时实际参数就是数组的名称,也就是数组指针。,由于在调用函数时向函数传递的实际上是数组地址,因此要特别注意在函数中如对数组的单元进行了修改,实际上是对主函数的数组进行修改。 另外一点要指出的是,数组在传递时传递的是数组指针,它不包含数组大小的信息,因此在向函数传递数组时一般要用一个整数同时传递数组的大小。,7.4.2 数组元素作为实际参数,如果实际参数是数组名称,则向函数传递的数组指针,但如实际参数是某个数组元素,那么因为数组元素是一个变量,因此传递方法与普通变量是一样的,采用传值的方式进行,函数中形式参数的变化不会影响对应的实参的数组元素。,7.5.1 字符串指针 字符串实际上是内存中一段连续的字节单元中存储的字符的总和,最后用一个0来标志它的结束。前面已经讲解过字符串与字符数组是密切相关的,而数组又与指针密切相关的,因此字符串与指针也密切相关。指向字符串的指针称为字符串指针,其类型是char *或unsigned char *。实际上只要知道字符串的首地址的指针,那么就可以通过移动指针存取字符串的每一个字符,当访问到字符0时就是字符串的边界。因此可以用字符串指针来表示字符串。例如:,7.5 字符串与指针,char *s=”Hello”; 其中s就是一个字符串指针,在执行该语句时系统为”Hello”字符串分配6个字节的空间,同时把字符串的首地址既H字符的地址赋值给s指针变量。上述语句也可以写成: char s=”Hello”; 用字符数组来存储字符串时,数组的指针就是字符串指针。通过s指针可以访问到任何一个字符单元,例如i是一个整数下标,则si与*(s+i)是同一个元素,&si与s+i是同一个地址,+s或s可以使指针一次移动一个字节单元。,图7-19 “Hello”的指针,7.5.2 字符串指针作为函数参数,字符串指针作为函数参数与普通的数组指针作为函数参数完全一样,因为字符串指针实际上也是字符数组的指针。应用中不同的是在普通数组作为函数参数时要同时向函数传递数组的大小,但字符串指针作为函数参数传递字符串时由于字符串可以通过0的结束标志来判断字符串的大小,因此不需要向函数传递字符串的大小,只要传递字符串指针,在函数中就可以操作整个字符串了。,7.6 指针与二维数组,7.6.1 指针数组与二维数组 指针数组就是数组的每一个元素都是一个指针变量,例如: int *p3; 则p0、p1、p2这3元素都是整数指针。 在二维数组中曾经讲到过二维数组是数组的数组,,例如: int a34; 则a0、a1、a2都是一位的数组,每个数组的元素个数是4,既然a0、a1 、a2是一维数组,因此它们也就是数组指针,既它们都是int*类型指针,,换句话说可以: p0=a0; p1=a1; p2=a2; 因此a0+0就是a00元素的指针,a0+1是a01元素的指针,a2+2是a22元素的指针,一般情况下,如i(i=0,1,2)及j(j=0,1,2,3)是二维数组a的下标变量,则ai+j是aij元素的指针,可以通过*(ai+j)来存取aij元素。 a是一个指针数组,有3个指针元素,既a0、a1、a2,而每一个指针数组都有4个整数元素,a是一个int (*)4类型的指针,既是一个指针,该指针指向有4个整数的数组。,7.6.2 二维数组作为函数参数,设有二维数组: int a34; 用它作为函数fun的参数可以写成下列形式之一: void fun(int a34,int m,int n); / 指定行数与列数 void fun(int a4,int m,int n); / 指定列数 void fun(int (*a)4,int m,int n); / 指定a是一个指向有4个元素的整数数组的指针 在用二维数组作函数参数时,第一维的数值可以省略,但第二维的数值不可以省略。,7.6.3 字符串数组,在字符串数组中每一个数组元素都是一个字符串指针,例如: char s34; 则s0、s1、s2都是char*指针,s是一个(char *)4的指针,如果用二维的字符数组来存储字符串,则性质与前面讲到的二维整数数组相似。 但是字符串指针数组可以用来存储一组字符串的指针,可以通过这样一组字符串指针数组来操作一组字符串。,7.7 动态数组,7.7.1 动态内存分配 在很多实际问题中,数组的大小预先是不可知的,只有在程序运行时根据计算结果才能确定数组的大小,因此需要能在程序中通过变量来确定数组大小,即根据实际需要来分配存储空间,这样的数组称为动态数组。 在C语言中允许用户自己申请内存空间,申请的函数是: void *malloc( int size );,malloc的意思是memory allocation,它的作用是向系统申请size个字节的空间,如成功则返回申请到的内存空间的指针,该指针是一个void *指针,在具体应用时还需要转换成具体某一数据类型的指针,如申请失败则返回一个空指针NULL,其中NULL是系统定义的常数,表示一个空的指针。应用该函数时必须包

温馨提示

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

评论

0/150

提交评论