动态分配内存

news2024/12/23 22:38:34

目录

前言

一.malloc,free函数

1.malloc,free函数原型

2.使用方法

3.具体实例

4.注意事项

二.calloc函数

1.calloc函数原型

2.主要特点

3.使用案例

三.realloc函数

1.realloc函数原型

2.使用案例

3.注意事项


前言

动态内存是指在程序运行时,按需分配和释放的内存空间。这种内存分配不在编译时固定,而是在程序执行过程中,根据实际需要分配,并且可以手动释放。

以下介绍的函数都包含于头文件<stdlib.h>

为什么使用动态内存?

1.灵活性高。动态内存可以根据需要分配内存块。

2.避免浪费内存。动态内存允许程序根据需要分配精确的内存量,从而更有效地使用内存资源。

一.malloc,free函数

malloc 是 C 标准库中用于动态内存分配的函数。它从堆(heap)中分配指定字节数的内存,并返回指向这块内存的指针。如果内存分配失败,它会返回 NULL

free 函数是C标准库中的一个函数,用于释放由动态内存分配函数(如 malloccallocrealloc)分配的内存。它的作用是将不再需要的动态内存归还给操作系统,防止内存泄漏

1.malloc,free函数原型

void* malloc(size_t size);

  • size:要分配的内存大小,以字节为单位。
  • 返回值:成功时,返回指向已分配内存块的指针;失败时,返回 NULL
  • void*:返回值类型

void free(void* ptr);

  • 参数:

    • ptr:一个指向要释放内存块的指针,这个指针必须是通过 malloccallocrealloc 返回的指针。如果 ptrNULLfree 不会执行任何操作。
  • 返回值:

    • free 没有返回值。

2.使用方法

(1)内存分配,如:

int* p = (int*)malloc(sizeof(int)); // 为一个 int 类型变量分配内存

(2)判断是否开辟空间成功(如果没有开辟成功,直接使用指针可能回答导致程序崩溃,未定义行为等),如:

if (p == NULL) {
	perror("malloc");//打印错误信息的函数
	return 1;//分配失败,退出程序
}

(3)释放内存(防止内存泄露),如:

free(p);

(4)将指针置为空(防止指针在释放内存地址后还指向原来那个地址,相当于野指针,可能会导致未定义行为或者程序崩溃等等),:

p = NULL;

3.具体实例

#include<stdio.h>
#include<stdlib.h>
int main() {
	int* arr = (int*)malloc(sizeof(int) * 10);
	//或者int* arr=(int*)malloc(40);
	//判断是否分配内存成功
	if (arr == NULL) {
		perror("malloc");//打印错误信息
		return 1;//分配失败,退出程序
	}
    //初始赋值
	for (int i = 0; i < 10; i++) {
		arr[i] = i + 1;
	}
    //打印结果
	for (int i = 0; i < 10; i++) {
		printf("%d ", arr[i]);
	}
	//释放内存
	free(arr);
	//将arr置为空
	arr = NULL;
	return 0;
}

需要注意的是:

在int* arr = (int*)malloc(sizeof(int) * 10);这一语句中

1.(int*)是强制转换类型,将原本的返回值类型void*转化为我们需要定义的数据类型,当然这里我们定义的是int*类型的。

2.sizeof(int)*10是int类型的字节数乘以10,即我们要开辟4*10=40个字节,开辟10个整型的空间,当然我们也可以这么写malloc(40),前提是你要计算好你需要开辟的字节数,否则在没有开辟够这么多的字节数的情况下越界访问数组可能会导致程序崩溃或者无限循环等的行为。

4.注意事项

malloc开辟的空间是没有创建初始值的。

举例如下:

#include<stdio.h>
#include<stdlib.h>
int main() {
	int* p = (int*)malloc(sizeof(int) * 5);
	for (int i = 0; i < 5; i++) {
		printf("%d ", p[i]);
	}
	return 0;
}

结果是随机值:

二.calloc函数

calloc 是 C 语言中的标准库函数,用于动态分配内存。与 malloc 类似,calloc 也用于在堆上分配一块内存

1.calloc函数原型

void* calloc(size_t num, size_t size);

  • num:要分配的元素个数。
  • size:每个元素的大小(以字节为单位)。

2.主要特点

(1)分配并初始化内存为零

calloc 会分配一块内存,并将这块内存中的所有字节初始化为 0。这与 malloc 的行为不同,malloc 仅仅分配内存,但不对内存进行初始化,内存中的内容可能是垃圾值。

(2)两个参数

malloc 不同,calloc 需要两个参数:第一个参数是要分配的元素个数,第二个参数是每个元素的大小。malloc 只需要一个参数(总内存大小),而 calloc 的目的是让用户更加清晰地定义数组类型的内存分配。

3.使用案例

#include <stdio.h>
#include <stdlib.h>

int main() {
    int* arr = (int*)calloc(5, sizeof(int));  // 分配5个int大小的空间,且初始化为0

    if (arr == NULL) {
        printf("Memory allocation failed!\n");
        return 1;
    }

    // 输出分配并初始化的数组
    for (int i = 0; i < 5; i++) {
        printf("%d ", arr[i]);  // 输出结果将是 0 0 0 0 0
    }
    printf("\n");

    // 使用完成后释放内存
    free(arr);
    arr=NULL; 

    return 0;
}

结果如图:

三.realloc函数

realloc 函数用于调整已经分配的动态内存的大小

1.realloc函数原型

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

  • ptr:指向已经通过 malloc, calloc 或者 realloc 分配的内存。如果 ptrNULLrealloc 的行为与 malloc 类似,分配一块新的内存。
  • size:新分配的内存大小,以字节为单位。如果 size 为 0,realloc 的行为与 free 类似,会释放 ptr 指向的内存。

2.使用案例

(1)扩大内存

#include <stdio.h>
#include <stdlib.h>

int main() {
    int* arr = (int*)malloc(5 * sizeof(int));  // 分配5个int的内存

    if (arr == NULL) {
        perror("malloc");
        return 1;
    }

    // 初始化数组
    for (int i = 0; i < 5; i++) {
        arr[i] = i;
    }
    //第一次打印
    for (int i = 0; i < 5; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
    // 调整数组大小,增加到10个int
    int* new_arr = (int*)realloc(arr, 10 * sizeof(int));

    if (new_arr == NULL) {
        perror("realloc");
        free(arr);  // 如果失败,释放原来的内存
        arr = NULL;
        return 1;
    }

    // 如果重新分配成功,继续使用新数组
    arr = new_arr;

    // 初始化新增加的部分(第二次打印)
    for (int i = 5; i < 10; i++) {
        arr[i] = i;
    }

    // 输出数组
    for (int i = 0; i < 10; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    // 释放内存
    free(arr);
    arr = NULL;
    return 0;
}

结果如图:

(2)缩小内存

#include <stdio.h>
#include <stdlib.h>

int main() {
    // 分配 10 个 int 大小的内存
    int* arr = (int*)malloc(10 * sizeof(int));

    if (arr == NULL) {
        perror("malloc");
        return 1;
    }

    // 初始化数组
    for (int i = 0; i < 10; i++) {
        arr[i] = i + 1;
    }

    printf("初始10个元素:\n");
    for (int i = 0; i < 10; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    // 使用 realloc 缩小数组到 5 个 int
    int* new_arr = (int*)realloc(arr, 5 * sizeof(int));

    if (new_arr == NULL) {
        perror("realloc");
        free(arr);  // 如果 realloc 失败,释放原来的内存
        arr = NULL;
        return 1;
    }

    // 如果 realloc 成功,继续使用缩小后的数组
    arr = new_arr;

    printf("缩小后的元素:\n");
    for (int i = 0; i < 5; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    // 释放缩小后的内存
    free(arr);
    arr = NULL;

    return 0;
}

结果如图:

注意事项:

  • 在缩小内存时,数组后面的数据会丢失。程序只能访问缩小后剩余的那部分数据。
  • 缩小内存后,应确保访问的索引在新分配的范围内,避免越界访问。

3.注意事项

  • 扩展/缩小内存realloc 可以扩展或者缩小已经分配的内存块。如果扩展,之前的数据会保留;如果缩小,超出部分会被释放。
  • 原内存的保留:如果 realloc 需要移动内存块(例如在当前内存空间不足的情况下),它会自动分配新内存并将旧内存的数据复制过去,原来的内存块会被释放。
  • 失败时不释放原内存:如果 realloc 失败,它不会释放原来的内存,程序可以继续使用原来的

除了这三点,我们还要注意一点,我们来看一下代码:

就是用原来的指针接收申请的空间

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int* ptr = (int*)malloc(100);
	if (ptr != NULL)
	{
		//业务处理 
	}
	else
	{
		return 1;
	}
	//扩展容量 
	ptr = (int*)realloc(ptr, 1000);//这样可以吗?(如果申请失败会如何?) 
    free(ptr);
    return 0;
}

问题:

  • 如果 realloc 申请失败,会返回 NULL。此时,ptr 的原有地址(即之前分配的内存)将会被丢失,导致 内存泄漏。由于 ptr 被覆盖成 NULL,无法再释放之前申请的内存,也无法继续使用。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java网络通信—TCP

1.客户端 2.服务端

OpenGL ES 纹理(7)

OpenGL ES 纹理(7) 简述 通过前面几章的学习&#xff0c;我们已经可以绘制渲染我们想要的逻辑图形了&#xff0c;但是如果我们想要渲染一张本地图片&#xff0c;这就需要纹理了。 纹理其实是一个可以用于采样的数据集&#xff0c;比较典型的就是图片了&#xff0c;我们知道我…

【ios】---swift开发从入门到放弃

swift开发从入门到放弃 环境swift入门变量与常量类型安全和类型推断print函数字符串整数双精度布尔运算符数组集合set字典区间元祖可选类型循环语句条件语句switch语句函数枚举类型闭包数组方法结构体 环境 1.在App Store下载Xcode 2.新建项目&#xff08;可以先使用这个&…

AKShare-股票数据-相关股票

AKShare-股票数据-相关股票 数据科学实战 数据科学实战 2024年10月01日 13:53 作者寄语 本次更新股票数据-相关股票接口。主要修复该接口&#xff0c;目前通过该接口可以获取 时间&#xff0c;股票代码&#xff0c;相关股票代码&#xff0c;涨跌幅 等字段的数据。 欢迎加入专…

Java之方法的使用

修饰符 返回值 方法名称&#xff08;形式参数&#xff09;{ } 当无参数的时候形式参数中什么都不写。 列如求两个数相加 修饰符可有可无。 方法重载&#xff1a; 1.方法名相同 2.参数列表不同 3。返回值不影响重载

STL--string类

我们从这篇文章之后就正式开始学习STL的string&#xff0c;字面看起来是不是像C语言里面的字符串之类的处理方法&#xff0c;是的&#xff0c;C里面也是对字符串的一些处理函数&#xff0c;但是C有很多这样的函数&#xff0c;给大家推荐一个网站 &#xff0c;这个网站是C的官网…

Python | Leetcode Python题解之第448题找到所有数组中消失的数字

题目&#xff1a; 题解&#xff1a; class Solution:def findDisappearedNumbers(self, nums: List[int]) -> List[int]:n len(nums)for num in nums:x (num - 1) % nnums[x] nret [i 1 for i, num in enumerate(nums) if num < n]return ret

Verilog基础:$display系统函数和C语言中的库函数printf的区别

相关阅读 Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482 Verilog中的$display系统函数和C语言中的库函数printf都是用于输出信息&#xff0c;但它们的用法存在一定差别&#xff0c;本文将简要描述。 $display系统函数的B…

Javaweb商城项目

smbms 视频教程&#xff1a;javaweb-30&#xff1a;smbms项目搭建_哔哩哔哩_bilibili 一.项目分析 1.项目结构 2.数据库表 CREATE DATABASE smbms;USE smbms;DROP TABLE IF EXISTS smbms_address;CREATE TABLE smbms_address (id bigint(20) NOT NULL AUTO_INCREMENT CO…

计算机毕业设计 家校互联管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

2024年录屏软件排行榜:班迪录屏等四款软件实测!

不论是学习、娱乐还是工作&#xff0c;都有可能需要用到屏幕录制功能。在这篇文章中&#xff0c;我们将从不同的使用场景出发&#xff0c;为大家推荐几款实用的录屏工具——福昕录屏大师、转转大师录屏、爱拍录屏以及班迪录屏。 Foxit REC 直达链接&#xff08;复制到浏览器打…

Flexible组件的用法

文章目录 1. 概念介绍2. 使用方法3. 示例代码我们在上一章回中介绍了扩展内容相关的知识,本章回中将介绍Flexible组件.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 我们在前面章回中介绍了扩展列表相关的内容,当页面中其它组件和扩展列表一起使用时,扩展列表有可能会…

SpringBoot——基础配置

但是还需要删除pom.xml中的标签——模板的文件也同样操作 banner的选项——关闭 控制台 日志 banner图片的位置——还会分辨颜色 在 Java 的日志框架&#xff08;如 Logback、Log4j2 等&#xff09;中&#xff0c;logging.level.root主要用于设置根日志记录器的日志级别…

【Redis】如何在 Ubuntu 上安装 Redis 5

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 本期内容主要介绍如何在 Ubuntu 上安装 Redis5 一些碎碎念&#xff1a; 本来这期内容介绍如何在 Centos 安装 Redis …

常用的Java安全框架

Spring Security&#xff1a; 就像Java安全领域的“瑞士军刀”&#xff0c;功能全面且强大。 支持认证、授权、加密、会话管理等安全功能。 与Spring框架无缝集成&#xff0c;使用起来特别方便。 社区活跃&#xff0c;文档丰富&#xff0c;遇到问题容易找到解决方案。 Apach…

SigmaStudio控件Cross Mixer\Signal Merger算法效果分析

衰减与叠加混音算法验证分析一 CH2:输入源为-20dB正弦波1khz CH1叠加混音&#xff1a;参考混音算法https://blog.csdn.net/weixin_48408892/article/details/129878036?spm1001.2014.3001.5502 Ch0衰减混音&#xff1a;外部多个输入源做混音时&#xff0c;建议参考该算法控件&…

网络通信——OSPF协议(基础篇)

这里基础是因为没有讲解OSPF中的具体算法过程&#xff0c;以及其中很多小细节。后续会更新。 目录 一.OSPF的基础信息 二.认识OSPF中的Router ID 三.OSPF中的三张表 四.OSPF中的度量方法&#xff08;计算开销值&#xff09; 五. OSPF选举DR和BDR&#xff08;就是这个区域…

简单vue指令实现 el-table 可拖拽表格功能

安装 SortableJS sorttableJs 相关优点如下&#xff1a; 相关配置项 参考 &#x1f449; SortableJS中文官网 pnpm i sortablejs封装成指令 不多逼逼&#xff0c;直接上才艺 &#x1f92a;&#x1f92a;&#x1f92a; 先安装一个 nanoid 插件 用于生成随机id&#xff0c;注…

图神经网络:处理复杂关系结构与图分类任务的强大工具

创作不易&#xff0c;您的打赏、关注、点赞、收藏和转发是我坚持下去的动力&#xff01; 图神经网络&#xff08;Graph Neural Network, GNN&#xff09;是针对图数据的一类神经网络模型。图数据具有节点&#xff08;节点代表实体&#xff09;和边&#xff08;边代表节点之间的…

LeetCode[中等] 55.跳跃游戏

给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 思路 贪心算法 可达位置…