




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第第6章章 指针指针6.1 指针概念指针概念 6.2 指针变量的定义和使用指针变量的定义和使用6.3 指针运算指针运算6.4 指针与数组及字符串指针与数组及字符串 6.5 指针数组和多级指针指针数组和多级指针 6.1 指针概念 变量的变量的直接地址访问(指针常量的概念引入)直接地址访问(指针常量的概念引入)查看查看VC6.0VC6.0代码的反汇编代码的反汇编 变量的变量的间接地址访问(指针变量的概念引入)间接地址访问(指针变量的概念引入) 区分指针变量的区分指针变量的定义和建立(何为定义和建立(何为“建立指针建立指针”) 指针变量的灵活性指针变量的灵活性 指针变量的两个空间概念(自身空间指针变
2、量的两个空间概念(自身空间+ +目标空间)目标空间)2/22/26.1 指针概念6.1.1 6.1.1 变量的地址变量的地址(指针常量)(指针常量) 程序一旦被执行,则该程序的指令、常量和变量等都要程序一旦被执行,则该程序的指令、常量和变量等都要存放在计算机的内存中。计算机的内存是以字节为单位的一存放在计算机的内存中。计算机的内存是以字节为单位的一片连续的存储空间,每个字节都有一个编号,这个编号就称片连续的存储空间,每个字节都有一个编号,这个编号就称为内存的地址。为内存的地址。注意 : 存储单元的地址和它里面存放的内容完全是两回存储单元的地址和它里面存放的内容完全是两回事事。 &aa
3、如果在程序中定义了一个变量,系统会根据如果在程序中定义了一个变量,系统会根据变量的数据类型给它分配一定字节数的内存空间变量的数据类型给它分配一定字节数的内存空间。例如例如: 在一个源程序中定义了如下变量在一个源程序中定义了如下变量: double d = 1.0; long int c = 8;int b = 100; short a = 3;1001002100410083100100081. 16位系统给变量系统给变量a a分配的地址是分配的地址是0 x10000 x1000,变量,变量b b分配的地分配的地址是址是0 x10020 x1002,变量,变量c c分配的地址是分配的地址是0
4、x10040 x1004变量变量d d分配的地址是分配的地址是0 x10080 x1008,得到如上图所示的内存示意图。,得到如上图所示的内存示意图。4B2B2B2/42/4在在VC6.0VC6.0中,变量中,变量a a、b b、c c、d d的地址分别为的地址分别为ebpebp- -* * *,对,对应的空间为:应的空间为:dword ptrdword ptr ebp-8 ebp-8dword ptrdword ptr ebp-0ch ebp-0chdword ptrdword ptr ebp-10h ebp-10hword ptrword ptr ebp-14h ebp-14h6.1.2
5、6.1.2 指针变量指针变量 除了前面介绍的普通变量之外,还使用另外一种特殊性除了前面介绍的普通变量之外,还使用另外一种特殊性质的变量,即质的变量,即指针变量指针变量。 指针变量是存放地址的变量。指针变量是存放地址的变量。它和普通变量一样占用一它和普通变量一样占用一定的存储空间。但是,它与普通变量定的存储空间。但是,它与普通变量不同之处不同之处在于,指针变在于,指针变量的存储空间中存放的不是普通的数据,而是一个地址,例量的存储空间中存放的不是普通的数据,而是一个地址,例如一个变量的首地址。如一个变量的首地址。 设某指针变量的名字是设某指针变量的名字是pxpx,同时存在另外一个名字,同时存在另外
6、一个名字为为x x的普通变量的普通变量, ,将变量将变量x x的地址送入指针的地址送入指针pxpx的存储区域,的存储区域,即即pxpx的内容就是变量的内容就是变量x x的地址,如下图所示:的地址,如下图所示:因此我们可以看出,因此我们可以看出,访问一个变量有两种方法访问一个变量有两种方法:(1 1)通过变量本身直接访问,)通过变量本身直接访问,x x,即,即直接地址访问直接地址访问(2 2)通过指向该变量的指针间接访问,)通过指向该变量的指针间接访问,* *pxpx,即,即间接地址访问间接地址访问 指针px 变量x 指针px 变量x px=&x (a) 变量的地址装入指针 (b) 指针
7、指向变量 2/62/61、什么叫建立指针、什么叫建立指针2、忘记给指针变量赋值的害处!、忘记给指针变量赋值的害处!“野指针野指针”3、指针变量使用的规则、指针变量使用的规则定义指针变量定义指针变量指明该指针只能指向哪种类型变量指明该指针只能指向哪种类型变量建立指针建立指针明确该变量从此时开始指向哪个变量明确该变量从此时开始指向哪个变量借助指针变量间接访问其指向的对象借助指针变量间接访问其指向的对象通过给指针变量赋值来确定指向关系通过给指针变量赋值来确定指向关系 指针px 变量x 指针px 变量x px=&x (a) 变量的地址装入指针 (b) 指针指向变量 建立指针建立指针建立指针建立
8、指针 指针px 变量x 指针px 变量x px=&x (a) 变量的地址装入指针 (b) 指针指向变量 指针变量空间指针变量空间访问时用访问时用px目标变量空间目标变量空间访问时用访问时用x或或*px3/93/96.2 6.2 指针变量的定义和使用指针变量的定义和使用6.2.1 6.2.1 指针变量的定义及初始化指针变量的定义及初始化 1 . 指针变量的定义指针变量的定义 指针变量在程序中使用之前,必须进行定义。指针变量在程序中使用之前,必须进行定义。 *指针名指针名;例如例如: int *px; char *name; static int *pa; 上面定义了名字为上面定义了名字为
9、pxpx,namename和和papa的三个不同类型指针。的三个不同类型指针。变量名由用户命名,使用字符的起名规则与变量名相同。变量名由用户命名,使用字符的起名规则与变量名相同。1/101/10 指针变量的存储类型是指针变量本身的存储类型。它指针变量的存储类型是指针变量本身的存储类型。它与与普通变量一样,分为:普通变量一样,分为: autoauto(在函数内部定义,可以缺省)(在函数内部定义,可以缺省) registerregister static static extern extern(在函数外部定义时可以缺省)(在函数外部定义时可以缺省) 不同存储类型的指针使用的存储区域不同,这与普通
10、不同存储类型的指针使用的存储区域不同,这与普通变变量完全相同。指针存储类型和指针在程序中的定义位置决定量完全相同。指针存储类型和指针在程序中的定义位置决定指针的寿命和可见性。即指针变量也分为指针的寿命和可见性。即指针变量也分为内部内部的和的和外部外部的,的,全局全局的和的和局部局部的。的。1/111/112 . 指针变量的指针变量的初始化初始化/赋初值赋初值建立指针建立指针 指针变量在定义的同时,也可以被赋予初值,初始化时指针变量在定义的同时,也可以被赋予初值,初始化时赋予它的初值必须是地址量赋予它的初值必须是地址量: *指针名指针名=初始地址值初始地址值;例如:例如: int *pa=&am
11、p;a;它把变量它把变量a a的地址作为初值赋给了的地址作为初值赋给了intint型指针型指针papa。注意注意:从表面上看,似乎把一个初始地址量赋给了指针的目从表面上看,似乎把一个初始地址量赋给了指针的目标变量标变量* *papa。其实不然,初始化形式中。其实不然,初始化形式中* *pa=&apa=&a不是一个运算表不是一个运算表达式,而是一个说明性语句,说明指针达式,而是一个说明性语句,说明指针papa的值等于的值等于a a的地址。的地址。等价于等价于int *pa;pa=&a;指针的类型中包含哪些信指针的类型中包含哪些信息?息?int* * 指针自指针自身类型身类
12、型目标变目标变量类型量类型2/132/13 下面的例子是把变量下面的例子是把变量n n的地址赋予指针的地址赋予指针p p,并且把已经,并且把已经初初始化好的指针始化好的指针p p赋给指针赋给指针q:q: int n; int *p=&n; int *q=p; 指针变量中只能存放地址,不要将一个整型量赋给一个指针变量中只能存放地址,不要将一个整型量赋给一个指针变量,下面的赋值是不合法的:指针变量,下面的赋值是不合法的: int *pointer=1000;下面的赋值合法但很危险下面的赋值合法但很危险 intint * *pointer=pointer=(intint * *)1000;1
13、000;1/141/14例例6.1 6.1 指针的概念指针的概念#include void main() int a; int *pa = & a ; /定义并建立指针定义并建立指针pa a = 10; printf(a:%dn,a); printf(*pa:%dn,*pa); printf(&a:%x(HEX)n,&a); printf(pa:%x(HEX)n,pa); printf(&pa:%x(HEX)n,&pa);运行结果:运行结果:a:10*pa:10&a:fff4(HEX)pa:fff4(HEX)&pa:fff2(HEX)注意
14、注意: 上述输出结果中,后三行上述输出结果中,后三行的结果每次运行时可能不一样,的结果每次运行时可能不一样,但第一行和第二行输出值应该是但第一行和第二行输出值应该是相等的。相等的。一旦建立指针一旦建立指针a a和和* *papa等价等价若未建立,则二者不若未建立,则二者不等价等价3/173/17例例 求地址量数据长度的程序求地址量数据长度的程序#include void main( ) / 定义字符串数组定义字符串数组str,定义一,定义一char型指针型指针ps指向它指向它 char str = abcdefghi, *ps = str; / 定义定义int型变量型变量i,并定义一个,并定义
15、一个int型指针型指针pi指向它指向它 int i = 6, * pi = &i; / 定义定义float型变量型变量f,定义一,定义一float型指针型指针pf指向它指向它 float f = 6.4f, *pf = &f; / 定义定义double型变量型变量d,和一,和一double型指针型指针pd指向它指向它 double d = 3.1415926, *pd = &d; printf(1) size of strings pointer is %d byte = %d bits.n, sizeof(ps), 8 * sizeof(ps); printf(2)
16、size of INTs pointer is %d bytes = %d bits.n, sizeof(pi), 8 * sizeof(pi); printf(3) size of FLOATs pointer is %d bytes = %d bits.n,sizeof(pf), 8 * sizeof(pf); printf(4) size of DOUBLEs pointer is %d bytes = %d bits.n, sizeof(pd), 8 * sizeof(pd); 该程序在该程序在Borland C+ V3.1上的运行结果为:上的运行结果为:(1) size of str
17、ings pointer is 2 byte = 16 bits.(2) size of INTs pointer is 2 bytes = 16 bits.(3) size of FLOATs pointer is 2 bytes = 16 bits.(4) size of DOUBLEs pointer is 2 bytes = 16 bits.等价于等价于sizeof(charsizeof(char * *)3/203/203. void指针(void *) voidvoid型指针变量:用来指向一种抽象数据的指针类型,但型指针变量:用来指向一种抽象数据的指针类型,但不指明它指向哪种具体的
18、数据类型,称为不指明它指向哪种具体的数据类型,称为“无类型指针无类型指针”。 定义的方法是在该指针变量的定义语句中,用定义的方法是在该指针变量的定义语句中,用voidvoid作为作为目标数据类型,即:目标数据类型,即: void * 指针变量名指针变量名; 定义时目标数据类型指定为定义时目标数据类型指定为voidvoid型,则可以将已定义的各种类型指型,则可以将已定义的各种类型指针直接赋给针直接赋给voidvoid型指针型指针; ;将将voidvoid型指针赋给其他各种类型指针时,型指针赋给其他各种类型指针时,必须必须采用强制类型转换,将它变成指向相应数据类型的指针。采用强制类型转换,将它变成
19、指向相应数据类型的指针。抽象指针抽象指针 定义抽象指针的目的?定义抽象指针的目的? 2/222/226.2.2 6.2.2 指针的使用指针的使用1. 取地址运算符取地址运算符&和取内容运算符和取内容运算符*(1).(1).取地址运算符取地址运算符& & 单目单目& &是取地址运算符,单目是取地址运算符,单目& &运算表达式的形式为:运算表达式的形式为: & &变量变量例:设变量说明为例:设变量说明为 int x; char y; double z;则地址表达式则地址表达式&x&x,&y&y和
20、和&z&z的结果的结果类型分别为:类型分别为: intint* *(整型指针),(整型指针), charchar* *(字符型指针)(字符型指针) doubledouble* *( (双精度浮点型指针双精度浮点型指针) )。1/231/23 由于数组名和常量不是左值表达式,而寄存器变量没由于数组名和常量不是左值表达式,而寄存器变量没有存储地址,因此数组名、常量和寄存器变量均不能做单目有存储地址,因此数组名、常量和寄存器变量均不能做单目& &的操作对象。的操作对象。 例:设变量说明为例:设变量说明为 intint i ,a 4; i ,a 4; register
21、int register int k k;&i&i,&ai&ai ,&a0&a0(或(或a a):):合法合法的地址表达式的地址表达式其类型均为其类型均为intint* *(整型指针)。(整型指针)。&k&k,&a&a :非法非法1/241/24(2 2)指针运算符)指针运算符 * * 单目单目* *是是间接访问运算符间接访问运算符。通过指针间接访问指针所指。通过指针间接访问指针所指对象(即目标变量),而不是通过变量名字访问变量,称为对象(即目标变量),而不是通过变量名字访问变量,称为间接访问。间接访问。间接访问的
22、表示形式为:间接访问的表示形式为: * 指针指针 例如:例如: char c, char c, * *pc = &c;pc = &c; * *(&c) = (&c) = aa; * *pc = pc = aa; c = c = aa;取目标变量内容的运算符取目标变量内容的运算符2/262/26(3 3)单目)单目* *和和 & &的运算关系的运算关系 单目单目* *和和 & &互为逆运算,它们之间的运算关系可表达为:互为逆运算,它们之间的运算关系可表达为: *(& 左值表达式左值表达式) 等价于等价于 左值表达式左值表达式
23、 &(*地址表达式地址表达式) 等价于等价于 地址表达式地址表达式上面两个式子上面两个式子表明表明: 二者为互逆运算。二者为互逆运算。但要注意:但要注意:& &后面必须跟随变量名后面必须跟随变量名* *后面必须跟随指针(常量或变量均可)后面必须跟随指针(常量或变量均可)1/271/272. 2. 指针的正确用法指针的正确用法 使用指针的使用指针的正确方法正确方法是:是:(1) 必须按被间接访问变量的类型来定义指针变量;必须按被间接访问变量的类型来定义指针变量;(2)必须用被间接访问变量的地址给指针变量赋值(或用指必须用被间接访问变量的地址给指针变量赋值(或用指针变量初始
24、化方式),使指针指向确定的目标对象,针变量初始化方式),使指针指向确定的目标对象,(3)然后才能使用指针来引用变量。然后才能使用指针来引用变量。 下面这个代码段说明了一个下面这个代码段说明了一个极为常见的错误极为常见的错误: intint * *p;p; * *p = 5;p = 5;没有办法预测没有办法预测5 5这个值存放在什么地方这个值存放在什么地方, ,也不会也不会“创建创建”用于用于存存储整型值储整型值5 5的内存空间。的内存空间。3/303/30通常定义时不确定通常定义时不确定指向时,暂时赋指向时,暂时赋值为值为NULLNULL 3.NULL3.NULL指针指针 NULLNULL指针
25、的概念是非常有用的。它提供了一种方法,指针的概念是非常有用的。它提供了一种方法,表表示某个特定的指针目前并未指向任何目标变量。示某个特定的指针目前并未指向任何目标变量。 ANSI C+ANSI C+标准定义标准定义NULLNULL指针,它作为指针变量的一个特指针,它作为指针变量的一个特殊状态,表示不指向任何东西。要使一个指针变量为殊状态,表示不指向任何东西。要使一个指针变量为NULLNULL,可以给它赋一个零值。可以给它赋一个零值。为了测试指针变量是否为为了测试指针变量是否为NULLNULL,可以将它和零进行比较。,可以将它和零进行比较。NULLNULL指针并未指向任何东西,对一个指针并未指向
26、任何东西,对一个NULLNULL指针进行取内容指针进行取内容运算运算* *是非法的,在对指针进行取内容运算是非法的,在对指针进行取内容运算* *之前,首先必须之前,首先必须确保它并非确保它并非NULLNULL指针。指针。1/311/316.3 指针运算指针运算 由于指针是持有地址的变量这一特性,指针的运算与某由于指针是持有地址的变量这一特性,指针的运算与某些普通变量的运算在种类上和意义上都是不同的。指针运算些普通变量的运算在种类上和意义上都是不同的。指针运算的种类是有限的,它只能进行:的种类是有限的,它只能进行: 算术运算算术运算 关系运算关系运算 赋值运算赋值运算6.3.1 6.3.1 指针
27、的算术运算指针的算术运算 不是简单的不是简单的+ -+ -* */ /运算,其结果与指针的类型有关,准确地运算,其结果与指针的类型有关,准确地说说是与指针类型中的目标数据类型(即去掉一个是与指针类型中的目标数据类型(即去掉一个* *后的类型)后的类型)有关。有关。 设设p1p1和和p2p2是是指向具有相同数据类型指向具有相同数据类型的一组数据的指针变量,的一组数据的指针变量,n n是整数,则指针可以进行的算术运算有如下几种是整数,则指针可以进行的算术运算有如下几种: p1+n, p1-n, p1+, +p1, p1-, -p1, p1-p23/343/341. 1. 指针与整数的加减运算指针与
28、整数的加减运算 指针作为地址加上或减去一个整数指针作为地址加上或减去一个整数n n,仍为一个指针,仍为一个指针含义:含义:以指针当前指向位置为基准,向高地址端或低地址以指针当前指向位置为基准,向高地址端或低地址端跳过端跳过n n个目标类型对象后,得到一个新的指向。个目标类型对象后,得到一个新的指向。 *(px-2) *(px-1) *px *(px+1) *(px+2) *(px+3) px-2 px-1 px px+1 px+2 px+3 *(py-1) *py *(py+1) *(py+2) py-1 py py+1 py+2 Short *px; Long *py; 3/373/37各种
29、指针变量进行加各种指针变量进行加1 1运算后的地址变化量运算后的地址变化量 指针类型指针类型指针加指针加1运算后的地址变化量运算后的地址变化量char * ptr;1short *ptr;2signed short *ptr;2unsigned short *ptr;2int *ptr;2signed int *ptr;2unsigned int*ptr;2longint*ptr; 4signed long int*ptr;4unsigned long int *ptr;4float *ptr;4double *ptr;8long double *ptr;102. 2. 指针自增、自减运算指针
30、自增、自减运算 指针指针+、-单目运算也是地址计算单目运算也是地址计算,它具有上,它具有上述的计算特点,指针的述的计算特点,指针的+、-单目运算是单目运算是指针变量本指针变量本身值的变化,变化前指向某个对象,变化后将指向另身值的变化,变化前指向某个对象,变化后将指向另一个对象一个对象。指针。指针+运算后就指向了下一个同运算后就指向了下一个同类型数据的位置,类型数据的位置,- - -运算后就指向上一个同类型数运算后就指向上一个同类型数据的位置。运算后指针变量本身值的变化量取决于它据的位置。运算后指针变量本身值的变化量取决于它指向的目标数据类型。指向的目标数据类型。 3/403/40例如,指针例如
31、,指针pxpx指向指向intint型(型(2 2字节长)数据,字节长)数据,pypy的内容假设为的内容假设为地址值地址值f000f000,当执行,当执行pxpx+后,后,pypy的内容加的内容加2 2,成为,成为f002f002,它是下一个数据的地址。指针加一前后的变化如图所示它是下一个数据的地址。指针加一前后的变化如图所示: : *px px int *px; F000 F000 F001 F002 F003 F004 F005 px小 F002 *px px+ +; F000 F001 F002 F003 F004 F005 *(px-1) 3/433/43 y= * px+; 相当于:
32、y= * (px+); 但要注意,不是先移动但要注意,不是先移动pxpx指针,再取其指向的指针,再取其指向的目标!目标!这里是后置运算。因此该表达式的运算顺序是,访问当前指针指向的目标,把目标变量的值赋予y,然后,px加1后得到新的px值,指向下一个目标。 2/452/45 【例【例】看一个用指针运算实现字符串复制函数的程序的例子看一个用指针运算实现字符串复制函数的程序的例子:char *strcpy(char *dest, char *src) char *temp=dest; while( (*dest+=*src+)!=0 ); return temp; /返回目的字符串的首地址返回目的
33、字符串的首地址 这是标准函数库中的函数,函数体中使用了指针后置运算:这是标准函数库中的函数,函数体中使用了指针后置运算: (*dest+=*src+)!=0; 运算过程:运算过程:把把srcsrc的目标变量的值赋予的目标变量的值赋予destdest的目标变量,然后判断赋值表达的目标变量,然后判断赋值表达式的结果值,即赋的值是否不等于式的结果值,即赋的值是否不等于00。destdest和和srcsrc的值使用后执的值使用后执行加一运算,分别指向下一个目标。函数中循环体是空语句。行加一运算,分别指向下一个目标。函数中循环体是空语句。5/505/503. 3. 指针的相减指针的相减 设指针设指针p
34、p和和q q是指向同一组数据类型一致的数据,则是指向同一组数据类型一致的数据,则p-qp-q运算的结果值是两指针指向的地址位置之间的数据个运算的结果值是两指针指向的地址位置之间的数据个数数。由此看出,。由此看出,两指针相减实质上也是地址计算两指针相减实质上也是地址计算。它执行。它执行的运算不是两指针持有的地址值相减,而是按下列公式得的运算不是两指针持有的地址值相减,而是按下列公式得出结果:出结果:)(q)(p)psizeof 式中(式中(p p)和()和(q q)分别表示指针)分别表示指针p p和和q q的地址值,所以,的地址值,所以,两指针相减的结果值不是地址量,而是一个整数。两指针相减的结
35、果值不是地址量,而是一个整数。 3/533/53例例6.3 统计输入字符串的字符个数统计输入字符串的字符个数#include void main() char s20; char * p; printf (“Enter a string (less than 20 characters):n”); scanf (“ %s”,s); p=s; /将字符指针指向字符数组的入口将字符指针指向字符数组的入口 while (*p!=0) /逐个移动字符指针直到字符串结束逐个移动字符指针直到字符串结束 p+; printf (“The string length:%dn”,p-s) ; /p-s就是字符串
36、的长度就是字符串的长度运行结果运行结果: :Enter a string (less than 20 Enter a string (less than 20 characters):characters):abcdefghiabcdefghiThe string length :9The string length :94/574/57程序运行过程示意图如图所示:1/581/586.3.2 6.3.2 关系运算关系运算 两个两个指向同一组类型相同数据的指针指向同一组类型相同数据的指针之间可以进行各种关系运算。之间可以进行各种关系运算。两指针之间的关系运算表示它们指向的地址位置之间的关系两指针
37、之间的关系运算表示它们指向的地址位置之间的关系。 对于两指针对于两指针p1p1和和p2p2间的关系表达式间的关系表达式: : p1p2若若p1p1指向高地址空间,指向高地址空间,p2p2指向低地址空间,该表达式结果值为指向低地址空间,该表达式结果值为1 1,反之为,反之为0 0。两指针相等的概念是两指针指向同一位置两指针相等的概念是两指针指向同一位置。 指向不同数据类型的指针之间的关系运算是没有意义的。指针与一指向不同数据类型的指针之间的关系运算是没有意义的。指针与一般整数变量之间的关系运算也是无意义的。般整数变量之间的关系运算也是无意义的。指针的有效性判断:指针的有效性判断: 指针可以和指针
38、可以和NULLNULL指针之间进行等于或不等于的关系运算,即指针之间进行等于或不等于的关系运算,即: : p=NULL或或p!=NULL它们用于判断指针它们用于判断指针p p是否为一个空指针。是否为一个空指针。2/602/60(void (void * *)0)0)6.3.3 6.3.3 指针的赋值运算指针的赋值运算 向指针变量赋值时,赋的值必须是地址常量或同类向指针变量赋值时,赋的值必须是地址常量或同类型的其他指针变量,不能是整数。指针赋值运算常见有型的其他指针变量,不能是整数。指针赋值运算常见有以下几种形式以下几种形式: :(1 1)把一个变量的地址赋予一个指向相同数据类型的)把一个变量的
39、地址赋予一个指向相同数据类型的指针指针 例如:例如: char c, *pc; pc=&c;6.3.3 6.3.3 指针的赋值运算指针的赋值运算 向指针变量赋值时,赋的值必须是地址常量或同类向指针变量赋值时,赋的值必须是地址常量或同类型的其他指针变量,不能是整数。指针赋值运算常见有型的其他指针变量,不能是整数。指针赋值运算常见有以下几种形式以下几种形式: :(1 1)把一个变量的地址赋予一个指向相同数据类型的)把一个变量的地址赋予一个指向相同数据类型的指针指针 例如:例如: char c, *pc; 正确:正确: pc=&c;错误:错误:int i;char *pc;pc=&a
40、mp;i;(3 3)把数组的入口地址赋予指向相同数据类型的指)把数组的入口地址赋予指向相同数据类型的指针针例如:例如: char name20, char name20, * *pname; pname; pnamepname=name;=name;(2 2)把一个指针的值赋予指向相同数据类型的另一)把一个指针的值赋予指向相同数据类型的另一个指针个指针 例如:例如: intint i, i,* *p, p, * *q;q; q=&i;q=&i; /q/q指向一个确定目标指向一个确定目标i ip=q;p=q;10/7010/70(4 4)动态内存分配)动态内存分配 在在C+C+中
41、,对于定义的每一个变量,系统都自中,对于定义的每一个变量,系统都自动在计算机中分配一个或多个字节单元以存放将要动在计算机中分配一个或多个字节单元以存放将要保存的变量值。保存的变量值。 当程序所要处理的某种数据无法确定其数据量时,便需要在程序运行期间动态地分配存储空间,所以我们要在程序的运行过程中,现场判断实际数据的数据量,并分配内存;当处理完所要处理的数据时,再将这些内存释放。 为了实现动态存储技术,标准函数库特设置了一对标准函数,它们的原型在malloc.h中并用到stdlib.h。因此,在使用它们的程序开头处,必须写有: #include #include /或malloc.h(VC6)
42、它们的原型是: void * malloc(unsigned size); void free(void * ptr); 2/722/721 1)由由mallocmalloc( )( )函数所分配的内存空间放在数据区的堆函数所分配的内存空间放在数据区的堆 (HeapHeap)中)中。如图所示。如图所示: :程序代码区程序代码区存放外部变量和存放外部变量和静态变量静态变量堆区堆区存放自动变量存放自动变量和函数的形参和函数的形参数据区数据区栈区栈区静态存储区静态存储区动态存储区动态存储区2 2) mallocmalloc( )( )函数有一个无符号整数型的形参函数有一个无符号整数型的形参sizes
43、ize,用来指定所分配内存空间的大小(用来指定所分配内存空间的大小(以字节为单位给以字节为单位给出出)。)。 对字符串都是采用表达式对字符串都是采用表达式“strlenstrlen(“(“字符串字符串”) ) + 1”+ 1”或或 “ “strlenstrlen( (指向字符串的指针指向字符串的指针) + 1”) + 1”作为作为实参。实参。其中,加其中,加1 1个字节是用来存放字符串的结尾符个字节是用来存放字符串的结尾符00。2/722/723)3)当当mallocmalloc( )( )函数执行成功时,其函数执行成功时,其返回值是大小为返回值是大小为sizesize的内的内存空间首地址存空
44、间首地址,可采用地址赋值操作把它的返回值赋给一个指,可采用地址赋值操作把它的返回值赋给一个指向相同数据类型的指针变量,这样就生成了一个新的变量,称向相同数据类型的指针变量,这样就生成了一个新的变量,称为为“动态变量动态变量”,该指针变量名就是动态变量名;,该指针变量名就是动态变量名;当它当它执行失败时将返回一个空指针执行失败时将返回一个空指针。因此在使用。因此在使用mallocmalloc( )( )函函数时,必须检测其返回值不为空指针,不然可能因堆区的内存数时,必须检测其返回值不为空指针,不然可能因堆区的内存资源耗尽而出错。其一般格式为:资源耗尽而出错。其一般格式为:if(指针名指针名 =
45、(类型类型 * )malloc(空间大小空间大小) = NULL) 出错处理操作出错处理操作 或简化写成:或简化写成:if( ! (指针名指针名 = (类型类型 * )malloc(空间大小空间大小) ) 出错处理操作出错处理操作 出错处理操作,常包含出错处理操作,常包含 exitexit(1 1););该动态变量又被称作该动态变量又被称作“匿名堆对匿名堆对象象”,指针是其等价名,要求指,指针是其等价名,要求指针值不能改变,一旦改变,则指针值不能改变,一旦改变,则指针不再作为匿名堆对象的等价名针不再作为匿名堆对象的等价名4/774/774 4)由于指针函数)由于指针函数mallocmalloc
46、( )( )的返回值是无类型指针的返回值是无类型指针(void (void * * 型型) ),把,把voidvoid型指针赋给其他各种非型指针赋给其他各种非voidvoid型型指针时,还指针时,还必须用强制类型转换,把它的数据类型转必须用强制类型转换,把它的数据类型转换成与换成与“指针名指针名”相同的数据类型。相同的数据类型。 5 5)free( )free( )函数用来释放由函数用来释放由mallocmalloc( )( )函数在堆区中所函数在堆区中所分配的内存空间分配的内存空间,以便这些内存空间成为再分配时的,以便这些内存空间成为再分配时的可用空间。可用空间。6 6)free( )fre
47、e( )函数的形参函数的形参ptrptr也是无类型指针,它专门用也是无类型指针,它专门用来接受来接受mallocmalloc( )( )函数在堆区中所分配的内存空间首函数在堆区中所分配的内存空间首地址,对其他地址量将不发生作用,因此,地址,对其他地址量将不发生作用,因此,free( )free( )函数是函数是mallocmalloc( )( )函数的配对物,即在整个源程序内,函数的配对物,即在整个源程序内,它们是成对出现的。它们是成对出现的。4/814/817 7)freefree仅仅回收堆对象所占空间的使用权,被仅仅回收堆对象所占空间的使用权,被freefree的堆对象原来的数据遗留在内存
48、中,不会被的堆对象原来的数据遗留在内存中,不会被清清0 0处理。一旦处理。一旦freefree成功执行,从那刻起被释放的成功执行,从那刻起被释放的内存空间即可能再次内存空间即可能再次部分或全部地部分或全部地被分配给另外被分配给另外的堆对象。因此,原有的的堆对象。因此,原有的“动态变量动态变量”将不存在,将不存在,对应的指针也将不再有意义。但指针变量仍然存对应的指针也将不再有意义。但指针变量仍然存在,其值仍然为原值,但已经变化成在,其值仍然为原值,但已经变化成“野指针野指针”。8 8)避免同一块堆空间被释放两次避免同一块堆空间被释放两次9 9)正确使用指向堆对象的指针变量)正确使用指向堆对象的指针变量ptrptr的规则的规则在在freefree之前之前ptrptr取值不能被修改,否则取值不能被修改,否则1 1、无法访问堆对象;、无法访问堆对象;2 2、无法、无法freefree释放,造成堆内存泄露(释放,造成堆内存泄露(memory leakmemory leak)freefree(ptrptr)后将)后将ptrptr赋值为赋值为NULLNULL4/854/85小小 结结 本章的掌握的内容有:本
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 装饰材料行业新技术应用考核试卷
- 锯材加工过程中的木材阻燃处理考核试卷
- 汽车语音识别与控制系统考核试卷
- 食物中毒院前急救
- 新生儿小肠坏死性结肠炎护理
- 麻醉药理学局部麻醉药
- 任务8.3+打造主播人设+课件-《互联网+推销实务》
- Methyltetrazine-amido-Tri-acid-PEG1-ethoxymethyl-methane-生命科学试剂-MCE
- 风格制胜3:风格因子体系的构建及应用
- 自然语言及语音处理项目式教程 课件7.2.2-2基于深度学习的语音合成算法
- 乳腺癌患者静脉管理
- 制造企业生产记录档案管理制度
- 急诊科临床诊疗指南-技术操作规范更新版
- 《接触网施工》课件 4.8.1 交叉线岔安装
- 艺术培训学校档案管理制度(3篇)
- 住院时间超过30天的患者管理与评价登记本
- 企业架构数字化转型规划
- 《中医基础理论》课程教案
- 2.1始终坚持以人民为中心 课件高中政治统编版必修三政治与法治
- 北师大版四年级下册小数乘法竖式计算200题及答案
- 【小升初】2023-2024学年贵州遵义市六年级下学期数学期末试题2套(含解析)
评论
0/150
提交评论