您的位置:首页 > 其它

指针和数组(一维,二维,三维)以及野指针的避免

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实参)的地址,这样,虽然实参和形参不一样,但是它们只想的地址是一样的,所以对相同地址的数的操作会影响到原来的数。

安全性:

指针可能会重复释放,而且会产生野指针,从而导致内存的泄漏;也有可能导致堆缓冲区溢出
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: