一、指向的内存空间 VS 对应的内存空间
以int *p = num 举例来说
num++:对num对应的内存空间的值加1
p++:对p对应的内存空间的值加1(加的是步长)
(*p)++:根据p对应的空间里保存的地址找到其对应的空间 = 对p指向的内存空间进行操作
从上面的例子可以总结出:
*p:操作的是p指向的内存空间
p:操作的是p对应的内存空间
二、一维指针、二维指针、三维指针及其间的关系
先来看一个整型变量的储存
0x1000 + 1 = 0x1001 加一个字节的长度
0x1000 + 1 = 0x1004 加一个指针的长度
在这里引出步长的概念,即指加上的数据类型的长度
1.一维指针
int *p = num
p保存的是整型变量的地址
p == &num
*p == num == *(&num)
2.二维指针
int *pp = &p
二维指针pp保存的是一维指针p的地址
p++:0x1000 --> 0x1004
(*pp)++:0x1000 --> 0x1004
pp++:0x2000 --> 0x2004
(**pp++):5 --> 6
因此可以总结出:
num = *p == **pp = *(&num)
&num = p = *pp
3.三维指针
int ***ppp = &pp
三维指针ppp保存的是二维指针pp的地址
(**ppp)++:0x1000 --> 0x1004
可以总结出:
num == *p == **pp == ***ppp == *(&num)
&num = p = *pp == **ppp
三、野指针
1.什么是野指针?
野指针是随机指向一块内存的指针,会导致内存泄漏
2.导致野指针的原因有哪些?
①在定义的时候没有初始化,系统随机分配一块内存,指针没有访问权限
②指向一块已经释放的内存
3.如何避免野指针?
野指针是无法完全避免的,只有平时养成良好的编码习惯才能有效的避免野指针
(1)在指针没有指向的时候,令其指向空
好处:①提醒我们不能对零地址进行操作
②方便寻找段错误
(2)给指针赋值时,使用malloc给指针分配空间
以用malloc分配100个字节为例:
#define MAX_SIZE 100
char *ptr = (char *)malloc(MAX_SIZE * sizeof(char));
malloc是在堆空间上分配,返回值为void *(万能指针:可以接收任何指针的值,但是不能做取值操作)
(char *):强制类型转换,转换成char型
sizeof(char):提高代码的移植性,因为不是所有操作平台上的char型都是1个字节
malloc的使用步骤:
①分配内存:(char *)malloc(MAX_SIZE * sizeof))
②检查是否分配成功
if(NULL == ptr)
{
printf(“malloc error:\n”);
exit(1);
}
③清空内存中的数据 memset/bzero
#define MAX_SIZE sizeof(char) *MAX_SIZE
memset(ptr,0,sizeof(char) * MAX_SIZE)
bzero(ptr,MAX_SIZE)
④使用内存
⑤释放内存 free(ptr)
⑥重新将指针置成NULL
四、指针的运算
1.指针 +/- 整数:跳指针所指向的数据类型的步长
2.指针 - 指针:两个地址相隔的数据的个数
五、动态分配函数malloc、realloc、calloc
1.malloc的实现原理
malloc()到底从哪里得到了内存空间?答案是从堆里面获得空间。也就是说函数返回的指针是指向堆里面的一块内存。操作系统中有一个记录空闲内存地址的链表。当操作系统收到程序的申请时,就会遍历该链表,然后就寻找第一个空间大于所申请空间的堆结点,然后就将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。
malloc()的工作机制:malloc函数的实质体现在,它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表。调用malloc函数时,它沿连接表寻找一个大到足以满足用户请求所需要的内存块。然后,将该内存块一分为二(一块的大小与用户请求的大小相等,另一块的大小就是剩下的字节)。接下来,将分配给用户的那块内存传给用户,并将剩下的那块(如果有的话)返回到连接表上。调用free函数时,它将用户释放的内存块连接到空闲链上。到最后,空闲链会被切成很多的小内存片段,如果这时用户申请一个大的内存片段,那么空闲链上可能没有可以满足用户要求的片段了。于是,malloc函数请求延时,并开始在空闲链上翻箱倒柜地检查各内存片段,对它们进行整理,将相邻的小空闲块合并成较大的内存块。
2.realloc和calloc的使用方法
①realloc
realloc原型是extern void *realloc(void *mem_address, unsigned int newsize);
使用格式:指针名=(数据类型*)realloc(要改变内存大小的指针名,新的大小)。
功能:给一个已经分配了地址的指针重新分配空间,先判断当前的指针是否有足够的连续空间,如果有,扩大mem_address指向的地址,并且将mem_address返回,如果空间不够,先按照newsize指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来mem_address所指内存区域(注意:原来指针是自动释放,不需要使用free),同时返回新分配的内存区域的首地址。即重新分配存储器块的地址。
内存使用完毕后,要用free()来释放
②calloc
calloc的函数原型:void *calloc(size_t n, size_t size);
使用格式:str = (char*)calloc(10,sizeof(char));
功能:在内存的动态存储区中分配n个长度为size的连续空间,同时会将分配的内存空间中每一位都置为0,函数返回一个指向分配起始地址的指针;如果分配不成功,返回NULL。
内存使用完毕后,同样需要用free()来释放
3.malloc、realloc、calloc的比较
①初始化内存:函数malloc不能初始化所分配的内存空间,而函数calloc能。使用malloc之后需要用memset或bzero将分配的内存空间置为0,而calloc在使用时就已经将内存初始化为0了
②realloc传入的指针必须是已经用malloc、calloc或realloc已经分配过内存的指针
③三个函数在内存使用完毕后都需要调用free()来释放