首页 > 系统相关 >[C语言]-基础知识点梳理-动态内存管理

[C语言]-基础知识点梳理-动态内存管理

时间:2024-08-20 22:27:13浏览次数:8  
标签:知识点 malloc int void free C语言 动态内存 空间 开辟

前言

各位师傅大家好,我是qmx_07,今天给大家讲解动态内存管理的相关知识,下一章节更新 文件管理部分的知识点

为什么要进行动态内存分配

int val = 20;//在栈空间上开辟四个字节 
char arr[10] = {0};//在栈空间上开辟10个字节的连续空间 

上述的开辟空间的⽅式有两个特点:

  • 空间开辟⼤⼩是固定的。
  • 数组在申明的时候,必须指定数组的⻓度,数组空间⼀旦确定了⼤⼩不能调整
  • 有时候我们需要的空间⼤⼩在程序运⾏的时候才能知道,那数组的编译时开辟空间的⽅式就不能满⾜了,所以引申了动态内存的概念,让程序员自己申请和释放空间

malloc和free

malloc和free函数使用,需要加载<stdlib.h>头文件

malloc

void* malloc (size_t size);

这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。

  • 如果开辟成功,则返回一个指向开辟好空间的指针。
  • 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
  • 返回值的类型是 void ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。

free

void free (void* ptr);

free函数用来释放动态开辟的内存

  • 如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
  • 如果参数 ptr 是NULL指针,则函数什么事都不做。

代码演示

#include <stdio.h>
#include <errno.h>
int main()
{
	int arr[10] = { 0 };
	int* p = (int*)malloc(40);
	if (NULL == p)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	for (int i = 0; i <= 10; i++)
	{
		arr[i] = i;
	}
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	free(p);
	p = NULL;
	return 0;
}

在这里插入图片描述

  • 使用free函数 只是将这片内存空间 还给 操作系统,内容没有发生改变,所以我们需要把这个指针置空

calloc

void* calloc (size_t num, size_t size);
  • 函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0。
  • 与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0。

代码演示

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int* p = (int*)calloc(10, sizeof(int));
	if (NULL == p)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	free(p);
	p = NULL;
	return 0;
}

在这里插入图片描述

  • calloc = malloc + memset

realloc

  • 概念: 通过malloc或者calloc方式申请空间,可能过小或者过大,这时候就需要使用realloc来更改已经申请的内存空间大小
void* realloc (void* ptr, size_t size);
  • ptr 指针,也就是要改变的内存地址
  • size 要改变的大小

realloc 底层剖析

在这里插入图片描述
在这里插入图片描述

  • 第一种开辟情况,原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小的连续空间来使用。这样函数返回的是一个新的内存地址
  • 第二种开辟情况,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化

代码演示

在这里插入图片描述
在这里插入图片描述

  • 详情参考 底层剖析解释

动态内存错误

  • 对NULL指针的解引用操作
void test()
{
int *p = (int *)malloc(INT_MAX/4);
*p = 20;//如果p的值是NULL,就会有问题
free(p);
}
  • 对动态开辟空间的越界访问
void test()
{
int i = 0;
int *p = (int *)malloc(10*sizeof(int));
if(NULL == p)
{
exit(EXIT_FAILURE);
}
for(i=0; i<=10; i++)
{
*(p+i) = i;//当i是10的时候越界访问
}
free(p);
}
  • 对非动态开辟内存使用free释放
void test()
{
int a = 10;
int *p = &a;
free(p);
}
  • 使用free释放一块动态开辟内存的一部分
void test()
{
int *p = (int *)malloc(100);
p++;
free(p);//此时p的位置已经发生了变化,p不再指向动态内存的起始位置
}
  • 对同一块动态内存多次释放
void test()
{
int *p = (int *)malloc(100);
free(p);
free(p);//重复释放
}
  • 动态开辟内存忘记释放(内存泄漏)
void test()
{
int *p = (int *)malloc(100);
if(NULL != p)
{
*p = 20;
}
}
int main()
{
test();
while(1);
}
  • 重点:开辟空间之后,记得free置空

C/C++程序的内存开辟

在这里插入图片描述

  • 栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结
    束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是
    分配的内存容量有限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返
    回地址等。
  • 堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分
    配方式类似于链表。
  • 数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。
  • 代码段:存放函数体(类成员函数和全局函数)的二进制代码。

总结

  • 我们学习了malloc,calloc,realloc,以及c/c++程序的内存开辟,下一章节学习 文件管理

标签:知识点,malloc,int,void,free,C语言,动态内存,空间,开辟
From: https://blog.csdn.net/weixin_58038441/article/details/141339843

相关文章

  • C语言典型例题46
    《C程序设计教程(第四版)——谭浩强》题目:习题3.6企业发放的奖金根据利润提成。利润I低于或等于100000元的,奖金可提成10%;                   利润高于100000元,低于200000元(100000<I≤200000)时,低于100000元的部分按10%提成,高于1000......
  • C语言函数递归
    前言与概述本文章将通过多个代码并赋予图示,详细讲解C语言函数递归的定义和函数递归的运算过程。函数递归定义程序调用自身的编程技巧称为递归。递归作为一种算法在程序设计语言中广泛应用。一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法。它通常把一个大型......
  • C语言:递归
    递归简单来说就是函数自己调用自己。特点:一般代码比较简洁,没有出口。例子1:用一个函数计算阶乘#include<stdio.h>//不用递归intfac(intn){ intval=1; for(inti=1;i<=n;i++) { val*=i; } returnval;}//用递归intfac1(intn){ if(n==1) {......
  • c语言基础------数组指针
    在C语言中,数组指针是一种特殊的指针类型,它指向一个数组。具体来说,数组指针是指向数组首元素的指针,但它与普通指针有所不同,因为它包含了数组的大小信息。下面是关于数组指针的一些基本概念和用法:定义数组指针数组指针可以通过以下方式定义:int(*arrayPtr)[10];//arra......
  • c语言基础--------字符串指针
    在C语言中,字符串指针是一个指向字符类型的指针,通常用于指向字符串的第一个字符。字符串在C语言中通常表示为字符数组,而字符串指针则是用来存储这种字符数组首地址的变量。定义字符串指针字符串指针的定义方式如下:char*stringPtr;这里的char*表示stringPtr是......
  • Stream流的基本知识点
    Stream流结合了Lambda表达式,简化集合、数组的操作Stream流的使用步骤:1.先得到一条Stream流(流水线),并把数据放上去2.;利用Stream流中的API进行各种操作过滤转换中间方法方法调用完之后,还能继续进行方法调用统计打印终结方法方法调用完之后,就不能调用其他方法1.得到流的......
  • 数据结构-队列 c语言使用链表和数组分别实现
    队列定义队列(queue)是一种遵循先入后到规则的线性数据结构,将队列头部称为“队首”,尾部称为“队尾”,把元素加入队尾称为“入队”,删除队首元素称为“出队”。队列实现基于链表的实现将链表的头节点和尾结点分别视为“队首”和“队尾”,规定队尾仅可添加节点,队首仅可删除节点。......
  • 打印空心正方形(c语言)
    1.//KiKi学习了循环,BoBo老师给他出了一系列打印图案的练习,该任务是打印用“*”组成的“空心”正方形图案。//输入描述://多组输入,一个整数(3~20),表示输出的行数,也表示组成正方形边的“*”的数量。//输出描述://针对每行输入,输出用“*”组成的“空心”正方形,每个“*......
  • Python面试中常见的知识点和问题
    Python面试中常见的知识点和问题,供你参考: ###基础知识1.**数据类型**:  -基本类型:int,float,str,bool  -容器类型:list,tuple,set,dict 2.**控制结构**:  -条件语句:if,elif,else  -循环语句:for,while 3.**函数**:  -定义函数:def......
  • 【C语言】基础知识详解(二) 字符串
    一、什么是字符串?在C语言中,字符串是一种特殊的字符数组,用于存储一系列字符。字符串的表示:在C语言中,字符串是由字符组成的数组,并以空字符'\0'结束。空字符用于标识字符串的结束。例如,字符串"hello"在内存中实际上是{'h','e','l','l','o','\0'}。字符串声明:可以使......