版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第第7 7章章 指针指针 在这一章中将介绍在这一章中将介绍C语言程序的指针,指语言程序的指针,指针是一内存中的地址,任何一个变量在内存中针是一内存中的地址,任何一个变量在内存中都有一个空间,这个空间有一个地址,这个地都有一个空间,这个空间有一个地址,这个地址就是变量的指针,通过指针可以实现对内存址就是变量的指针,通过指针可以实现对内存的直接访问。的直接访问。7.1 指针概述指针概述7.2 指针与函数参数指针与函数参数7.3 指针与数组指针与数组7.4 数组与函数参数数组与函数参数7.5 字符串与指针字符串与指针7.6 指针与二维数组指针与二维数组7.7 动态数组动态数组7.1 指针概述指针概述
2、 在计算机中,所有的数据都是存放在存储在计算机中,所有的数据都是存放在存储器中的,不同的数据类型所占用的内存单元数器中的,不同的数据类型所占用的内存单元数不等,如不等,如int整型量占整型量占4个字节,字符量占个字节,字符量占1个字个字节。为了正确地访问这些内存单元,节。为了正确地访问这些内存单元, 必须为每必须为每个内存单元编上号,根据一个内存单元的编号个内存单元编上号,根据一个内存单元的编号即可准确地找到该内存单元。内存单元的编号即可准确地找到该内存单元。内存单元的编号也叫做地址。也叫做地址。 既然根据内存单元的编号或地址既然根据内存单元的编号或地址就可以找到所需的内存单元,所以通常也把这
3、就可以找到所需的内存单元,所以通常也把这个地址称为指针。个地址称为指针。 1 指针变量指针变量 系统的指针地址可以用一个变量来存储,这系统的指针地址可以用一个变量来存储,这个变量就是指针变量。指针变量的定义规则是:个变量就是指针变量。指针变量的定义规则是: 数据类型数据类型 * 变量名称;变量名称; 指针变量的定义与普通变量十分相似,只是在其指针变量的定义与普通变量十分相似,只是在其中插入了一个中插入了一个“*”号,例如:号,例如: int *p; p是指针变量,可以用来存储一个整数变量的地址,是指针变量,可以用来存储一个整数变量的地址,或称它指向一个整数变量。或称它指向一个整数变量。严格地说
4、,一个指针严格地说,一个指针是一个地址,是一个常量。而一个指针变量却可是一个地址,是一个常量。而一个指针变量却可以被赋予不同的指针值,是变量,但通常把指针以被赋予不同的指针值,是变量,但通常把指针变量简称为指针。变量简称为指针。 2 指针变量的赋值指针变量的赋值 指针变量是一个可以存储指针值的变量,在指针变量是一个可以存储指针值的变量,在32位系统中它占位系统中它占4个字节,可以把一个变量用个字节,可以把一个变量用&取地址后赋值给这个指针变量,例如:取地址后赋值给这个指针变量,例如: int a=1,*p; p=&a; 此时此时p存储了变量存储了变量a的地址。注意变量的地址。注
5、意变量p本身本身也是一个变量,它自己也有一个存储单元,这个也是一个变量,它自己也有一个存储单元,这个存储单元显然与变量存储单元显然与变量a的存储单元是不同的,变的存储单元是不同的,变量量a的存储单元存储的是变量的存储单元存储的是变量a的值,而变量的值,而变量p存存储单元存储的是变量储单元存储的是变量a单元的地址,如图单元的地址,如图7-3所示。所示。 图7-3 变量指针与指针变量 指针变量是有类型的,例如:指针变量是有类型的,例如: int *p; char *q; 则则p是一个指向整数变量的指针变量,是一个指向整数变量的指针变量,q是一个是一个指向字符变量的指针变量,在对它们赋值时要指向字符
6、变量的指针变量,在对它们赋值时要注意类型匹配,例如:注意类型匹配,例如: int *p,a; char *q,c; p=&a; / 正确正确 q=&c; / 正确正确 p=&c; / 错误错误 q=&a; / 错误错误 一般要保证变量类型与指针类型一致,不一般要保证变量类型与指针类型一致,不能把一种类型的变量的指针赋值给另外一种不能把一种类型的变量的指针赋值给另外一种不同类型的指针变量。但是由于指针毕竟是一个同类型的指针变量。但是由于指针毕竟是一个内存地址,从物理上来说,内存地址,从物理上来说,p与与q都是内存地址,都是内存地址,在在32位系统中都是位系统中都是
7、32位二进制地址值,没有什位二进制地址值,没有什么本质区别,因此经过转化后还是可以交叉赋么本质区别,因此经过转化后还是可以交叉赋值的,通过指针的类型转换可以实现下列赋值:值的,通过指针的类型转换可以实现下列赋值: p=(int*)&c; / &c是是char *指针,指针,(int*)转化后成为转化后成为int *类型指针类型指针 q=(char*)&a; / &a是是int *指针,指针,(char*)转化后成为转化后成为char *类型指针类型指针 一般指针变量类型的转换可以通过下面方式完成:一般指针变量类型的转换可以通过下面方式完成: (数据类型数据类型
8、*)指针指针 另外数组变量也可以取指针,例如:另外数组变量也可以取指针,例如: int a5,*p; p=&a0; / p指向指向a0变量变量 p=&a4; / p指向指向a4变量变量 关于数组与指针的关系在后面章节中再进一步讲解。关于数组与指针的关系在后面章节中再进一步讲解。 3通过指针访问变量通过指针访问变量 既然指针变量指向一个变量,因此通过指既然指针变量指向一个变量,因此通过指针变量也就知道变量的位置,知道位置也就能针变量也就知道变量的位置,知道位置也就能访问到变量,可以通过指针变量存取变量的值。访问到变量,可以通过指针变量存取变量的值。 C中规定通过:中规定通过: *
9、指针变量指针变量 来访问对应变量的值,例如:来访问对应变量的值,例如: int a=1,b,*p; p=&a; *p=2; / 设置设置p指向的变量的值为指向的变量的值为2,既,既a=2 b=*p; / 把把p指向的变量的值赋予指向的变量的值赋予b,既,既b=2 在在C语言中,系统对语言中,系统对“*指针变量指针变量”的解释是的解释是根据指针变量的类型计算出对应变量所占字节数,根据指针变量的类型计算出对应变量所占字节数,之后把指针变量所指的连续的几个字节的二进制之后把指针变量所指的连续的几个字节的二进制数据看成是与指针变量同类型的数据并存取这一数据看成是与指针变量同类型的数据并存取这一
10、数据。数据。7.2 指针与函数参数指针与函数参数 指针变量与普通变量一样也可以作为函数指针变量与普通变量一样也可以作为函数参数来传递,实际参数是一个变量的指针,该参数来传递,实际参数是一个变量的指针,该变量的指针传递到函数的形式参数指针变量,变量的指针传递到函数的形式参数指针变量,这样形式参数的指针变量仍然指向实际参数,这样形式参数的指针变量仍然指向实际参数,换句话说就是在函数中可以访问主函数的实际换句话说就是在函数中可以访问主函数的实际参数。参数。 但要注意函数如返回一个指针,则这个指但要注意函数如返回一个指针,则这个指针指向的变量必须有效,不能返回一个函数局针指向的变量必须有效,不能返回一
11、个函数局部变量的指针,这个指针是无意义的,因为函部变量的指针,这个指针是无意义的,因为函数的局部变量在函数退出时已经销毁了。数的局部变量在函数退出时已经销毁了。 在前面章节中曾经介绍过当变量作为函数在前面章节中曾经介绍过当变量作为函数参数时,它是函数的一个局部变量,它在函数参数时,它是函数的一个局部变量,它在函数内的改变不会影响到主函数的对应实参数变量。内的改变不会影响到主函数的对应实参数变量。但如把指针变量作为函数参数来传递情况有不但如把指针变量作为函数参数来传递情况有不同,通过该指针变量去改变对应变量的值会影同,通过该指针变量去改变对应变量的值会影响到主函数对应的变量。响到主函数对应的变量
12、。例例7_5:值传递与地址传递规则。:值传递与地址传递规则。#include void fun(int *p,int b) printf(fun中中: p=%p *p=%d &b=%p b=%dn,p,*p,&b,b); *p=100; b=100;void main() int a=1,b=2,*p; p=&a; printf(调用前调用前: p=%p a=%d &b=%p b=%dn,p,a,&b,b); fun(p,b); printf(调用前调用前: p=%p a=%d &b=%p b=%dn,p,a,&b,b); C语言中把函数
13、参数是指针变量的传递方语言中把函数参数是指针变量的传递方法称为地址传递,它传递的是变量的地址,因法称为地址传递,它传递的是变量的地址,因此在函数中用此地址改变对应变量的值时,实此在函数中用此地址改变对应变量的值时,实际上改变的是主函数中的变量的值。而把函数际上改变的是主函数中的变量的值。而把函数参数是普通变量的传递称为值传递,它传递的参数是普通变量的传递称为值传递,它传递的是实际参数的值,而且它是函数的局部变量,是实际参数的值,而且它是函数的局部变量,因此它的值在函数中改变时不会影响到主函数因此它的值在函数中改变时不会影响到主函数中实际参数的值。中实际参数的值。7.3 指针与数组指针与数组 i
14、nt a5; 则则a0、a1、a2、a3、a4都是整数变量,都是整数变量,既然是变量它们在内存中有对应的存储空间,既然是变量它们在内存中有对应的存储空间,也就可以取出其指针地址,而且这些地址是连也就可以取出其指针地址,而且这些地址是连续的,因为数组单元是连续的。续的,因为数组单元是连续的。 既然数组的单元是连续存放的,因此只要知既然数组的单元是连续存放的,因此只要知道数组第一个单元的地址,那么整个数组中任何道数组第一个单元的地址,那么整个数组中任何一个单元的地址也就可以计算出来,或者说只要一个单元的地址也就可以计算出来,或者说只要掌握了数组的第一个单元的指针,整个数组就掌掌握了数组的第一个单元
15、的指针,整个数组就掌握在手中了。握在手中了。 数组第一个单元的指针称为数组的首地址,数组第一个单元的指针称为数组的首地址,也称为数组的地址,在也称为数组的地址,在C语言中数组的首地址直语言中数组的首地址直接用数组名称得到,例如数组接用数组名称得到,例如数组 int a5; 则则a就是数组的首地址,也就是说,就是数组的首地址,也就是说,a就是就是&a0,a就是指向数组的指针。实际上这一规则对于任就是指向数组的指针。实际上这一规则对于任何类型的数组都是一样的。何类型的数组都是一样的。 图7-11 int a5数组指针 既然数组名称就是数组的首地址,也就可以通既然数组名称就是数组的首地址,也
16、就可以通过数组指针去访问数组的任何一个单元了,方法过数组指针去访问数组的任何一个单元了,方法是把数组的地址指针加上一个作为数组下标的整是把数组的地址指针加上一个作为数组下标的整数就是数组的对应单元的地址。例如:数就是数组的对应单元的地址。例如: int a5; a是数组的首地址,既是数组的首地址,既&a0,而,而a+1是是a1的地址,的地址,既既&a1,*(a+1)是对应的单元变量,既是对应的单元变量,既a1。一。一般如般如i是数组的整数下标,则是数组的整数下标,则a+i是第是第i个单元的地个单元的地址,既址,既a+i就是就是&ai,同时,同时*(a+1)就是就是ai,
17、通过,通过*(a+i)去存取数组单元的值与用去存取数组单元的值与用ai去存取是完全去存取是完全一样的。一样的。 值得注意的是,值得注意的是,a+i不是简单把不是简单把a的二进制的二进制地址值加了一个整数地址值加了一个整数i,对于整数数组实际上,对于整数数组实际上a+i从二进制值上来说比从二进制值上来说比a地址多了地址多了sizeof(int)*i的值。的值。 1 指针移动指针移动 数组单元的指针可以通过数组指针加上一个数组单元的指针可以通过数组指针加上一个数组下标整数变量来得到,这种指针运算称为指数组下标整数变量来得到,这种指针运算称为指针移动运算。当指针加上一个正整数时,指针值针移动运算。当
18、指针加上一个正整数时,指针值变大了,它指向了存储器的后面,称指针后移,变大了,它指向了存储器的后面,称指针后移,或向下移动。实际上指针不但可以下移,也可以或向下移动。实际上指针不但可以下移,也可以上移。如指针加上一个负整数,指针值变小了,上移。如指针加上一个负整数,指针值变小了,它指向了存储器的前面,称指针前移,或向上移它指向了存储器的前面,称指针前移,或向上移动。动。 如指针的移动仅仅是一个单元,则常用如指针的移动仅仅是一个单元,则常用+ 或或的运算符来实现。通过指针在数组范围内的运算符来实现。通过指针在数组范围内的上下或前后移动可以随意地存取数组的任何的上下或前后移动可以随意地存取数组的任
19、何一个单元。一个单元。 2 指针比较指针比较 指针在数组中移动之后有前后之分,体现在它指针在数组中移动之后有前后之分,体现在它的二进制值有大小之分,因此指针可以通过其二的二进制值有大小之分,因此指针可以通过其二进制值来比较大小。指针指向后面的,其二进制进制值来比较大小。指针指向后面的,其二进制值大,这样的指针大;指针指向前面的,其二进值大,这样的指针大;指针指向前面的,其二进制值小,这样的指针小。指针比较主要运算有:制值小,这样的指针小。指针比较主要运算有: 大于大于 = 大于等于大于等于 = 小于等于小于等于= 相等相等 !=; 不等于不等于 比较运算的结果是一个逻辑值,通过比较两比较运算的
20、结果是一个逻辑值,通过比较两个指针的值可以知道它们在内存中的相对位置。个指针的值可以知道它们在内存中的相对位置。 3 指针的减法运算指针的减法运算 通过比较运算可以知道两个指针的前后关通过比较运算可以知道两个指针的前后关系,但怎样知道它们之间的相对距离呢?要知系,但怎样知道它们之间的相对距离呢?要知道它们的相对距离可以通过计算两个指针的差道它们的相对距离可以通过计算两个指针的差来得到,两个指针的差是一个整数,表示它们来得到,两个指针的差是一个整数,表示它们之间间隔的单元数(注意不是相差的字节数)。之间间隔的单元数(注意不是相差的字节数)。 7.4 数组与函数参数数组与函数参数 前面已经讲到过指
21、针可以作为函数参数,而前面已经讲到过指针可以作为函数参数,而数组与是指针密切相关,因此数组也可以作为数组与是指针密切相关,因此数组也可以作为函数参数,数组作为函数参数实际上就是数组函数参数,数组作为函数参数实际上就是数组指针作为函数参数,其规则是:指针作为函数参数,其规则是: 函数类型函数类型 函数名称(数组类型函数名称(数组类型 数组名称数组名称);); 或或 函数类型函数类型 函数名称(数组类型函数名称(数组类型 *数组名称);数组名称); 例如:例如: void fun(int a); void fun(int *a); 这两种方式是等价的,注意在用第一种方这两种方式是等价的,注意在用第
22、一种方式时不必在式时不必在中写数组的大小。在调用函数时中写数组的大小。在调用函数时实际参数就是数组的名称,也就是数组指针。实际参数就是数组的名称,也就是数组指针。 由于在调用函数时向函数传递的实际上是由于在调用函数时向函数传递的实际上是数组地址,因此要特别注意在函数中如对数组数组地址,因此要特别注意在函数中如对数组的单元进行了修改,实际上是对主函数的数组的单元进行了修改,实际上是对主函数的数组进行修改。进行修改。 另外一点要指出的是,数组在传递时传递另外一点要指出的是,数组在传递时传递的是数组指针,它不包含数组大小的信息,因的是数组指针,它不包含数组大小的信息,因此在向函数传递数组时一般要用一
23、个整数同时此在向函数传递数组时一般要用一个整数同时传递数组的大小。传递数组的大小。 如果实际参数是数组名称,则向函数传递如果实际参数是数组名称,则向函数传递的数组指针,但如实际参数是某个数组元素,的数组指针,但如实际参数是某个数组元素,那么因为数组元素是一个变量,因此传递方法那么因为数组元素是一个变量,因此传递方法与普通变量是一样的,采用传值的方式进行,与普通变量是一样的,采用传值的方式进行,函数中形式参数的变化不会影响对应的实参的函数中形式参数的变化不会影响对应的实参的数组元素。数组元素。 字符串实际上是内存中一段连续的字节单元中字符串实际上是内存中一段连续的字节单元中存储的字符的总和,最后
24、用一个存储的字符的总和,最后用一个0来标志它的来标志它的结束。前面已经讲解过字符串与字符数组是密切结束。前面已经讲解过字符串与字符数组是密切相关的,而数组又与指针密切相关的,因此字符相关的,而数组又与指针密切相关的,因此字符串与指针也密切相关。指向字符串的指针称为字串与指针也密切相关。指向字符串的指针称为字符串指针,其类型是符串指针,其类型是char *或或unsigned char *。实。实际上只要知道字符串的首地址的指针,那么就可际上只要知道字符串的首地址的指针,那么就可以通过移动指针存取字符串的每一个字符,当访以通过移动指针存取字符串的每一个字符,当访问到字符问到字符0时就是字符串的边
25、界。因此可以用时就是字符串的边界。因此可以用字符串指针来表示字符串。例如:字符串指针来表示字符串。例如:7.5 字符串与指针字符串与指针 char *s=”Hello”; 其中其中s就是一个字符串指针,在执行该语句就是一个字符串指针,在执行该语句时系统为时系统为”Hello”字符串分配字符串分配6个字节的空间,个字节的空间,同时把字符串的首地址既同时把字符串的首地址既H字符的地址赋值字符的地址赋值给给s指针变量。上述语句也可以写成:指针变量。上述语句也可以写成: char s=”Hello”; 用字符数组来存储字符串时,数组的指针用字符数组来存储字符串时,数组的指针就是字符串指针。通过就是字符
26、串指针。通过s指针可以访问到任何指针可以访问到任何一个字符单元,例如一个字符单元,例如i是一个整数下标,则是一个整数下标,则si与与*(s+i)是同一个元素,是同一个元素,&si与与s+i是同一个地是同一个地址,址,+s或或s可以使指针一次移动一个字节单可以使指针一次移动一个字节单元。元。 图7-19 “Hello”的指针 字符串指针作为函数参数与普通的数组指字符串指针作为函数参数与普通的数组指针作为函数参数完全一样,因为字符串指针实针作为函数参数完全一样,因为字符串指针实际上也是字符数组的指针。应用中不同的是在际上也是字符数组的指针。应用中不同的是在普通数组作为函数参数时要同时向函数
27、传递数普通数组作为函数参数时要同时向函数传递数组的大小,但字符串指针作为函数参数传递字组的大小,但字符串指针作为函数参数传递字符串时由于字符串可以通过符串时由于字符串可以通过0的结束标志来的结束标志来判断字符串的大小,因此不需要向函数传递字判断字符串的大小,因此不需要向函数传递字符串的大小,只要传递字符串指针,在函数中符串的大小,只要传递字符串指针,在函数中就可以操作整个字符串了。就可以操作整个字符串了。 7.6 指针与二维数组指针与二维数组 指针数组就是数组的每一个元素都是一个指针数组就是数组的每一个元素都是一个指针变量,例如:指针变量,例如: int *p3; 则则p0、p1、p2这这3元
28、素都是整数指针。元素都是整数指针。 在二维数组中曾经讲到过二维数组是数组的数在二维数组中曾经讲到过二维数组是数组的数组,组, 例如:例如: 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元素的指元素
29、的指针,一般情况下,如针,一般情况下,如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个整数的数组。个整数的数组。 设有二维数组:设有二维数组: 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个元素的整数数组的指针个元素的整数数组的指针 在用二维数组作函数参数时,第一维的数值可以省在用二维数组作函数参数时,第一维的数值可以省略,但第二维的数值不可以省略。
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年度专业牧场代牧服务标准合同4篇
- 2025年度临时停车场帐篷搭建施工合同范本3篇
- 2024物流包装与装卸合同
- 2025年度智慧家居产品研发承包经营合同书范文4篇
- 2025年度桉树种植与生物质能利用技术研发合同3篇
- 2025年个人汽车抵押贷款抵押权设立及转让合同4篇
- 2025年度住宅小区地下车库车位使用权购买合同范本4篇
- 2025年度文化产业园开发承包合同股东内部合作协议4篇
- 2024年甲乙双方石材供需合同
- 2025年度新能源项目地质钻孔工程承包协议4篇
- 【传媒大学】2024年新营销
- 乳腺癌的综合治疗及进展
- 【大学课件】基于BGP协议的IP黑名单分发系统
- 2025届广东省佛山市高三上学期普通高中教学质量检测(一模)英语试卷(无答案)
- 自身免疫性脑炎课件
- 人力资源管理各岗位工作职责
- 信阳农林学院《新媒体传播学》2023-2024学年第一学期期末试卷
- 2024建筑公司年终工作总结(32篇)
- 信息安全意识培训课件
- 2024年项目投资计划书(三篇)
- 配电安规课件
评论
0/150
提交评论