C_08_动态内存申请
动态内存申请
首先核心就是熟记 内存图以及内存中每个区域不同的功能:
引入
#include <stdio.h> int main(int argc, char const *argv[]) { int len = 0; printf("请输入数组长度\n"); scanf("%d",&len); //此时我们想将数组的长度动态设定,但是语法不支持 int nums[len] = {0}; return 0; }
作用:
在开发中根据实际需求开辟内存。
内存申请分类:
- 静态内存申请
- 动态内存申请
静态内存申请(静态分配)
1 在程序编译或运行过程中,按事先规定大小分配内存空间的分配方式。int a [10]; // int a [10]; 占40字节 10x4b = 40 2 必须事先知道所需空间的大小。 3 分配在栈区或全局变量区,一般以数组的形式。 4 按计划分配。
动态内存申请(动态内存)
1、在程序运行过程中,根据需要大小自由分配所需空间。 2、按需分配。 3、分配在堆区,一般使用特定的函数进行分配 特点:在程序运行中可以使用函数对其内存进行动态分配
动态分配函数:
注意点:
- 万能指针 不能使用 需要类型转换到想使用的 类型指针
- 内存申请有可能会申请失败 所以一般加上 判断申请的是否为空 为空直接退出 因为都没内存了 还写什么
如果你有一个 void* 指针 ptr,并且你知道它实际上指向一个 int 类型的值,你可以这样将它转换为 int* 类型的指针:
void* ptr = ...; // 假设ptr指向某个int类型的值
int* intPtr = (int*)ptr; // 显式类型转换
怎么查
使用man命令
> man 3 函数名
注意:
以下函数 由系统提供,属于库函数 意味着无需自己定义该函数,直接调用即可 因为动态内存分配的内存在 堆区, 无法自动释放内存,需要手动释放内存
1 memset
设置区间范围内容
函数是 C 语言标准库中的函数,位于
<cstring>
头文件中 所以要加上
作用:
# 将指定开始位置到指定长度的内存中的内容设置为指定的值。
语法:
void *memset (void *s,int c,size_t n); // 默认都是int 注意使用别的 要类型转换 void *s:开始的位置 int c: 指定的内容 n: 设定的长度 返回值: 设置的内存
2 free
释放动态申请内存
作用:
**释放动态分配申请的内存**
语法:
void free(void *ptr); 参数: void *ptr:要释放的内存的首地址 返回值: void :没有返回值
所属头文件:
此处里面的 size_t 都暂时默认为 int
3 malloc
申请动态内存
内存申请的都是随机数,在堆区动态申请内存
语法:
void *malloc(size_t size); 参数: size_t size:申请的内存大小,单位字节 返回值: void *:申请的内存的首地址,如果为NULL说明申请失败
示例:
#include <stdio.h> #include <stdlib.h> // malloc 动态申请内存 void *malloc(size_t size); 申请的内存大小,单位字节 int main(int argc, char const *argv[]) { // 要求:根据用户输入数量,动态申请内存,存储int型数据 int len = 0; printf("请输入存储的数的个数\n"); scanf("%d", &len); // 申请空间 使用万能指针 void *nums = malloc(len * sizeof(int)); if (nums == NULL) // 返回为null就直接退出没内存 也就是判空操作 { printf("申请失败\n"); return 0; } int *p = (int *)nums; // 类型转换 因为万能指针不能使用 for (int i = 0; i < len; i++) { printf("%d\n", p[i]); } // 释放空间 free(p); return 0; }
4 calloc
申请动态内存
作用:
> 动态申请内存 在堆区
语法:
void *calloc(size_t nmemb, size_t size); 参数: nmemb: 申请的内存块数 size: 每块所占的字节数 返回值: void *: 申请的内存的首地址,如果为NULL说明申请失败
示例
#include <stdio.h> #include <stdlib.h> // void *calloc(size_t nmemb, size_t size); // nmemb:申请的内存块数 size:每块所占的字节数 int main(int argc, char const *argv[]) { // 根据用户输入数量,动态申请内存,存储int型数据 int len = 0; printf("请输入存储的数的个数\n"); scanf("%d", &len); // 申请空间 int *nums = (int *)(calloc(len, sizeof(int))); // 判空 if (nums == NULL) { printf("申请失败\n"); return 0; } for (int i = 0; i < len; i++) { printf("%d\n", nums[i]); } // 释放空间 free(nums); return 0; }
两者区别:
malloc和calloc函数都是用来申请内存的。
区别:
1)函数的名字不一样
2)参数的个数不一样
3)malloc申请的内存,内存中存放的内容是随机的,不确定的,而calloc 函数申请的内存中的内容为0
5 realloc
追加内存
并不是再原来的尾部追加内存
而是重新开辟了一块你申请的内存大小区域并将原内存中的值拷贝到新内存的前面 , 原内存就被舍弃了
void *realloc(void *ptr, size_t size); 参数: void *ptr:要追加的内存的首地址 size:重新申请的大小,单位字节 返回值: void *:追加的内存的首地址,如果为NULL说明追加失败
注意:
该函数并不是在原基础上追加,而是从新开辟一片内存,将原内存中的值拷贝到新内存的前面
6.memcpy
拷贝内容
作用
拷贝内存中的内容
语法:
void *memcpy(void *dest, const void *src, size_t n); 参数: dest:目标地址 src:资源地址 n:长度 是按字节大小拷贝 无关数据类型
示例:
#include <stdio.h> #include <stdlib.h> #include <string.h> struct stu { char name[50]; char sex[10]; int age; }; int main(int argc, char const *argv[]) { struct stu s1 = {"张桑", "男", 18}; struct stu s2 = s1; s2.age = 20; struct stu s3; memcpy(&s3, &s1, sizeof(struct stu)); // s3.age = 21; printf("%s\n", s1.name); printf("%s\n", s1.sex); printf("%d\n", s1.age); printf("%s\n", s2.name); printf("%s\n", s2.sex); printf("%d\n", s2.age); printf("%s\n", s3.name); printf("%s\n", s3.sex); printf("%d\n", s3.age); return 0; }
内存泄漏
就是 有一块内存被用着 但是找不到 不能再使用 也不能删除 所以就是占用着造成了内存不能正常使用和释放
概念:
申请的空间,没有被指向,系统无法回收该空间。这种情况就叫内存泄漏。
情况1:指向堆区的指针变量指向了别地方
int *nums = cal1oc(10,4); //指向calloc函数在堆内存开辟的空间的首地址
int x= 10;
nums =&x; //将x的地址赋值给nums栈中成员变量
情况2:指向堆区的指针变量被意外释放
void method()
{
int * nums = calloc(10,4); // 局部变量使用完就随着函数结束 但是申请的内存没有释放 内存在占用 所以会造成内存泄漏
}
int mian()
{
method(); //调用完这个函数
return 0;
}
总结:
使用完成记得释放所用的内存
重复释放同一片内存也会导致程序出现问题
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
char *p = malloc(100);// 申请100b
free(p); //用完释放内存
free(p); // 重复释放内存
return 0;
}
如何避免重复释放一段内存
注意:
- 拷贝构造不使用判断 后期继承的时候会出现 对继承后的拷贝构造进行判断赋值会出问题
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
//如何避免重复释放
char *p = malloc(100); // 申请100字节
if (p != NULL) // 判断是否为NULL
{
free(p); // 内存释放
p = NULL; // 原指针指向NULL
}
return 0;
}
总结:
# 在使用申请的内存后要释放并将原指针指向NULL
# 每次释放前判断该指针是否为NULL,如果不为空在释放并制空
nclude <stdlib.h>
int main(int argc, char const *argv[])
{
//如何避免重复释放
char *p = malloc(100); // 申请100字节
if (p != NULL) // 判断是否为NULL
{
free§; // 内存释放
p = NULL; // 原指针指向NULL
}
return 0;
}
#### 总结:
~~~~bash
# 在使用申请的内存后要释放并将原指针指向NULL
# 每次释放前判断该指针是否为NULL,如果不为空在释放并制空