C_08_动态内存申请

devtools/2025/1/15 21:48:28/

动态内存申请

首先核心就是熟记 内存图以及内存中每个区域不同的功能:

在这里插入图片描述

引入

#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(104); //指向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);// 申请100bfree(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,如果不为空在释放并制空

http://www.ppmy.cn/devtools/104011.html

相关文章

C#入门篇7(面向对象)

目录 一、值传递和引用传递 1、概念 2、主要区别 3、用法 二、字符串 1、字符串的不可变性可以将字符串看作只读字符数组 2、字符串提供的各种方法 三、继承 1、 概念 2、格式 3、示例 4、子类继承于父类什么&#xff1f; 5、继承的特性 6、查看类图 四、new关键字…

Linux 命令行快捷键

Linux 命令行快捷键_linux删除一个单词-CSDN博客 涉及在linux命令行下进行快速移动光标、命令编辑、编辑后执行历史命令、Bang(!)命令、控制命令等。让basher更有效率。 常用 Ctrl左右键:在单词之间跳转 Ctrla: 跳到本行的行首 Ctrle: 跳到页尾 Ctrlu&#xff1a;删除当前光标…

51单片机——模块化编程

1、模块化编程介绍 传统方式编程&#xff1a;所有的函数均放在main.c里&#xff0c;若使用的模块比较多&#xff0c;则一个文件内会有很多的代码&#xff0c;不利于代码的组织和管理&#xff0c;而且很影响编程者的思路。 模块化编程&#xff1a;把各个模块的代码放在不同的.…

EXCEL文件如何批量加密,有什么方法

EXCEL文件的加密&#xff0c;通常在EXCEL软件上进行设置&#xff0c;它有打开密码与写保护密码&#xff0c;如果有多个文件的话&#xff0c;想通过一键设置的方法进行密码设置&#xff0c;那么它通常需要用到第三方软件进行批处理&#xff0c;因为EXCEL软件只能对当前打开的文件…

G722.1.C简单介绍

目录 一、编码参数二、编码特性三、解码特性四、应用领域五、优缺点 G.722.1 Annex C ("G.722.1C") 引用其他文章介绍&#xff1a; This paper describes the low-complexity 14 kHz audio coding algorithm which has been recently standardized by ITU-T as Recom…

Milvus向量数据库-数据备份与恢复

前言 随着Milvus版本的持续迭代&#xff0c;越来越多的用户将其作为构建生产环境的向量数据服务使用。作为数据服务使用&#xff0c;其中的运维、数据安全、容灾备份自然是用户最关心且不容有失的需求。为解决这一需求&#xff0c;Milvus-backup项目工具应运而生。 Milvus-ba…

备考AMC10美国数学竞赛2024:吃透1250道真题和知识点(持续)

有什么含金量比较高的初中生数学竞赛吗&#xff1f;美国数学竞赛AMC10是个不错的选择。那么&#xff0c;如何备考AMC10美国数学竞赛呢&#xff1f;做真题&#xff0c;吃透真题和背后的知识点是备考AMC8、AMC10有效的方法之一。 通过做真题&#xff0c;可以帮助孩子找到真实竞赛…

FFmpeg的入门实践系列六(编程入门之常见处理流程)

欢迎诸位来阅读在下的博文~ 在这里&#xff0c;在下会不定期发表一些浅薄的知识和经验&#xff0c;望诸位能与在下多多交流&#xff0c;共同努力 文章目录 前期博客参考书籍一、FFmpeg常见的处理流程复制编解码器的参数完整代码 二、创建并写入音视频文件三、总结附页 前期博客…