C语言-内存分配

内存分配

1. 引入

int nums[10] = {0}; //对

int len = 10;
int nums[len] = {0}; //错

是因为系统的内存分配原则导致的

2. 概述

在程序运行时,系统为了 更好的管理进程中的内存,所以有了 内存分配机制

分配原则:

2.1 静态分配

静态分配原则:

特点:

1、在程序编译过程中,按事先规定的大小 分配内存空间的分配方式;

2、必须事先知道所需空间的大小;

3、分配在 栈区或全局变量区,一般 以数组的形式

4、按计划分配

2.2 动态分配

特点:

1、在程序运行过程中,根据需要大小自由分配所需空间;

2、按需分配

3、分配在堆区,一般 使用特定的函数进行分配

案例:

需求:
    1、班级有15个学员,定义数组记录学员成绩
    	double score[15] = {0};
    
    2、记录学员成绩
    	- 输入学员数量
        - 在堆区申请
        - 扩展
        - 释放

注意:

在c语言中提供了一系列动态分配内存的函数
这些函数大部分都在stdlib.h头文件中声明

free 		释放
malloc 		申请空间,默认值随机
calloc 		申请空间,默认值为0
realloc 	扩展空间

string.h中提供的函数
memset 将malloc中的随机数设为0

3. 动态分配函数

3.1 memset 函数

作用:重置

语法:

#include <string.h>

void *memset(void *s, int c, size_t n);

参数:
	s: 开始的位置
	c: 重置后的数据
	n: 重置的数量
	从s开始, 将n个字节的数据, 设置为c

示例:

#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
    char str[10] = {0};
    memset(str, 'a', 10);
    for (char i = 0; i < 10; i++)
    {
        printf("%c ", str[i]);
    }
    printf("\n");
    // a a a a a a a a a a 

    int nums[5] = {1,2,3,4,5};
    memset(nums, 0, 20);
    for (int i = 0; i < 5; i++)
    {
        printf("%d ", nums[i]);
    }
    printf("\n");
    //0 0 0 0 0 
    return 0;
}

3.2 free 函数

作用:释放内存

语法:

#include <stdlib.h>

void free(void *ptr);

参数:
	ptr: 指针

注意:

ptr 指向的内存必须是 malloccallocrelloc 动态申请的内存

3.3 malloc 函数

作用:在堆内存中开辟空间

语法:

void *malloc(size_t size)

参数:
	size_t: 可以理解为无符号int;
	size: 开辟空间大小,单位字节。
	
返回值:
    开辟的空间的地址
    开辟失败返回NULL

注意:

  1. 在使用malloc时,需要 判断是否开辟成功
  2. 如果多次 malloc 申请的内存,第 1 次和第 2 次申请的内存不一定是连续的;
  3. malloc的返回值在使用中 记得 强制类型转换 (因为该函数原型返回 void*指针 );
  4. malloc从堆区申请空间后 空间的内容中的值是随机的(与局部变量一样大概率为0),可以使用memset函数对空间中的数据进行置0。

示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
    //1、申请空间
    //申请一个可以存储10个int数据的空间
    int *nums = (int *)malloc(10 * sizeof(int));
    //2、判断是否开辟失败
    if(nums == NULL)
    {
        printf("内存开辟失败\n");
        return 0;
    }
    //置0
    memset(nums, 0, 10*sizeof(int));
    //3、使用空间
    for (int i = 0; i < 10; i++)
    {
        printf("请输入第%d个数\n", i+1);
        scanf("%d", &nums[i]);
    }
    for (int i = 0; i < 10; i++)
    {
        printf("%d ", nums[i]);
    }
    printf("\n");
    //4、释放空间
    free(nums);
    return 0;
}

3.4 calloc 函数

作用:在堆内存中开辟空间

语法:

void *calloc(size_t nmemb, size_t size);

参数:
	nmemb: 申请的块数
	size: 每块的大小
	
返回值:
    开辟的空间的地址
    开辟失败返回NULL
    
int *p = malloc(10 * sizeof(int));
int *p = calloc(10, sizeof(int));

示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
    //1、申请空间
    //申请一个可以存储10个int数据的空间
    // int *nums = (int *)malloc(10 * sizeof(int));
    int *nums = (int *)calloc(10, sizeof(int));
    //2、判断是否开辟失败
    if(nums == NULL)
    {
        printf("内存开辟失败\n");
        return 0;
    }
    //3、使用空间
    for (int i = 0; i < 10; i++)
    {
        printf("请输入第%d个数\n", i+1);
        scanf("%d", &nums[i]);
    }
    for (int i = 0; i < 10; i++)
    {
        printf("%d ", nums[i]);
    }
    printf("\n");
    //4、释放空间
    free(nums);
    return 0;
}

3.5 realloc 函数

作用:扩展空间,其实是重新申请内存

语法:

void *realloc(void *ptr, size_t size);

参数:
	ptr:原指针
	size:从新开辟的大小,原大小+新开的大小
	
返回值:
    开辟成功返回新地址
    开辟失败返回NULL

注意:

新地址不一定等于原地址,但是大概率相同

在原先 ptr 指向的内存基础上重新申请内存,新的内存的大小为 size 个字节,如果原先内存后面有足够大的空间,就追加,如果后边的内存不够用,则 relloc 函数会在堆区找一个 size 个字节大小的内存申请,将原先内存中的内容拷贝过来,然后释放原先的内存,最后返回新内存的地址。

在这里插入图片描述

示例:

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
    char * strs = (char *)calloc(3, sizeof(char));

    strs = realloc(strs, 2*sizeof(char));
    for (int i = 0; i < 5; i++)
    {
        scanf("%s", &strs[i]);
    }
    for (int i = 0; i < 5; i++)
    {
        printf("%c ", strs[i]);
    }
    printf("\n");
    free(strs);
    
    return 0;
}

4. 内存泄漏

4.1 概念

申请的内存,首地址丢了,找不了,再也没法使用了,也没法释放了,这块内存就被泄露了。

4.2 记录申请内存的指针变量指向别的地方

int *p = (int *)malloc(40);
int nums[10] = {};
p = nums; //p 指向别的地方了
//从此以后,再也找不到申请的 40 个字节了。 则动态申请的 40 个字节就被泄露了

4.3 在函数中申请空间,使用完毕没有释放

void test()
{
	int *p = (int *)malloc(40);
} 
test();  //每调用一次 test 泄露 40 个字节

5. 防止多次释放

多次释放示例:

int *p = (int *)malloc(40);
free(p);
free(p);

//注意多次释放会报错

防止多次释放:

释放前判断,释放后置NULL

示例:

int *p = (int *)malloc(40);
if(p != NULL)
{
    free(p);
    p = NULL;
} 
if(p != NULL)
{
    free(p);
    p = NULL;
}

6. 练习

设计函数,接收一个字符串,返回这个字符串的逆向内容
#include <stdio.h>
#include <stdlib.h>

int my_strlen(char *str)
{
    int len = 0;
    while (*str != '\0')
    {
        str++;
        len++;
    }
    return len;
}

char * my_strrev(char *str)
{
    int len = my_strlen(str);
    char *new_str = (char *)calloc((len+1), sizeof(char));
    for (int i = 0; i < len; i++)
    {
        new_str[i] = str[len-i-1];
    }
    new_str[len] = '\0';
    return new_str;
}

int main(int argc, char const *argv[])
{
    char *str = "helloworld";
    char *new_str = my_strrev(str);
    printf("%s\n", new_str);
    if (new_str != NULL)
    {
        free(new_str);
        new_str = NULL;
    }
    
    return 0;
}
// dlrowolleh

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/213888.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

解决top-k问题--堆排序

目录 TOP-K问题 堆排序 考虑以下情况&#xff1a; 1.在n个数里面找最大的一个数 2.在n个数里面找最大的两个数 3.在n个数中求前k大的数 为什么不用大根堆呢&#xff1f; 代码 时间复杂度 TOP-K问题 即求数据结合中前K个最大的元素或者最小的元素&#xff0c;一般情况下数…

使用Redis构建任务队列

文章目录 第1关&#xff1a;先进先出任务队列第2关&#xff1a;优先级任务队列第3关&#xff1a;定时任务队列 第1关&#xff1a;先进先出任务队列 编程要求 在Begin-End区域编写 add_task(task_name) 函数&#xff0c;实现将任务加入队列的功能&#xff0c;具体参数与要求如下…

论文阅读——Loss odyssey in medical image segmentation

Loss odyssey in medical image segmentation github&#xff1a;https://github.com/JunMa11/SegLossOdyssey 这篇文章回顾了医学图像分割中的20种不同的损失函数&#xff0c;旨在回答&#xff1a;对于医学图像分割任务&#xff0c;我们应该选择哪种损失函数&#xff1f; 首…

使用 Kettle 完成数据 ETL

文章目录 使用 Kettle 完成数据 ETL数据清洗数据处理 使用 Kettle 完成数据 ETL 现在我们有一份网站的日志数据集&#xff0c;准备使用Kettle进行数据ETL。先将数据集加载到Hadoop集群中&#xff0c;然后对数据进行清洗&#xff0c;最后加载到Hive中。 在本地新建一个数据集文…

解决vscode中html部分无法嵌套注释

不管是React项目还是Vue项目&#xff0c;相信你一定遇到过同样的问题&#xff0c;如果想要注释的结构内部也存在注释&#xff0c;那么编译器会报以下问题 使用 HTML-Comment 这个插件即可解决问题 选中需要注释的区域并根据系统输入快捷键&#xff0c;可以发现就算嵌套了注释…

【论文解读】角色动画的一致可控的图像到视频合成

论文&#xff1a;https://arxiv.org/pdf/2311.17117.pdf 代码&#xff1a;https://github.com/HumanAIGC/AnimateAnyone 图片解释&#xff1a;给定参考图像&#xff08;每组中最左边的图像&#xff09;的一致且可控的角色动画结果。我们的方法能够对任意角色进行动画处理&#…

人工智能原理复习--不确定推理

文章目录 上一篇不确定推理概述主观Bayes(贝叶斯)方法可信度方法证据理论下一篇 上一篇 人工智能原理复习–确定性推理 不确定推理概述 常识具有不确定性。 常识往往对环境有极强的依存性。 其中已知事实和知识是构成推理的两个基本要素&#xff0c;不确定性可以理解为在缺…

Makefile初学之谜之隐式规则

刚开始学习Make教程&#xff1a;https://makefiletutorial.vercel.app/#/docs/fancy-rules&#xff0c;里面有个sample: objects foo.o bar.o all.o all: $(objects)# These files compile via implicit rules foo.o: foo.c bar.o: bar.c all.o: all.call.c:echo "int…

python--自动化办公(Word)

python自动化办公之—Word python-docx库 1、安装python-docx库 pip install python-docx2、基本语法 1、打开文档 document Document() 2、加入标题 document.add_heading(总标题,0) document.add_heading(⼀级标题,1) document.add_heading(⼆级标题,2) 3、添加文本 para…

Spring IOC—基于XML配置和管理Bean 万字详解(通俗易懂)

目录 一、前言 二、通过类型来获取Bean 0.总述&#xff08;重要&#xff09; : 1.基本介绍 : 2.应用实例 : 三、通过指定构造器为Bean注入属性 1.基本介绍 : 2.应用实例 : 四、通过p命名空间为Bean注入属性 1.基本介绍 : 2.应用实例 : 五、通过ref引用实现Bean的相…

手机也能“敲”代码?

除了PC个人电脑外&#xff0c;很多电子产品也可以实现代码的编辑&#xff0c;比如智能手机。现在主流的手机操作系统只有两种&#xff0c;一种是大部分手机厂商选择的安卓系统&#xff0c;另外一种是苹果公司独创的ios操作系统。而Android系统是基于Linux开发的专属于移动设备的…

【Leetcode题单】(01 数组篇)刷题关键点总结03【数组的改变、移动】

【Leetcode题单】&#xff08;01 数组篇&#xff09;刷题关键点总结03【数组的改变、移动】&#xff08;3题&#xff09; 数组的改变、移动453. 最小操作次数使数组元素相等 Medium665. 非递减数列 Medium283. 移动零 Easy 大家好&#xff0c;这里是新开的LeetCode刷题系列&…

Java数据结构之《构造哈夫曼树》题目

一、前言&#xff1a; 这是怀化学院的&#xff1a;Java数据结构中的一道难度中等(偏难理解)的一道编程题(此方法为博主自己研究&#xff0c;问题基本解决&#xff0c;若有bug欢迎下方评论提出意见&#xff0c;我会第一时间改进代码&#xff0c;谢谢&#xff01;) 后面其他编程题…

【蓝桥杯】翻硬币

翻硬币 思路&#xff1a; 其实有点贪心的意思&#xff0c;依次比较&#xff0c;不同就1&#xff0c;然后修改自己的字符串和下一个的字符串&#xff0c;再匹配。 #include<iostream> #include<string> using namespace std;string now,res;int main(void) {cin&g…

MQ - 消息系统

消息系统 1、消息系统的演变 在大型系统中&#xff0c;会需要和很多子系统做交互&#xff0c;也需要消息传递&#xff0c;在诸如此类系统中&#xff0c;你会找到源系统&#xff08;消息发送方&#xff09;和 目的系统&#xff08;消息接收方&#xff09;。为了在这样的消息系…

java高校实验室排课学生考勤系统springboot+vue

随着各高校办学规模的迅速扩大,学科专业的不断拓宽,传统的实验教学和实验室管理方法已经不能适应学校管理的要求,特别是化学实验室的管理,化学实验室仪器药品繁杂多样,管理任务繁重,目前主要使用人工记录方法管理,使用不便,效率低下,而且容易疏漏.时间一长将产生大量的文件和数…

【面试经典150 | 二分查找】搜索二维矩阵

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a;二分查找 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题涉及到的数据结构等…

c# OpenCV 读取、显示和写入图像(二)

读取、显示和写入图像是图像处理和计算机视觉的基础。即使在裁剪、调整大小、旋转或应用不同的滤镜来处理图像时&#xff0c;您也需要先读取图像。因此&#xff0c;掌握这些基本操作非常重要。 imread()读取图像imshow()在窗口中显示图像imwrite()将图像保存到文件目录里 我们…

细说CountDownLatch

CountDownLatch 概念 CountDownLatch可以使一个获多个线程等待其他线程各自执行完毕后再执行。 CountDownLatch 定义了一个计数器&#xff0c;和一个阻塞队列&#xff0c; 当计数器的值递减为0之前&#xff0c;阻塞队列里面的线程处于挂起状态&#xff0c;当计数器递减到0时…

力扣226:翻转二叉树

力扣226&#xff1a;翻转二叉树 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1] 示例 2&#xff1a; 输入&#xff1a;root [2,1,3]…
最新文章