堆空间
堆空间是由程序员手动申请和释放的,主要用到malloc函数和free函数。
1、malloc
#include <stdlib.h>
void *malloc(size_t size);
功能:在堆区开辟大小为size的空间
参数:size:开辟空间的大小,单位为字节。
返回值:
成功:返回开辟空间的首地址
失败:空指针NULL
代码格式:
type* var_name = (type *)malloc(sizeof(type)*n);
malloc内的参数是需要动态分配的字节数,而不是可以存储的元素个数!
2、free
#include <stdlib.h>
void free(void *ptr);
功能:释放之前用malloc、calloc和realloc所分配的内存空间。
参数:ptr:堆空间的首地址。
返回值:无
可以释放完堆空以后,把指针赋值为空指针:
free§;
p=NULL;
malloc和free搭配使用的代码:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
int *p=(int *)malloc(sizeof(int)*100);
if(p==NULL)
printf("lost!\n");
else
printf("success\n");
free(p);
p=NULL;
return 0;
}
3 经典错误代码
#include <stdio.h>
#include <stdlib.h>
void fun(char *p)
{
p= (char *)malloc(32);
scanf("%s",p);
}
int main(int argc, char const *argv[])
{
char *m=NULL;
fun(m);
printf("%s\n",m);
//free(m);
//m=NULL;
return 0;
}
m的指向一直是NULL;没有改变。P的指向一开始与m相同,然后把堆空间的首地址赋值给P,p的指向发生改变。
4 通过二级指针将堆空间的地址从子函数传递到main()函数
#include <stdio.h>
#include <stdlib.h>
void fun(char **p)
{
*p = (char *)malloc(32);
scanf("%s", *p);
}
int main(int argc, char const *argv[])
{
char *m=NULL;
fun(&m);
printf("%s\n",m);
free(m);
m=NULL;
return 0;
}
假设m的地址即&m=0x1000; 开辟的堆空间地址0x2000
头开始一个二级指针p指向m,m的指向为NULL,p=&m=0x1000。
*p=*(0x1000) 开辟堆空间时,*p=0x2000,-> *(0x1000)=0x2000,即这个时候m也指向了这片堆空间的首地址,所以在主函数中可以打印堆空间中的内容。
5通过返回值
#include <stdio.h>
#include <stdlib.h>
char *fun()
{
char *p= (char *)malloc(32);
scanf("%s",p);
return p;
}
int main(int argc, char const *argv[])
{
char *m=fun();
char *n=fun();
printf("%s\n",m);
printf("%s\n",n);
free(m);
m=NULL;
free(n);
n=NULL;
return 0;
}
这个很好理解,就是把堆空间的首地址返回给主函数,在主函数中由m接受。
图1 图2
在图1中会报段错误,因为str的指向始终没变 图2这个char p[]是个局部数组变量,把hello world的字符串存到这个数组中,该函数执行完return p后,把该数组的地址传给主函数中的str,但是该数组空间已经被释放掉了,里面为空,所以取不到字符串。
图3 图4
在图3中可以正常打印 图4中该堆空间被free调之后,并没有及时把指针str的指向置空NULL,所以还是指向该堆空间的首地址,所以world会打印出来,但是实际上该进程已经没有对该空间的操作权限了,如果有其他进程在赋值world之前,往这里面写入东西,该进程会把写入的东西用world覆盖掉,所以这样用是不可以的。