@TOC
一、动态内存函数
1.malloc函数
在这里插入图片描述
size代表字节数
如果 开辟空间成功 则返回这块空间的地址
如果 开辟空间失败 则返回NULL
正常来说 创建10个整形空间 应为
void*p=void *malloc(10 *sizoef(int));
但是由于void 解引用会报错
所以 (int * )p=(int * )malloc(10*sizeof(int));
#include<stdio.h> #include<stdlib.h> int main() { int*p=(int*)malooc(10*sizeof(int)); if(p!=NULL) { int i=0; for(i=0;i<10;i++) { *(p+i)=i; } } free(p); p=NULL; return 0; }
在这里插入图片描述
如果free(NULL) 则代表什么都不做
2.calloc函数
在这里插入图片描述
num代表元素个数
size代表字节数
与malloc函数不同,calloc函数可以将每个元素初始化为0
#include<stdio.h> #include<stdlib.h> int main() { int*p=(int*)malloc(10*sizeof(int)); if(p!=NULL) { int i=0; for(i=0;i<,10;i++) { printf("%d\n",*(p+i));//malloc没有初始化 全为随机值 } } free(p); p=NULL; return 0; }
#include<stdio.h> #include<stdlib.h> int main() { int*p=(int*)calloc(10,sizeof(int)); if(p!=NULL) { int i=0; for(i=0;i<10;i++) { printf("%d\n",*(p+i));//calloc可以初始化 全是0 } } free(p); p=NULL; return 0; }
3.realloc函数
在这里插入图片描述
realloc函数为一个扩大空间的作用
memblock为前一个的初始地址
size为增大后新空间的大小
realloc返回值有两种情况:
- 后面空间足够 ,则返回原来的初始地址
在这里插入图片描述 - 后面空间不够时
在下面创建一个空间 将旧空间拷贝到新空间 旧空间会还给操作系统
返回新空间的初始地址
在这里插入图片描述 - 当两种情况都不存在时 即无法开辟新空间 则返回NULL
#include<stdio.h> #include<stdlib.h> int main() { int*p=(int*)malloc(10*sizeof(int)); if(p!=NULL) { int i=0; for(i=0;i<10;i++) { *(p+i)=i; } } int*str=(int*)realloc(p,20*sizeof(int));//正常来说只要返回到p就可以了 但是要考虑到 为NULL时的情况 free(NULL)就什么都不做了 会造成内存泄漏 if(str!=NULL) { p=str; } free(p); p=NULL; return 0; }
二、常见动态内存错误
1.对NULL的解引用操作
#include<stdio.h> #include<stdlib.h> int main() { int*p=(int*)malloc(10*sizeof(int); int i=0; for(i=0;i<0;i++) { *(p+i)=i;//如果开辟失败返回NULL *NULL会报错 } free(p); p=NULL; return 0;
2.对动态空间的越界访问
#include<stdio.h> #include<stdlib.h> int main() { int*p=(int*)malloc(10*sizeof(int)); if(p!=NULL) { int i=0; for(i=0;i<40;i++) { *(p+i)=i;//开辟10个整数空间 想要访问40个整形 会造成越界访问 } } free(p); p=NULL; return 0; }
3.对非动态内存使用free释放
#include<stdio.h> #include<stdlib.h> int main() { int arr[10]={0}; int *p=arr;//arr是首元素地址 是在栈区上的 free(p);//动态内存 是在堆区上的 free栈区的会报错 p=NULL; return 0; }
4.使用free释放一块动态内存开辟的一部分
#inlcude<stdio.h> #inlcude<stdlib.h> int main() { int*p=(int*)malloc(10*sizeof(int)); if(p!=NULL) { int i=0; for(i=0;i<10;i++) { *p++=i;//p指针本身向后移动 free释放掉p现在所在后面的空间 会造成内存泄漏 } } free(p); p=NULL; return 0; }
在这里插入图片描述
5.对同一块内存的多次释放
#include<stdio.h> #include<stdlib.h> int main() { int*p=(int*)malloc(10*sizeof(int)); free(p); //p=NULL; free(p); //p=NULL; return 0; }
此时体现出p=NULL的重要性 如果没有这两个p=NULL 会报错
而加上后 free(NULL)表示什么都不做
6.动态开辟的空间忘记释放
#include<stdio.h> #include<stdlib.h> void test() { int*p=(int*)malloc(10*sizeof(int)); //free(p); } int main() { test(); } return 0;
p是虽然是一个指针变量 但也是个局部变量
随着函数销毁而销毁 ,使得 malloc创建的10个整形空间内存泄漏
三、笔试题
1.
#include<stdio.h> #include<stdlib.h> #include<string.h> void memoey(char*p) { p=(char*)malloc(100); } int main() { char*str=NULL; memory(str); strcpy(str,"hello world"); printf(str); return 0; }
会报错
memory函数 将指针传过去由指针接收 是传值调用
p为一份临时拷贝 ,随着函数销毁二销毁
所以即便是开辟动态内存也无法传给str, str依旧为NULL
在memory函数中 随着函数结束 局部变量p也会被销毁
使动态内存开辟的100个字节存在内存泄漏
改错
#include<stdio.h> #include<stdlib.h> #include<string.h> void memoey(char**p) { *p=(char*)malloc(100); } int main() { char*str=NULL; memory(&str); strcpy(str,"hello world"); printf(str); return 0; }
将一级指针的地址传过去 由 二级指针接收 为传址调用
可将动态内存返回
2.
#include<stdio.h> #include<stdlib.h> #include<string.h> char*memory() { char p[]="hello world"; return p; } void test() { char*str=NULL; str=memory(); printf(str); } int main() { test(); return 0; }
会报错
数组是在栈区上创建的, 随着函数的销毁而销毁
虽然 return p将h的地址传给了str
但是输出时 返回找memory函数就找不到了
属于非法访问内存
四、柔性数组
在这里插入图片描述
特点
- 在柔性数组上面至少有一个成员存在
- 在使用sizeof计算大小时 不包括柔性数组的内存
#include<stdio.h> struct S { int n; int arr[];//一个未知大小的数组 --柔性数组 } int main() { struct S s={0}; printf("%d\n",sizeof(s));//4 }
- 在一个结构体包含柔性数组时 应使用malloc创建动态内存空间
并加上期望的柔性数组的大小
#include<stdio.h> #include<stdlib.h> struct S { int n; int arr[];//期望柔性数组大小是10个整形 } int main() { strcut S*p=(struct S*)malloc(sizeof(s)+10*sizeof(int)); free(p); p=NULL; return 0; }