指针和数组(一维,二维,三维)以及野指针的避免
2016-07-19 19:18
357 查看
如何避免野指针?
答:①当指针未指向时,一般将指针置为空
②当想向指针指向空间赋值时,为其分配空间。当用malloc为其分配空间的时候,要看其是否分配成功(注意清空原来的缓冲区),函数执行完以后,需要用free(ptr),用完后再赋值为NULL(ptr=NULL)
初始化为NULL的目的:①该指向0地址,操作不能在0地址操作②当出现段错误的时候,容易改错,方便调试(NULL为宏,#define
NULL (void *)0代表0地址,0地址是不允许操作和访问的)
malloc分配空间:ptr=(char *)malloc(MAX_SIZE*sizeof(char))()加强制类型转换是为了:该必须是相同的
void *:表示万能指针(可接收任何指针类型,但不能进行取值,不能对地址指向空间操作)
指针-指针:计算两地址之间相差多少数据
数组 [ ]=*( )
一维数组(char *p=a)
①scanf(“%d”,&a[i]) scanf(“%d”,a+i) scanf(“%d”,p+i) scanf(“%d”,&p[i]) scanf(“%d”,p++)
②printf(“a[%d]=%d\n”,i,a[i]) printf(“a[%d]=%d\n”,i,*(a+i)) printf(“a[%d]=%d\n”,i,*(p+i)) printf(“a[%d]=%d\n”,i,p[i]) printf(“a[%\n”,i,*p++)
&a:对一维数组的数组名取地址等于数组的地址
*(&a):对一维数组的地址取值等于数组首元素的地址
(int (*pa)[MAX_SIZE]=&a)
二维数组(行可省略)
int a[i][j]
a代表首个一维数组的地址
①scanf(“%d”,&a[i][j]) printf(“a[%d][%d]=%d\n”,i,j,a[i][j])
②scanf(“%d”,*(a+i)+j) printf(“a[%d][%d]=%d\n”,i,j,*(*(a+i)+j)
传二维数组名用一维数组指针来接(void ch(char (*src)[100]))
*(*(a+i)+j)
a+i:第i+1个一维数组的地址
*(a+i):第i+1个一维数组的首元素地址
*(a+i)+j:第i+1个一维数组的第j+1个元素的地址
*(*(a+i)+j):第i+1个一维数组的第j+1个元素的值
三维数组(二维数组指针)
*(&a)=a:对二维数组的地址取值等于首个一维数组的地址
*(*(*(a+i)+j)+k)
a+i:第i+1个二维数组的地址
*(a+i):第i+1个二维数组的首个一维数组的地址
*(*(a+i)+j:第i+1个二维数组的第j+1个一维数组的首元素的地址
*(*(a+i)+j)+k:第i+1个二维数组的第j+1个一维数组的第k+1个元素的地址
*(*(*(a+i)+j+k):第i+1个二维数组的第j+1个一维数组的第k+1个元素的值
传指针数组时,用指针的指针:void print_ptr(char **ptr)
malloc,realloc,calloc的声明:
void* realloc(void* ptr, unsigned newsize);
void* malloc(unsigned size);
void* calloc(size_t numElements, size_t sizeOfElement);
分别什么时候使用?
malloc用于申请一段新的地址,参数size为需要内存空间的长度
calloc与malloc相似,参数sizeOfElement为申请地址的单位元素长度,numElements为元素个数
realloc是给一个已经分配了地址的指针重新分配空间,参数ptr为原有的空间地址,newsize是重新申请的地址长度
三者的区别:
malloc调用形式为(类型*)malloc(size):在内存的动态存储区中分配一块长度为“size”字节的连续区域,返回该区域的首地址。
calloc调用形式为(类型*)calloc(n,size):在内存的动态存储区中分配n块长度为“size”字节的连续区域,返回首地址。
realloc调用形式为(类型*)realloc(*ptr,size):将ptr内存大小增大到size。
malloc函数原理:
malloc函数有一个将可用的内存块连接为一个长长的列表的所谓空闲链表,调用malloc函数时,它沿连接表寻找一个大到足以满足用户请求所需要的内存块,然后将该内存块一分为二(一块的大小与用户申请的大小一样,另一块就是剩下的字节),接下来,将分配给用户的那块内存传给用户,并将剩下的那块(如果有的话),返回到链表上,调用free函数
时,它将用户释放的内存块连接到空链上,到最后,空闲链表会被切成很多的小内存片段,如果这时用户申请一个大的内存片段,那么空闲链上可能没有可能满足用户要求的片段了,于是malloc函数请求延时,并开始在空间中翻箱倒柜的检查内存片段,对它们进行整理,并将相邻的小空闲块合成较大的内存块
数组与指针的区别:
区间分配:
①数组要么在静态存储区被创建,要么在栈上被创建。数组名对应着一块内存,其地址与容量在生命期内保持不变,只有数组的内容可以改变。
指针可以随时指向任意类型的内存块,它的特征是“可变”,所以我们常用指针来操作动态内存。
②不能对数组名进行直接复制与比较
访问效率:
通过 a 访问,系统只需要计算常量 a 与 i*sizeof(type) 之和,然后访问该地址
通过 p 访问,p 是个变量,系统必须先访问 p 的地址,得到 p 的值,然后计算该值 v(p) 与 i*sizeof(type) 之和, 然后再访问得到的地址。
相比之下,指针要稍微慢一些,在绝大多数情况下,指针与数组相比,没有效率上的优势,有时反而更慢。指针的真正优势是灵活,好用。
函数传参:
数组在作为函数传参时,数组名将蜕化为指针,二维数组的存储方式是和一维数组没什么区别,但是用二维数组做参数,要注意的是:函数中的形参其实就相当于一个声明,并不产生内存分配,形参的目的就是要让编译器知道函数参数的数据类型
指针传参传递的是一参数(这里是Int实参)的地址,这样,虽然实参和形参不一样,但是它们只想的地址是一样的,所以对相同地址的数的操作会影响到原来的数。
安全性:
指针可能会重复释放,而且会产生野指针,从而导致内存的泄漏;也有可能导致堆缓冲区溢出
答:①当指针未指向时,一般将指针置为空
②当想向指针指向空间赋值时,为其分配空间。当用malloc为其分配空间的时候,要看其是否分配成功(注意清空原来的缓冲区),函数执行完以后,需要用free(ptr),用完后再赋值为NULL(ptr=NULL)
初始化为NULL的目的:①该指向0地址,操作不能在0地址操作②当出现段错误的时候,容易改错,方便调试(NULL为宏,#define
NULL (void *)0代表0地址,0地址是不允许操作和访问的)
malloc分配空间:ptr=(char *)malloc(MAX_SIZE*sizeof(char))()加强制类型转换是为了:该必须是相同的
void *:表示万能指针(可接收任何指针类型,但不能进行取值,不能对地址指向空间操作)
指针-指针:计算两地址之间相差多少数据
数组 [ ]=*( )
一维数组(char *p=a)
①scanf(“%d”,&a[i]) scanf(“%d”,a+i) scanf(“%d”,p+i) scanf(“%d”,&p[i]) scanf(“%d”,p++)
②printf(“a[%d]=%d\n”,i,a[i]) printf(“a[%d]=%d\n”,i,*(a+i)) printf(“a[%d]=%d\n”,i,*(p+i)) printf(“a[%d]=%d\n”,i,p[i]) printf(“a[%\n”,i,*p++)
&a:对一维数组的数组名取地址等于数组的地址
*(&a):对一维数组的地址取值等于数组首元素的地址
(int (*pa)[MAX_SIZE]=&a)
二维数组(行可省略)
int a[i][j]
a代表首个一维数组的地址
①scanf(“%d”,&a[i][j]) printf(“a[%d][%d]=%d\n”,i,j,a[i][j])
②scanf(“%d”,*(a+i)+j) printf(“a[%d][%d]=%d\n”,i,j,*(*(a+i)+j)
传二维数组名用一维数组指针来接(void ch(char (*src)[100]))
*(*(a+i)+j)
a+i:第i+1个一维数组的地址
*(a+i):第i+1个一维数组的首元素地址
*(a+i)+j:第i+1个一维数组的第j+1个元素的地址
*(*(a+i)+j):第i+1个一维数组的第j+1个元素的值
三维数组(二维数组指针)
*(&a)=a:对二维数组的地址取值等于首个一维数组的地址
*(*(*(a+i)+j)+k)
a+i:第i+1个二维数组的地址
*(a+i):第i+1个二维数组的首个一维数组的地址
*(*(a+i)+j:第i+1个二维数组的第j+1个一维数组的首元素的地址
*(*(a+i)+j)+k:第i+1个二维数组的第j+1个一维数组的第k+1个元素的地址
*(*(*(a+i)+j+k):第i+1个二维数组的第j+1个一维数组的第k+1个元素的值
传指针数组时,用指针的指针:void print_ptr(char **ptr)
malloc,realloc,calloc的声明:
void* realloc(void* ptr, unsigned newsize);
void* malloc(unsigned size);
void* calloc(size_t numElements, size_t sizeOfElement);
分别什么时候使用?
malloc用于申请一段新的地址,参数size为需要内存空间的长度
calloc与malloc相似,参数sizeOfElement为申请地址的单位元素长度,numElements为元素个数
realloc是给一个已经分配了地址的指针重新分配空间,参数ptr为原有的空间地址,newsize是重新申请的地址长度
三者的区别:
malloc调用形式为(类型*)malloc(size):在内存的动态存储区中分配一块长度为“size”字节的连续区域,返回该区域的首地址。
calloc调用形式为(类型*)calloc(n,size):在内存的动态存储区中分配n块长度为“size”字节的连续区域,返回首地址。
realloc调用形式为(类型*)realloc(*ptr,size):将ptr内存大小增大到size。
malloc函数原理:
malloc函数有一个将可用的内存块连接为一个长长的列表的所谓空闲链表,调用malloc函数时,它沿连接表寻找一个大到足以满足用户请求所需要的内存块,然后将该内存块一分为二(一块的大小与用户申请的大小一样,另一块就是剩下的字节),接下来,将分配给用户的那块内存传给用户,并将剩下的那块(如果有的话),返回到链表上,调用free函数
时,它将用户释放的内存块连接到空链上,到最后,空闲链表会被切成很多的小内存片段,如果这时用户申请一个大的内存片段,那么空闲链上可能没有可能满足用户要求的片段了,于是malloc函数请求延时,并开始在空间中翻箱倒柜的检查内存片段,对它们进行整理,并将相邻的小空闲块合成较大的内存块
数组与指针的区别:
区间分配:
①数组要么在静态存储区被创建,要么在栈上被创建。数组名对应着一块内存,其地址与容量在生命期内保持不变,只有数组的内容可以改变。
指针可以随时指向任意类型的内存块,它的特征是“可变”,所以我们常用指针来操作动态内存。
②不能对数组名进行直接复制与比较
访问效率:
通过 a 访问,系统只需要计算常量 a 与 i*sizeof(type) 之和,然后访问该地址
通过 p 访问,p 是个变量,系统必须先访问 p 的地址,得到 p 的值,然后计算该值 v(p) 与 i*sizeof(type) 之和, 然后再访问得到的地址。
相比之下,指针要稍微慢一些,在绝大多数情况下,指针与数组相比,没有效率上的优势,有时反而更慢。指针的真正优势是灵活,好用。
函数传参:
数组在作为函数传参时,数组名将蜕化为指针,二维数组的存储方式是和一维数组没什么区别,但是用二维数组做参数,要注意的是:函数中的形参其实就相当于一个声明,并不产生内存分配,形参的目的就是要让编译器知道函数参数的数据类型
指针传参传递的是一参数(这里是Int实参)的地址,这样,虽然实参和形参不一样,但是它们只想的地址是一样的,所以对相同地址的数的操作会影响到原来的数。
安全性:
指针可能会重复释放,而且会产生野指针,从而导致内存的泄漏;也有可能导致堆缓冲区溢出
相关文章推荐
- Proguard中optimize设置不当引发SimException
- 对象的比较排序
- 网页中高度的那些事
- Java进阶(三十四)Integer与int的种种比较你知道多少?
- Windows下搭建PHP开发环境
- burp suite实现映客直播下载
- 用create制作动画
- 删除Sybase数据库设备
- Java进阶(三十四)Integer与int的种种比较你知道多少?
- layui常用方法
- angular中的ng-class的几种常用方式
- 仅此记录所学所感
- C语言高级指针
- 数论基础定理及其应用(hdu 2685 I won't tell you this is about number theory, hdu 2582 f(n),hdu 1792 A New Chan)
- 抽象,接口,final,多态
- 复杂链表的复制
- easyui加载datagrid和treegrid的几种json数据格式
- PAT 1001 Public Bike Management
- 什么是Ajax无刷新技术?
- 20160713 程序流程控制