部分转载自
https://blog.csdn.net/qq_29924041/article/details/54897204
和小甲鱼数据结构课程
内存布局规律:
malloc 申请动态内存空间
void *malloc(size_t size);
malloc函数向系统申请分配size个字节的内存空间,并返回一个指向这空间的指针
void *,表示未确定类型的指针。
C,C++规定,void *类型可以强转为任何其他类型的的指针。
如果分配成功:则返回指向被分配内存空间的指针
不然,返回空指针NULL。
同时,当内存不再使用的时候,应使用free()函数将内存块释放掉。
void malloc1()
{
int *ptr;
ptr = (int *)malloc(sizeof(int));
if (ptr == NULL)
{
printf("失败\n");
exit(1);
}
printf("输入一个整数\n");
scanf("%d",ptr);
printf("%d\n",*ptr);
}//malloc申请的内存在堆上,不使用后要释放
//malloc还可以申请一块任意尺寸的内存空间
void malloc2()
{
int *ptr=NULL;
int i,num;
printf("请输入待录入整数个数: \n");
scanf("%d",&num);
ptr=(int *)malloc(num*sizeof(int));
for(i=0;i<num;i++)
{
printf("请录入第%d个整数:",i+1);
scanf("%d",&ptr[i]);
}
printf("你录入的整数是:");
for(i=0;i<num;i++)
{
printf("%d",ptr[i]);
}
putchar('\n');
free(ptr);
}
free 释放动态内存空间
void free(void *ptr);
free() 可以释放由 malloc()、calloc()、realloc() 分配的内存空间,以便其他程序再次使用。
【参数说明】ptr 为将要释放的内存空间的地址。
free() 只能释放动态分配的内存空间,并不能释放任意的内存。
如果 ptr 所指向的内存空间不是由上面的三个函数所分配的,或者已被释放,那么调用 free() 会有无法预知的情况发生。
如果 ptr 为 NULL,那么 free() 不会有任何作用。
注意:free() 不会改变 ptr 变量本身的值,调用 free() 后它仍然会指向相同的内存空间,但是此时该内存已无效,不能被使用。所以建议将 ptr 的值设置为 NULL
void malloc1()
{
int *ptr;
ptr = (int *)malloc(sizeof(int));
if (ptr == NULL)
{
printf("失败\n");
exit(1);
}
printf("输入一个整数\n");
scanf("%d",ptr);
printf("%d\n",*ptr);
free(ptr);
printf("%d\n",*ptr);
}
内存泄露:
导致内存泄漏主要有两种情况:
隐式内存泄漏(即用完内存块没有及时使用free函数释放)
丢失内存块地址
用了内存后要释放,malloc和free要像大括号一样,有左就有右
初始化内存空间
由于 malloc 并不会帮你初始化申请的内存空间,所以你需要自己进行初始化。
当然你可以写一个循环来做这件事儿,但我不建议你这么做,因为标准库提供了更加高效的函数:memset。
以mem开头的函数被编入字符串标准库,函数的声明包含在string.h这个头文件中:
-memset --使用一个常量字节填充内存空间,初始化函数
#define N 10
int memset1(void)
{
int *ptr=NULL;
int i;
ptr = (int*)malloc(sizeof(int));
if(ptr == NULL)
exit(1);
memset(ptr,0,N*sizeof(int))//初始化,指向要初始化的内存块,初始化常量,内存块连续尺寸
for(i=0;i<N;i++)
{
printf("%d ",ptr[i]);
}
free(ptr);
}
-memcpy --拷贝内存空间
-memmove–拷贝内存空间
-memcmp --比较内存空间
-memchr --在内存空间中搜索一个字符
处理字符串用str开头,处理内存空间用mem开头
calloc 申请并初始化一系列内存空间
void *calloc(size_t nmemb, size_t size);
比malloc多个初始化,此函数申请完空间后会把内存空间全部初始化为0
//如果想扩大空间可用memcpy
void memcpy1()
{
int *ptr1=NULL;
int *ptr2=NULL;
//第一次申请的内存空间
ptr1=(int *)malloc(sizeof(int));
//ptr1空间不够用
//第二次申请内存空间
ptr2= (int *)malloc(sizeof(int));
//将ptr1的数据拷贝到ptr2
memcpy(ptr2,ptr1,10);//目标,源,拷贝数量
free(ptr1);
//ptr2操作后
free(ptr2);
}
realloc 重新分配内存空间,与上有相同功能
void *realloc(void *ptr, size_t size);
函数概要:
- realloc 函数修改 ptr 指向的内存空间大小为 size 字节。
- 如果新分配的内存空间比原来的大,则旧内存块的数据不会发生改变;如果新的内存空间大小小于旧的内存空间,可能会导致数据丢失,慎用!
- 该函数将移动内存空间的数据并返回新的指针。
- 如果 ptr 参数为 NULL,那么调用该函数就相当于调用 malloc(size)。
- 如果 size 参数为 0,并且 ptr 参数不为 NULL,那么调用该函数就相当于调用 free(ptr)。
- 除非 ptr 参数为 NULL,否则 ptr 的值必须由先前调用 malloc、calloc 或 realloc 函数返回。
参数解析:
参数 含义
ptr 1. 指向由先前调用 malloc、calloc 或 realloc 函数返回的内存空间
2. 如果该参数为 NULL,相当于调用 malloc(size) 函数
size 指定新的内存块空间大小,以字节为单位
返回值:
- 如果函数调用成功,返回值是指向新的内存空间的指针,由于返回类型是 void 指针(void *),所以它可以被转换成任何类型的数据。
- 如果函数调用失败,返回值是 NULL。
- 如果 size 参数设置为 0,返回值也可能是 NULL,也可能返回一个指针值,稍后可以传递给 free 函数。
- 如果 realloc 函数调用失败,那么原始内存空间的数据并不会修改,也不会被释放或移动。
//根据用户输入需求不断拓宽内存空间
void realloc1()
{
int i,num;
int count = 0;
int *ptr = NULL;//必须初始化为NULL,调用realloc第一个为NULL相当于调用malloc
do
{
printf("请输入一个整数(输入-1表示结束):");
scanf("%d",&num);
count++;
ptr=(int *)realloc(ptr,count*sizeof(int));
if(ptr==NULL)
exit(1);
ptr[count-1]=num;//把数存放进去
}
while(num !=-1);
printf("输入的整数为:");
for(i=0;i<count;i++)
{
printf("%d",ptr[i]);
}
free(ptr);
}
堆
int *func2()
{
int *ptr=NULL;
ptr=(int*)malloc(sizeof(int));//从堆里申请内存空间,把堆的地址返回,则打印出来的则是520,可在main函数内释放
if(ptr==NULL)
{
exit(1);
}
*ptr=520;
return ptr;
}
/堆与栈比较 与数据结构中的堆和栈不同/
//发展方向
/**• 堆和其它区段一样,都是从低地址向高地址发展
• 栈则相反,是由高地址向低地址发展
**/
void fazhan()
{
int *ptr1 = NULL;//局部变量存在栈中
int *ptr2 = NULL;
ptr1 = (int *)malloc(sizeof(int));
ptr2 = (int *)malloc(sizeof(int));
printf("stack: %p -> %p\n",&ptr1,&ptr2);//栈
printf("heap: %p -> %p\n",ptr1,ptr2); //堆
} //可行
/**结果为:
stack:0060FF28->0060FF2C
heap:00652F90->00652FA0
**/
常见的内存错误:
1:段错误
使用未分配成功的内存
避免方式:在使用内存之前检查指针是否为NULL;
引用分配成功但尚未初始化的内存
避免方式:赋予初值,即便是赋予零值也不可省略
内存分配成功并且已经初始化,但操作越过了内存的边界
避免:注意下表的使用不能超出边界
忘记释放内存,造成内存泄露
避免方式:申请内存的方式和释放内存的方式需要成双成对
释放内存之后却继续去使用这一块内存
避免方式:使用free内存之后,把指针置为NULL;
内存错误的注意点:
指针消亡了,并不表示它所指向的内存会被自动释放,(在free之前,直接将指针设为NULL);
内存释放了,并不代表指针会消亡或者成了NULL指针;(在free之后,指针并没有进行NULL设置)
野指针:
野指针的形成是指针变量没有被初始化,任何指针变量刚被创建的时候不会自动成为NULL指针,它的缺省值是最忌的,它会乱指一气
指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法内存
free内存块之后,需要将指针设置为NULL,如果没有设置为NULL,也会出现“野指针”,它是指向“垃圾”内存的指针;
多次free内存块,是会导致程序崩溃的