数组与指针ppt课件.ppt
,数组与指针,1.空间分类2.为什么用指针3.指针的定义及使用方式4.指针的访问方式(即变量操作的本质)5.数组同指针的关系6.数组和指针作为函数的参数和返回值,栈空间堆空间,空间分类,数组-物理空间存放的本质,定义数组就是申请了一块连续的内存空间。用户可操作的空间大小等于数组元素*每个元素所占的空间大小。数组元素连续存放在这块空间中。如:int intarray5;占用了20个字节,因为每个整型数占四个字节。如给intarray3赋值为3,如果这块空间的起始地址为100,那么在内存中的情况是:当你引用变量intarrayidx时,系统计算它的地址100+idx*4,对该地址的内容进行操作。,参照几何坐标系,数组下标超界问题,C/C+语言不检查数组下标的超界。如定义数组 int intarray10;合法的下标范围是0 9,但如果你引用intarray10,系统不会报错。如数组intarray 的起始地址是1000,当引用intarray10时,系统对1040号内存进行操作。而1040可能是另一个变量的地址解决方法(1)由程序员自己控制。在对下标变量进行操作前,先检查下标的合法性。(2)利用容器等,数组的缺点,必须知道数组的确定类型和空间大小,才能定义数组。数组的大小受到栈大小的限制。通常栈的大小是2M。,指针的概念,如在某一程序中定义了 int x=2;如系统给x分配的空间是1000号单元,则指向x的指针是另一个变量p,p中存放的数据为10001000号单元的内容有两种访问方式:访问变量x(直接访问)访问变量p指向的单元的内容(间接访问),定义指针变量,定义指针变量要告诉编译器该变量中存放的是一个地址。指针变量的主要用途是提供间接访问,因此也需要知道指针指向的单元的数据类型指针变量的定义 类型标识符*指针变量;如:int*intp;double*doublep;int*p,x,*q;,类型标识符的作用?,指针变量的操作,如何让指针指向某一变量?因为我们不知道系统分配给变量的真正地址是什么。用取地址运算符“&运算符后面不能跟常量或表达式。如&2 是没有意义的,&(m*n+p)。也是没有意义的如何通过指针变量处理和改变它所指向的单元的值?用地址解析运算符“*”解决。如*intp 表示的是 intp 指向的这个单元的内容。如:*intp=5 等价于 x=5在对 intp 使用引用运算之前,必须先对 intp 赋值,指针实例,如有:int X,*intp,Y;X=3;Y=4;intp=,如执行:*intp=Y+4;,注意:不能用 intp=100;因为我们永远不知道变量存储的真实地址,而且程序每次运行变量地址可能都不同。,指针使用,指针变量可以指向不同的变量。如上例中intp指向x,我们可以通过对intp的重新赋值改变指针的指向。如果想让intp指向y,只要执行intp=&y就可以了。这时,intp与x无任何关系。同类的指针变量之间可相互赋值,表示二个指针指向同一内存空间。空指针指针没有指向任何空间空指针用常量NULL表示,NULL的值一般赋为0不能引用空指针指向的值野指针(没有初始化的指针),指针变量的使用,设有定义 int x,y;int*p1,*p2;,执行语句:x=23;y=234;,执行语句:p1=,执行语句:*p1=34;p2=p1;,指针实例,有以下结构,比较执行 p1=p2和*p1=*p2后的不同结果。,指针的初始化,指针在使用前必须初始化。和别的变量一样,定义指针不初始化是一个比较普通的错误。没有初始化的指针可能指向任意地址,对这些指针作操作可能会导致程序错误(野指针)。NULL是一个特殊指针值,称为空指针。它的值为0。它可被用来初始化一个指针,表示不指向任何地址。,思考:int*p;*p=5;有什么问题?,指针与数组,在C+中,指针和数组关系密切,几乎可以互换使用数组名可以看成是常量指针,对一维数组来说,数组名是数组的起始地址,也就是第一个元素的地址如执行了p=array,则p与array是等价的,对该指针可以进行任何有关数组下标的操作,数组实际访问方式:C+语言的下标运算符 是以指针作为操作数的,fiboni被编译系统解释为*(fibon+i)即表示为fibon所指(固定不可变)元素向后第i个元素。无论以下标方式或指针方式存取数组元素时,系统都是转换为指针方法实现。,通过指针访问数组时,下标有效范围由程序员自己检查。,数组元素的指针表示,方法3:for(p=a;pa+10;+p)cout*p;,方法2:for(i=0;i10;+i)cout*(a+i);,方法1:for(i=0;i10;+i)cout ai;,方法4:for(p=a,i=0;i10;+i)cout*(p+i);,方法5:for(p=a,i=0;i10;+i)cout pi;,下列程序段 有无问题?for(i=0;i10;+i)cout*a;+a;,指针同样可以进行”+”,”-“运算,运算结果也是指向后一个或前一个数组元素。,*但是有”+”和”-”的表达式往往容易出错,必须小心使用,如:y=*pfib+;由于后”+”的优先级高于”*”,所以该表达式等效于y=*(pfib+),又因是后”+”,所以y中取值为*pfib,而pfib增1后指向下一个元素。这条语句在C+中是常用的。千万不可误解为将pfib所指目标增1。,动态内存分配,什么时候需要动态分配内存?实例:顺序对一批文件进行解析,但是不知道文件的大小,如何建立缓冲区?参看一个人脸检测的Ground Truth文件格式,C语言方法malloc函数原型:void*malloc(size_t n);n是要分配的内存的大小(字节为单位),返回值是分配内存的块的首地址,关键代码:int*array;array=(int*)malloc(10*sizeof(int);注意:单位,内存大小不能写成数组元素的个数,需要注意的问题(1)malloc函数是一个库函数,它并不是C语言中的关键字:需要头文件才可以使用该函数并不是所有的平台都可以使用该函数,尤其是一些单片机系统,free函数原型:void free(void*p);p是要释放的已分配内存的块的首地址,释放一块动态分配的内存:例如:int*p;p=(int*)malloc(sizeof(int);free(p);,动态内存申请与释放,中由new 和 delete两个运算符替代-运算符new用于进行内存申请:申请动态变量:p=new type;申请动态数组:p=new typesize;申请动态变量并初始化:p=new type(初值)-运算符delete 释放 new分配的内存:释放动态变量:delete p;释放动态数组:delete p;,/为简单变量动态分配内存,并作初始化int main()int*p;p=new int(99);/动态分配内存,并将99作为初始化值赋给它 cout*p;delete p;return 0;,动态内存申请与释放,/动态字符串的使用int main()int*p;char*q;p=new int(5);q=new char10;strcpy(q,abcde);cout*p endl;cout q endl;delete p;delete q;return 0;,输出结果:5abcde,动态分配的检查,new操作的结果是记录申请到的空间的起始地址及大小(隐式)当系统空间用完时,new操作可能失败new操作失败时,返回空指针/NULL,动态内存申请与释放,/动态分配检查int main()int*p;p=new int;if(p=NULL)/if(NULL=p)cout allocation failuren;return 1;*p=20;cout*p;delete p;return 0;,assert宏,assert()宏在标准头文件cassert中 assert()有一个参数,表示断言为真的表达式,预处理器产生测试该断言的代码。如果断言不是真,则在发出一个错误消息后程序会终止。,#include#include/包含assert宏的头文件int main()int*p;p=new int;assert(p!=0);/p等于0,则退出程序*p=20;cout*p;delete p;return 0;,内存分配的进一步介绍,静态分配:对全局变量和静态变量,编译器为它们分配空间,这些空间在整个程序运行期间都存在自动分配:函数内的局部变量空间是分配在系统的栈工作区。当函数被调用时,空间被分配;当函数执行结束后,空间被释放动态分配:在程序执行过程中需要新的存储空间时,可用动态分配的方法向系统申请新的空间,当不再使用时用显式的方法还给系统。这部分空间是从被称为堆的内存区域分配。,内存泄漏,动态变量是通过指针间接访问的。如果该指针被修改,这个区域就被丢失了。堆管理器认为你在继续使用它们,但你不知道它们在哪里,这称为内存泄露。为了避免出现孤立的区域,应该明白地告诉堆管理器这些区域不再使用。可以采用delete操作,它释放由new申请的内存。当释放了内存区域,堆管理器重新收回这些区域,而指针仍然指向堆区域,但不能再使用指针指向的这些区域。要确保在程序中同一个区域释放一次。释放内存对一些程序不重要,但对有些程序很重要。如果你的程序要运行很长时间,而且存在内存泄漏,这样程序会耗尽所有内存,直至崩溃。,动态空间分配示例,输入一批数据,计算它们的和。数据个数在设计程序时尚无法确定。存储一批数据应该用数组,但C+语言的数组大小必须是固定的。该问题有两个解决方案:开设一个足够大的数组,每次运行时只使用一部分。缺点:浪费空间用动态内存分配根据输入的数据量申请一个动态数组,#include int main()int*p,i,n,sum=0;cout n;p=new intn;if(p=NULL)return 1;for(i=0;i pi;for(i=0;in;+I)sum+=pi;cout Number of elements:n endl;cout Sum of the elements:sum endl;delete p;return 0;,作业,实现几个字符串操作函数,计算字符串长度字符串倒置比较字符串大小查找子串2.二阶矩阵操作矩阵加法矩阵减法矩阵乘法,个人项目一,简易目标检测(通过8位灰度图像处理)读取 保存自己设定阈值,二值化水平/垂直镜像放大缩小平滑滤波去噪声,Thanks!Q&A!,