C语言中如何进行内存管理

主页:17_Kevin-CSDN博客

收录专栏:《C语言》

C语言是一种强大而灵活的编程语言,但与其他高级语言不同,它要求程序员自己负责内存的管理。正确的内存管理对于程序的性能和稳定性至关重要。


一、引言

C 语言是一门广泛使用的编程语言,它为程序员提供了对内存的直接控制能力。这种对内存的控制使得 C 语言非常灵活,但也带来了更大的责任。在 C 语言中,程序员需要负责内存的分配和释放,否则可能会导致内存泄漏和其他内存管理问题。本文将深入探讨 C 语言的内存管理机制,包括内存分配、内存释放、内存泄漏等问题。

二、内存分配

C语言中有三种内存分配方式:

  • 静态内存分配
  • 栈内存分配
  • 动态内存分配

静态内存分配

静态内存分配:静态内存分配是在程序编译时进行的,它将内存分配给全局变量和静态变量。全局变量和静态变量的内存空间在程序运行期间一直存在,直到程序结束。静态内存分配的优点是内存分配和释放的效率高,缺点是内存使用不灵活,无法根据需要动态调整内存大小。

当我们创建变量的时候,系统将会自动的为变量分配空间:

//创建变量a
int a = 0;

可以观察到当创建变量a后系统会为a分配一块内存,这就是静态内存的分配。

栈内存的分配

栈内存分配是在程序运行时进行的,它将内存分配给函数内部的局部变量。栈内存的空间是有限的,当函数执行完毕后,栈内存会自动释放。栈内存分配的优点是内存管理简单,缺点是内存空间有限,不适合分配大内存。

例如:

当创建一个函数,在函数中创建一个变量local_num,和local_name

void test()
{int local_num = 17;char local_name = "Kevin";}int main()
{test();return 0;
}

 当调试时走过这两个局部变量但没有走出函数时可以观察到这两个变量成功的创建了:

 当走出函数后刷新即可发现两个变量变成了未标识变量:

这就是在函数中的栈内存分配,随用随分配,在用过后就销毁。

动态内存分配

动态内存分配是在程序运行时根据需要进行的内存分配。它使用 malloc() 函数或 calloc() 函数来分配内存空间,使用 free() 函数来释放内存空间。动态内存分配的优点是内存使用灵活,可以根据需要动态调整内存大小,缺点是内存管理复杂,容易出现内存泄漏等问题。

具体函数的使用可以翻阅博主这篇博客进行查阅

C/C++ (stdio.h)标准库详解-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/SDFsoul/article/details/135568683

1. malloc

malloc() 函数用于分配指定大小的内存块

int main() 
{int* ptr;// 分配 10 个整数的内存块ptr = (int*)malloc(10 * sizeof(int));if (ptr == NULL) {printf("内存分配失败\n");exit(1);}// 访问分配的内存for (int i = 0; i < 10; i++) {ptr[i] = i + 1;}// 输出分配的内存中的值for (int i = 0; i < 10; i++) {printf("%d ", ptr[i]);}printf("\n");// 释放内存free(ptr);return 0;
}

在上述示例中,malloc() 函数用于分配 10 个整数的内存块。如果内存分配成功,ptr 将指向分配的内存块,否则输出错误信息并退出程序。然后,可以通过 ptr 访问和修改分配的内存。最后,使用 free() 函数释放分配的内存块。

2. calloc

calloc() 函数用于分配指定数量的元素,并将它们初始化为 0

#include <stdio.h>
#include <stdlib.h>int main() 
{int* ptr;// 分配 10 个整数的内存块,并将它们初始化为 0ptr = (int*)calloc(10, sizeof(int));if (ptr == NULL) {printf("内存分配失败\n");exit(1);}// 访问分配的内存for (int i = 0; i < 10; i++) {printf("%d ", ptr[i]);}printf("\n");// 释放内存free(ptr);return 0;
}

在上述示例中,calloc() 函数用于分配 10 个整数的内存块,并将它们初始化为 0。如果内存分配成功,ptr 将指向分配的内存块,否则输出错误信息并退出程序。然后,可以通过 ptr 访问和修改分配的内存。最后,使用 free() 函数释放分配的内存块。

3. free

free() 函数用于释放之前分配的内存块,在上文malloc和calloc中均用到了free函数,目的就是在使用完分配的内存块后进行释放,避免内存泄漏。

三、内存释放

在 C 语言中,内存释放是非常重要的。如果忘记释放不再使用的内存,就会导致内存泄漏。内存泄漏会导致程序的性能下降,甚至可能导致程序崩溃。在 C 语言中,有两种常见的内存释放方式:手动释放和自动释放。

1. 手动释放

手动释放是指程序员使用 free() 函数来释放不再使用的内存空间。在使用动态内存分配时,程序员需要在不再使用内存空间时手动调用 free() 函数来释放内存。

#include <stdlib.h>int* allocate_memory(int size) 
{int* memory = (int*)malloc(size * sizeof(int));if (memory == NULL) {printf("内存分配失败\n");exit(1);}return memory;
}void free_memory(int* memory) 
{if (memory != NULL) {free(memory);}
}int main() 
{int* dynamic_memory = allocate_memory(10);for (int i = 0; i < 10; i++) {dynamic_memory[i] = i + 1;}for (int i = 0; i < 10; i++) {printf("%d ", dynamic_memory[i]);}printf("\n");free_memory(dynamic_memory);return 0;
}
  1. allocate_memory 函数用于动态分配一块大小为 size 个整数的内存空间,并返回指向该内存空间的指针。如果内存分配失败,程序会输出提示信息并调用 exit(1) 来退出程序。

  2. free_memory 函数用于释放动态分配的内存空间,首先检查指针是否为空,然后调用 free 函数进行内存释放。

  3. main 函数中,首先调用 allocate_memory 函数分配了包含 10 个整数的内存空间,并将返回的指针赋值给 dynamic_memory。然后使用循环给动态分配的内存赋值,并输出每个元素的值。

  4. 最后,通过调用 free_memory 函数释放动态分配的内存空间,避免内存泄漏。

2. 自动释放

自动释放是指在某些情况下,C 语言的编译器会自动释放不再使用的内存空间。例如,当函数执行完毕后,编译器会自动释放函数内部的栈内存。

#include <stdio.h>void function() 
{int local_variable = 30;printf("局部变量的值:%d\n", local_variable);
}int main() 
{function();return 0;
}

四、内存泄漏

内存泄漏指程序在不再需要使用内存时未将其释放,导致系统内存资源浪费。内存溢出则是指程序访问超出了已分配内存块的范围(例如数组越界访问)。


五、指针和内存

在C语言中,指针与内存密切相关。我们可以通过指针指向目标地址来直接操作内存,包括访问、修改和释放内存。

指针数组

int *ptrArray[10]; // 声明一个包含10个整型指针的数组

二级指针

int **pptr; // 声明一个二级整型指针
int value = 100;
int *ptr = &value;
pptr = &ptr; // 将ptr的地址赋给pptr

指针与结构体

结构体和指针的结合也是C语言中常见的用法,可以方便地操作复杂的数据结构(例如链表)。


希望这能帮助您更好地理解和应用C语言中的内存管理知识。

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

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

相关文章

学习Android的第十八天

目录 Android 可复用 BaseAdapter 为什么使用BaseAdapter&#xff1f; 如何使用BaseAdapter&#xff1f; Android GridView 网格视图 GridView 属性 示例 Android Spinner 下拉选项框 Spinner Spinner 属性 示例 Android AutoCompleteTextView 自动完成文本框 Auto…

饲料加工设备让饲料厂和养殖场生产轻松高效

亲爱的饲料厂和养殖场朋友们&#xff0c;你们是不是正在寻找一款方便高效的饲料加工设备呢&#xff1f;那么我们的产品就是你们选择&#xff01; 郑州永兴专为饲料生产而设计的饲料加工设备&#xff0c;无论是养殖场还是饲料厂&#xff0c;都离不开它的帮助。我们提供大中小型…

51单片机-(定时/计数器)

51单片机-&#xff08;定时/计数器&#xff09; 了解CPU时序、特殊功能寄存器和定时/计数器工作原理&#xff0c;以定时器0实现每次间隔一秒亮灯一秒的实验为例理解定时/计数器的编程实现。 1.CPU时序 1.1.四个周期 振荡周期&#xff1a;为单片机提供定时信号的振荡源的周期…

卡尔曼滤波器的定义,实例和代码实现

卡尔曼滤波器(Kalman filter)是一种高效的递归滤波器, 能够从一系列包含噪音的测量值中估计动态系统的状态. 因为不需要存储历史状态, 没有复杂计算, 非常适合在资源有限的嵌入式系统中使用. 常用于飞行器的导引, 导航及控制, 机械和金融中的时间序列分析, 轨迹最佳化等. 卡尔曼…

LeetCode59. 螺旋矩阵 II(C++)

LeetCode59. 螺旋矩阵 II 题目链接代码 题目链接 https://leetcode.cn/problems/spiral-matrix-ii/ 代码 class Solution { public:vector<vector<int>> generateMatrix(int n) {vector<vector<int>> res(n, vector<int>(n, 0));int startx …

Linux第67步_linux字符设备驱动_注册和注销

1、字符设备注册与注销的函数原型” /*字符设备注册的函数原型*/ static inline int register_chrdev(unsigned int major,\ const char *name, \ const struct file_operations *fops) /* major:主设备号&#xff0c;Limnux下每个设备都有一个设备号&#xff0c;设备号分…

点云检测网络PointPillar

1. 提出PointPillar的目的 在此之前对于不规则的稀疏的点云的做法普遍分为两派: 一是把点云数据量化到一个个Voxel里&#xff0c;常见的有VoxelNet和SECOND , 但是这种做法比较普遍的问题是由于voxel大部分是空集所以会浪费算力(SECOND利用稀疏卷积解决了它) &#xff0c;但是…

MNIST数据集下载(自动下载)

&#x1f4da;**MNIST数据集下载(自动下载)**&#x1f4da; &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程 &#x1f448; 希望得到您的…

本地数据库Room——study_1

目录 1.概念 2.组成 3.导入依赖 4.具体实现 4.1 数据表的设置 4.2 方法接口 4.3 数据库类 -》 基石&#xff0c;使用模板 4.4 实现真正的实例Room库 1.概念 Room 持久性库在 SQLite 上提供了一个抽象层&#xff0c;以便在充分利用 SQLite 的强大功能的同时&#xff0c…

Qt程序设计-钟表自定义控件实例

本文讲解Qt钟表自定义控件实例。 效果如下: 创建钟表类 #ifndef TIMEPIECE_H #define TIMEPIECE_H#include <QWidget> #include <QPropertyAnimation> #include <QDebug> #include <QPainter> #include <QtMath>#include <QTimer>#incl…

基于InternLM和LangChain搭建自己的知识库

背景 LLM存在一定的局限性&#xff0c;如&#xff1a; 知识时效性受限&#xff1a;如何让LLM能够获取最新的知识专业能力有限&#xff1a;如何打造垂直领域的大模型定制化成本高&#xff1a;如何打造个人专属的LLM应用 正文 为了突破LLM的局限性&#xff0c;目前有两种范式…

51单片机(6)-----直流电机的介绍与使用(通过独立按键控制电机的运行)

前言&#xff1a;感谢您的关注哦&#xff0c;我会持续更新编程相关知识&#xff0c;愿您在这里有所收获。如果有任何问题&#xff0c;欢迎沟通交流&#xff01;期待与您在学习编程的道路上共同进步。 目录 一. 直流电机模块介绍 1.直流电机介绍 2.电机参数 二. 程序设计…

day08_面向对象基础_内存关系

零、今日内容 一、作业 二、面向对象 一、作业 package com.qf.homework;import java.util.Arrays;/*** --- 天道酬勤 ---** author QiuShiju* date 2024/2/28* desc*/ public class Homework {public static void main(String[] args) {test();}//写一个方法 用于合并两个int…

事件驱动的奇迹:深入理解Netty中的EventLoop

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 事件驱动的奇迹&#xff1a;深入理解Netty中的EventLoop 前言基础概念EventLoop的工作原理Channel与EventLoop的关系定时任务与延时任务EventLoop的生命周期EventLoop中的线程模型性能优化与最佳实践 …

minikube windows 下载安装

下载地址 https://multipass.run/ 选择版本 下载结果 安装就是持续的下一步&#xff0c;安装后的效果 打开后的效果

【数据结构】从链表到LinkedList类

&#x1f9e7;&#x1f9e7;&#x1f9e7;&#x1f9e7;&#x1f9e7;个人主页&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388; &#x1f9e7;&#x1f9e7;&#x1f9e7;&#x1f9e7;&#x1f9e7;数据结构专栏&#x1f388;&#x1f388;&#x1f388;&…

5.WEB渗透测试-前置基础知识-常用的dos命令

内容参考于&#xff1a; 易锦网校会员专享课 上一篇内容&#xff1a;4.WEB渗透测试-前置基础知识-快速搭建渗透环境&#xff08;下&#xff09;-CSDN博客 常用的100个CMD指令 1.gpedit.msc—–组策略 2. sndrec32——-录音机 3. Nslookup——-IP地址侦测器 &#xff0c;是一个…

Vue.js实战:构建一个简单的学生管理系统

摘要&#xff1a; 本文将引导你使用Vue.js框架来构建一个完整的学生管理系统。我们将从环境搭建开始&#xff0c;逐步介绍Vue的核心概念、组件创建、数据管理、事件处理、路由配置以及项目构建等关键步骤。通过实际操作&#xff0c;你将能够掌握Vue.js的基础知识&#xff0c;并…

搭建XSS 测试平台

XSS 测试平台是测试XSS漏洞获取cookie并接收Web 页面的平台&#xff0c;XSS 可以做 JS能做的所有事&#xff0c;包括但不限于窃取cookie、后台增删改文章、钓鱼、利用XSS漏洞进 行传播、修改网页代码、网站重定向、获取用户信息(如浏览器信息、IP 地址)等。这 里使用的是基于x…

Linux:Kubernetes(k8s)——基础理论笔记(1)

我笔记来源的图片以及共享至GitHub&#xff0c;本章纯理论。这是k8s中部分的基础理论 &#x1f447; KALItarro/k8spdf: 这个里面只有一个pdf文件 (github.com)https://github.com/KALItarro/k8spdf&#x1f446; 什么是kubernetes kubernetes 是一个开源的&#xff0c;用于管…