C语言动态内存分配详解

article/2025/9/14 22:02:06

文章目录

  • 前言
  • 一、为什么存在动态内存分配
    • 1、已掌握的内存开辟方式
    • 2、上述开辟空间方式的特点
    • 3、为什么存在动态内存分配
  • 二、动态内存函数的介绍
    • 1、malloc
    • 2、free
    • 3、calloc
    • 4、realloc
  • 三、常见的动态内存错误
    • 1、对NULL指针的解引用操作
    • 2、对动态开辟内存的越界访问
    • 3、对非动态开辟内存使用free释放
    • 4、使用free释放动态开辟内存的一部分
    • 5、对同一块动态内存的多次释放
    • 6、动态开辟内存忘记释放(内存泄漏)
  • 四、几个经典的笔试题
    • 1、题目1
    • 2、题目2
    • 3、题目3
    • 4、题目4
  • 总结

前言

自从前两次博客写完以后,感觉对于我本人来说,收获很大,尤其是将学过的知识再度温习一遍,感觉基础扎实了很多,所以就养成了一个习惯,每学完一个模块,都会写一篇博客,不仅仅是写个我自己的,也是想通过这篇博客,与大家分享一些我的见解。本来周四就学完了动态内存分配,但是周末博主去玩了,于是忘记了写博客,现在加班奉上。

一、为什么存在动态内存分配

1、已掌握的内存开辟方式

在C语言中,我们将内存分为了4个区间:
代码区,全局变量与静态变量区,局部变量区即栈区,动态存储区,即堆(heap)区或自由存储区(free store)。

为了方便大家理解,图解如下:
在这里插入图片描述
通过之前的学习,我们了解了一些内存的使用方法:

(1)创建一个变量
当我们想要使用单一变量的时候,我们可以通过创建一个变量,来使用内存。

int a = 10;//局部变量 - 栈区
int g_a = 10;//全局变量 - 静态区

(2)创建一个数组
当我们需要使用多个相同类型变量的时候,我们可以通过创建一个数组,来使用内存。

int arr[10];//局部变量 - 栈区
int g_arr[10];//全局变量 - 静态区

2、上述开辟空间方式的特点

以上两种使用内存的方式是我们学过的,也是常用的,但是在某些情况下,仅仅有这两种方法是不足的。

例如:我们需要创建一个数组来存放一个班级的学生信息的时候。

我们在创建这个arr数组的时候,当我们直接给定数组的长度arr[50]的时候,这样是很简单,但是这样合理吗?
例1:

#include<stdio.h>
struct s
{char name[20];int age;
};
int main()
{struct s arr[50];// 50个struct s 类型的数据// 30 :不够// 60 :浪费return 0;
}

假设这个班级只有30个人,那么我们是不是就浪费了一部分的空间;假设这个班级有60个人,那么我们给定的50又不够。所以说这里给定多少都是不合理的。

这里有人又会说了,很简单啊:要多少给多少就好了嘛!就像这样
例2:

#include<stdio.h>
struct s
{char name[20];int age;
};
int main()
{int n = 0;scanf_s("%d", &n);struct s arr[n];//错误(活动)	E0028	表达式必须含有常量值return 0;
}

运行结果为:报错

事实证明,我们的想法很美妙,但是现实却很残酷:
这里的错误名称叫:表达式必须含有常量值
说明对于 struct s arr[n]; 这里的n是变量,那就不行了。

这里延伸一下:例2这种代码的写法叫做变长数组
对于变长数组这种写法目前仅对于C99是可运行通过的。

总结:上述开辟空间方式的特点
(1)开辟空间的大小是固定的;
(2)数组在声明的时候,必须制定数组的长度,它所需的内存在编译时分配。

3、为什么存在动态内存分配

我们对于内存开辟空间的需求,不仅仅局限于这些方式,有时候我们需要的空间大小在程序运行的时候才能知道,这时上述方式就不能达成目的了,所以动态内存分配就应运而生了。

二、动态内存函数的介绍

1、malloc

C语言提供了一个动态内存开辟的函数:

	void* malloc (size_t size);

malloc的全称是memory allocation,中文叫动态内存分配,用于申请一块连续的指定大小的内存块区域以void*类型返回分配的内存区域地址,当无法知道内存具体位置的时候,想要绑定真正的内存空间,就需要用到动态的分配内存,且分配的大小就是程序要求的大小。

这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。
(1)如果开辟成功,则返回一个指向开辟好空间的指针;
(2)如果开辟失败,则返回一个NULL指针,因此 malloc 的返回值一定要做检查;
(3)返回值的类型是 void*,所以 malloc 函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定;
(4)如果参数 size 为 0 ,malloc 的行为是标准是未定义的,取决于编译器。

举一个例子
例3:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
int main()
{// 向内存申请10个整形的空间int* p = (int*)malloc(10 * sizeof(int));// malloc -> #include<stdlib.h>//int* p = malloc(10 * sizeof(int));// 错误	 C2440	 “初始化” : 无法从“void * ”转换为“int* ”if (p == NULL){// 打印错误原因的一个方式printf("%s\n", strerror(errno));// strerror -> #include<string.h>// errno -> #include<errno.h>}else{// 正常使用空间int i = 0;for (i = 0; i < 10; i++){*(p + i) = i;}for (i = 0; i < 10; i++){printf("%d ", *(p + i));}}return 0;
}

运行结果为:
0 1 2 3 4 5 6 7 8 9

在例3中,我们如果采用 “ int* p = malloc(10 * sizeof(int)); ” 的方式来开辟空间,在大部分检测严格的编译器中,会报错,这是因为变量类型的不同,从这里我们也可以看出,malloc 开辟空间的返回值是 void* 类型;

上面我们也提到了:如果 malloc 开辟失败,则返回一个NULL指针,所以malloc 的返回值一定要做检查,所以我们用了一种特殊的方式来打印错误原因——“ printf("%s\n", strerror(errno)); ” ,这样如果开辟失败,编译器就不会报错了,而是在运行后将错误的原因打印出来。

易错提示:
因为我们计算机的内存也是有限的,所以我们不能为所欲为的开辟空间,当我们需要开辟的空间不够时,打印错误就会出现“Not enough space”。

2、free

紧接上文,我们不能为所欲为的开辟空间,因为空间是有限的,所以应当有借有还,我们在前边向系统借用了这么多内存,当我们用完以后,我们应该把这块内存还给系统,那么怎么还呢?这里就需要用到我们的 free 函数了。

C语言为我们提供了另外一个函数,专门用来做动态内存的释放和回收的:

	void free(void *ptr)

free函数用来释放动态开辟的内存:
(1)如果参数 ptr 指向的空间不是动态开辟的,那 free 函数的行为是未定义的;
(2)如果参数 ptr 是NULL指针,则函数什么操作都不进行。

先来看一个例子
例4:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
int main()
{// 向内存申请10个整形的空间int* p = (int*)malloc(10 * sizeof(int));// malloc -> #include<stdlib.h>//int* p = malloc(10 * sizeof(int));// 错误	 C2440	 “初始化”  :  无法从“void * ”转换为“int* ”if (p == NULL){// 打印错误原因的一个方式printf("%s\n", strerror(errno));// strerror -> #include<string.h>// errno -> #include<errno.h>}else{// 正常使用空间int i = 0;for (i = 0; i < 10; i++){*(p + i) = i;}for (i = 0; i < 10; i++){printf("%d ", *(p + i));}}// 当动态申请的空间不再使用的时候// 就应该还给操作系统free(p);p = NULL;return 0;
}

运行结果为:
0 1 2 3 4 5 6 7 8 9

对比例3和例4,例4只是多了两行代码:
free( p );
p = NULL;

有人会疑惑了,例3和例4的运行结果明明是一样的啊,那为什么我们还要多此一举,加上这两行代码呢?
没错看上去运行结果是一样的,但这仅仅只是对于我们代码量很少的情况下,我们申请的内存够用了,所以目的达到了;但是假设我们要做一项任务量巨大的工程的时候,我们只借不还,系统的内存在不断减少,我们还能继续写程序吗?所以应该从现在养成一个习惯,申请的内存,用完以后一定要进行 free()操作。

这里有人又有疑问了,那我们用完了内存,释放了不就好了吗?为什么还要把这个指针p置为空指针呢?
其实当我们free(p)操作结束以后,这块空间是释放了,但是p的值并没有改变,如果有人找到了这个p,进行了破坏,我们的程序就有可能出问题,所以我们不妨主动将p置为空指针,让有非分之想的人断绝这些念想。

光说不练,是学习编程语言的大忌,我们趁热打铁,来做一道练习题:
在这里插入图片描述
正确答案为:
例5:

#include "string.h"
#include <stdio.h>
#include<stdlib.h>
int main()
{char* src="hello,world"; char* dest=NULL;int len=strlen(src);dest=(char*)malloc(len+1);// 要为\0分配空间char* d=dest;char* s=src+len-1;// 指向最后一个字符while(len--!=0){ *(d++)=*(s--);// 注意不要丢掉*号*d ='\0';// 字符串的结尾不要忘记'\0'} printf("%s",dest);free(dest);// 使用完要释放空间,避免内存泄露dest = NULL; // 释放不等于安全,将其置为空指针的操作不可省略return 0;
}

3、calloc

C语言还提供了一个函数叫 calloc ,calloc 函数也用来动态内存分配:

	void* calloc(size_t num,size_t size)

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

举个例子:
例6:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
int main()
{int* p = (int*)calloc(10sizeof(int));// calloc -> #include<stdlib.h>if (p == NULL){// 打印错误原因的一个方式printf("%s\n", strerror(errno));// strerror -> #include<string.h>// errno -> #include<errno.h>}else{// 正常使用空间int i = 0;for (i = 0; i < 10; i++){printf("%d ", *(p + i));}}// 当动态申请的空间不再使用的时候// 就应该还给操作系统free(p);p = NULL;return 0;
}

运行结果为:
0 0 0 0 0 0 0 0 0 0

由此可见:calloc 函数会将动态开辟空间的每个字节初始化为0

4、realloc

回归今天的核心问题,如果我们在使用内存的过程中需要对内存的大小进行调整怎么办呢?

C语言同样为我们提供了一个函数叫 realloc ,realloc 函数可以让动态内存管理更加灵活:

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

(1)ptr 是要调整的内存地址;
(2)size 是调整后的新大小;
(3)返回值为调整之后的内存起始位置;

举个例子:
例7:

#include<stdio.h>
#include<stdlib.h>
int main()
{int* p = (int*)malloc(20);for (int i = 0; i < 5; i++){*(p + i) = i;}for (int i = 0; i < 5; i++){printf("%d ", *(p + i));}int* p2 = (int*)realloc(p, 40);for (int j = 5; j < 10; j++){*(p + j) = j;}for (int j = 5; j < 10; j++){printf("%d ", *(p + j));}free(p);p = NULL;return 0;
}

运行结果为:
0 1 2 3 4 5 6 7 8 9

(4)这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到 新 的空间;

(5)realloc 在调整内存空间的过程中存在两种情况
①原有空间之后有足够大的空间
此时,直接在原有内存之后追加空间,原来空间的数据不发生变化。

②原有空间之后没有足够大的空间
在堆空间上另找一个合适大小的连续空间来使用,这样函数返回的是一个新的内存地址。

图解如下:
在这里插入图片描述

三、常见的动态内存错误

1、对NULL指针的解引用操作

例8:

#include<stdio.h>
#include<stdlib.h>
int main()
{// 1.对NULL指针解引用操作int* p = (int*)malloc(40);// 万一malloc失败了,p就被赋值为NULL// 不安全// 记得判断p是否为空int i = 0;for (i = 0; i < 10; i++){*(p + i) = i;}free(p);p = NULL;return 0;
}

对于例8,如果 malloc 开辟空间失败,此时 p 被赋值为NULL,而下面对于空指针进行操作, *(p + i) 始终为非法地址,我们的操作始终为非法操作,所以我们一定要在使用前记得判断p是否为空。

2、对动态开辟内存的越界访问

例9:

#include<stdio.h>
#include<stdlib.h>
int main()
{// 2.对动态开辟内存的越界访问int* p = (int*)malloc(40);// 10个int -> 0-9if (p == NULL){return 0;}int i = 0;// 越界for (i = 0; i <= 10; i++){*(p + i) = i;}free(p);p = NULL;return 0;
}

对于例9,我们使用 malloc 向系统申请了 10个int 类型,但是我们在后边访问了 11个int 类型,运行程序的时候就会出现假死的情况,虽然是动态内存,但是也是有边界的,一但越界访问,程序就会出现问题。

3、对非动态开辟内存使用free释放

例10:

#include<stdio.h>
#include<stdlib.h>
int main()
{// 3.对非动态开辟内存使用free释放int a = 10;int* p = &a;free(p);p = NULL;return 0;
}

对于例10,a的空间是存放与栈区的,它并不是动态开辟的空间,free函数释放的一定是堆区上开辟的空间,如果对非动态开辟内存使用free释放,程序就会出现假死的情况。

4、使用free释放动态开辟内存的一部分

例11:

#include<stdio.h>
#include<stdlib.h>
int main()
{// 4.使用free释放动态开辟内存的一部分int* p = (int*)malloc(40);if (p == NULL){return 0;}int i = 0;for (i = 0; i < 10; i++){*p++ = i;}// 回收空间free(p);p = NULL;return 0;
}

对于例11,我们有这样一个操作 “*p++ = i;” ,当这个操作结束的时候,我们的指针p指向的空间已经不是我们动态开辟的完整空间了,不仅仅局限指向末尾,只要这里的p不再指向空间的初始位置,都会导致程序的崩溃。

5、对同一块动态内存的多次释放

例12:

#include<stdio.h>
#include<stdlib.h>
int main()
{// 5.对同一块动态内存的多次释放int* p = (int*)malloc(40);if (p == NULL){return 0;}// 假设使用了空间// 释放free(p);// ...很多行代码过后 free(p);// 再次释放 return 0;
}

对于例12,我们在使用完空间后,释放了空间,在很多行代码过后,又释放了一次空间,这样程序同样会假死,那么我们如何改进呢?
例13:

#include<stdio.h>
#include<stdlib.h>
int main()
{// 5.对同一块动态内存的多次释放int* p = (int*)malloc(40);if (p == NULL){return 0;}//可以这样free(p);p = NULL;free(p);return 0;
}

像例13这样,每次释放完空间,主动将p置为空指针,这样就可以有效避免了上述情况,因为我们之前提到过:
对于free函数:如果参数 ptr 是NULL指针,则free函数什么操作都不进行。

6、动态开辟内存忘记释放(内存泄漏)

例14:

#include<stdio.h>
#include<stdlib.h>
int main()
{// 6.动态开辟内存忘记释放(内存泄漏)while (1){malloc(1);//警告	C6031	返回值被忽略 : “malloc”。}return 0;
}

对于例14,当我们开辟内存忘记释放的时候,就会造成内存泄漏。我们的电脑可能就会出现死机的情况,遇到这种情况我们一般都会重启,但是当我们写程序达到几万行的时候,出现了这种问题,那将是一个十分恐怖的事情。

四、几个经典的笔试题

1、题目1

void GetMemory(char* p)
{p = (char*)malloc(100);
}
void Test(void)
{char* str = NULL;GetMemory(str);strcpy(str, "hello world");printf(str);
}

请问:运行 Test 函数会有什么样的结果?
答案为:程序崩溃

对于本题,很多人的注意力会集中于 “printf(str);” ,实际上这里并没有问题,它等价于 “printf("%s\n",str);” 。

解析代码:
看到 “GetMemory(str);” ,我们在这里传递的是 str 本身的值,而不是 str 的地址,进入 GetMemory 函数以后,我们在堆上开辟了100个空间,我们将这些空间放置在 p 中,这里的 p 作为一个形参变量,在 GetMemory 函数结束以后,这个 p 就销毁了, 实际上 str 仍然是NULL,而接下来我们想要将 “hello world” copy 到 str 中去,但是 str 作为NULL,它并没有指向一个有效的空间,进行操作的时候,无法避免的进行了非法访问,虽然后边的 printf 操作没有问题,但是程序在 strcpy 操作时就已经崩溃了。

总结:
(1)运行代码程序会出现崩溃现象;
(2)程序存在内存泄漏问题:
str 以值传递的形式给 p
p 是 GetMemory 函数的形参,只在函数内有效
等 GetMemory 函数返回之后,动态开辟内存尚未释放
并且无法找到,所以会造成内存泄漏

2、题目2

“返回栈空间地址问题”

char* GetMemory(void)
{char p[] = "hello world";return p;
}
void Test(void)
{char* str = NULL;str = GetMemory();printf(str);
}

请问:运行 Test 函数会有什么样的结果?
答案为:随机值(或者崩溃)

解析代码:
看到 “str = GetMemory();” ,进入 GetMemory 函数的时候,p[] 这个数组是GetMemory 函数内的形参,它申请了一个空间,这个空间只在 GetMemory 函数内存在,在 GetMemory 函数结束的时候,的确将 p 的地址返回了,放置在 str 中,但是当 GetMemory 调用完成之后,p 这个数组开辟的空间返还给操作系统了,这个空间里存放的值,我们是不清楚的,接下来 “printf(str);”
打印出来的值我们不清楚,所以结果为随机值。

3、题目3

void* GetMemory(char** p, int num)
{*p = (char*)malloc(num);
}
void Test(void)
{char* str = NULL;GetMemory(&str, 100);strcpy(str, "hello");printf(str);
}

请问:运行 Test 函数会有什么样的结果?
答案为:
(1)输出hello
(2)但是有内存泄漏

解析代码:
看到 “GetMemory(&str, 100);” ,将 str的地址传入 GetMemory 函数,用二级指针p 来接收,那么 *p 指向的地址即为 str ,然后将 “hello” copy 到 str 当中,再打印出来,这些操作都没有问题,但是当我们使用完 str 以后,忘记释放动态开辟的内存,导致了内存泄漏。

4、题目4

void Test(void)
{char* str = (char*)malloc(100);strcpy(str, "hello");free(str);if (str != NULL){strcpy(str, "world");printf(str);}
}

请问:运行 Test 函数会有什么样的结果?
答案为:
(1)world
(2)非法访问内存(篡改动态内存区的内容,后果难以预测,非常危险)

解析代码:
首先,我们向系统申请了100个字节,地址存放在 str 中;然后,我们把 “hello” copy 到 str 当中去;接下来,我们释放了这块空间,之后, str 指向的这块空间已经还给操作系统了;然后,进行判断: str 是否为空指针,虽然之前我们对申请的动态内存进行了释放,但是 str 的值并没有改变,仍然是 “hello”,所以它不为空指针;进入if语句后,将 “world” copy 到 str 当中,world 就把 hello 给覆盖了;所以打印 str 以后结果为 world。

虽然打印了world,但是这个程序依然出了问题,对于 “free(str);” 操作:已经把空间释放掉了,这表明这块空间已经不属于我们了,我们已经不能再使用这块空间了,但是接下来我们还将 world 放进去,并且打印,这就属于非法访问内存了。

提示:free(p)和p=NULL一定要连贯使用!

总结

关于动态内存分配的讲解就到此结束了,动态内存分配其实并不困难,更多的还是一些概念的背诵,只要我们牢记这些易错点,拿捏起来,还是轻轻松松的!加油,冲冲冲!
ps:动态内存分配拖了蛮久的,关于文件的博客,博主会快马加鞭的肝的(doge)


http://chatgpt.dhexx.cn/article/M2xja7iv.shtml

相关文章

动态内存管理(内存的分配与回收)详解

** 1. 数据结构之动态内存管理机制 ** 通过前面的学习&#xff0c;介绍很多具体的数据结构的存储以及遍历的方式&#xff0c;过程中只是很表面地介绍了数据的存储&#xff0c;而没有涉及到更底层的有关的存储空间的分配与回收&#xff0c;从本节开始将做更深入地介绍。 在使…

关于C++的动态内存分配

为什么要使用动态内存分配&#xff1f; 比较常见的情况是当我们使用一个数组时&#xff0c;我们需要去声明它&#xff0c;同时我们还需要提供给它一个编译时常量用于指定数组的长度。但是&#xff0c;我们有时候需要的数组并不是定长的。例如&#xff0c;我们要存储一个班级所…

【C语言】动态内存的分配

目录 &#x1f34b;&#x1f34b;前言 &#x1f34b;&#x1f34b;动态内存分配的定义 &#x1f34b;&#x1f34b;动态内存的优势 &#x1f34b;&#x1f34b;<1> 可以控制内存的大小 &#x1f34b;&#x1f34b;<2> 可以多次利用这部分空间 &#x1f34b;…

动态内存分配函数

一、静态存储分配与动态存储分配&#xff1a; &#xff08;1&#xff09;静态存储分配 通常定义变量&#xff08;或对象&#xff09;&#xff0c;编译器在编译时都可以根据该变量&#xff08;或对象&#xff09;的类型知道所需内存空间的大小&#xff0c;从而系统在适当的时候…

内存动态分区分配算法

文章目录 动态分区分配1. 首次适应算法&#xff08;First Fit&#xff09;2. 邻近适应算法&#xff08;Next Fit&#xff09;3. 最佳适应算法&#xff08;Best Fit&#xff09;4. 最坏适应算法&#xff08;Next Fit&#xff09; 总结 动态分区分配 所谓动态分区分配&#xff0…

C++之new动态分配内存生成数组

【任务1】&#xff1a; 编写并测试3*3矩阵转置函数&#xff0c;使用数组保存3*3矩阵。 实验要求 &#xff08;1&#xff09; 转置函数参数为二维数组&#xff1b; &#xff08;2&#xff09; 在main函数中实现输入、输出 #include <iostream> using namespace std…

C语言中的动态内存分配

大家好&#xff0c;今天简单讲一讲C语言中的动态内存分配。 补充&#xff1a;C程序中的内存块。 在C程序中&#xff0c;通常将内存划分为以下六个区域&#xff1a; &#xff08;1&#xff09;内核区域。这块区域是操作系统的&#xff0c;用户不能使用。 &#xff08;2&…

C语言动态分配内存

C语言动态分配内存 malloc 动态开辟内存的函数&#xff1a; void* malloc (size_t size); 这个函数向内存申请⼀块连续可⽤的空间&#xff0c;并返回指向这块空间的指针 如果开辟成功&#xff0c;则返回⼀个指向开辟好空间的指针 如果开辟失败&#xff0c;则返回⼀个NULL…

C/C++动态分配内存的几种方法

使用C/C编程时&#xff0c;会经常动态分配内存&#xff0c;以便合理使用内存&#xff0c;本文主要讲述动态内存分配的几种方法及一些原理&#xff0c;理解不深刻之处欢迎指教。 引言 为什么要进行动态内存分配&#xff1f;以数组为例&#xff0c;数组元素在内存中存储的地址是…

sadad

出版社&#xff1a; 河北少年儿童出版社 ISBN&#xff1a;12176804 版次&#xff1a;1 商品编码&#xff1a;12176804 包装&#xff1a;精装 丛书名&#xff1a; 幼儿家庭课堂 开本&#xff1a;12开 出版时间&#xff1a;2017-05-01 用纸&#xff1a;铜版纸 适读人群 &#xff…

SAADC

电流 :EasyDMA draws about 1.2 mA, and added to the 700 uASAADC current it sums to ~2 mA。和实测差不多 官方例程解析:TIMER + PPI +SAADC。 特征: 1、 支持8/10/12位分辨率,和14位过采样分辨率 2、 8通道:单端输入最多可同时配置8个通道 和 差分输入…

SAZS~

本文提出了一种新颖的形状感知零样本语义分割&#xff08;SAZS&#xff09;框架&#xff0c;利用大规模预训练视觉语言模型特征空间中丰富的先验知识&#xff0c;并通过在边界检测约束任务上进行联合训练来融合形状感知 论文链接&#xff1a;https://arxiv.org/abs/2304.08491…

SASSD

Structure Aware Single-stage 3D Object Detection from Point Cloud 文章&#xff1a;SA-SSD 代码&#xff1a;SA-SSD 这是来自香港理工大学和达摩院的一篇文章&#xff0c;一作是为在读的博士生&#xff0c;何晨航。通讯作者是张磊&#xff0c;香港理工大学的博导&#x…

Sarsa

基本概念 Sarsa Sarsa算法与Q-Learning算法极为相似&#xff0c;‘sarsa’五个字母的含义即s(当前状态)&#xff0c;a(当前行为)&#xff0c;r(奖励)&#xff0c;s(下一步状态)&#xff0c;a(下一步行为)&#xff0c;也就是说我们在进行这一步操作时已经想到当前s对应的a&…

反激电源

扶苗平衡&#xff1a;是针对电感的&#xff0c;不是针对变压器的&#xff1b;是电感稳态期间的情况&#xff0c;不是暂态期间的情况&#xff1b; 一个周期内&#xff0c;电感开通期间两端的电压乘以开通时间电感关断期间两端电压乘以关断时间。 对于反激变压器&#xff0c;其实…

Part-Ⅰ2. 稳态变换器分析原则(二)

2.4 Cuk电路分析 作为第二个示例&#xff0c;变换器可以实现类似buck-boost电路功能&#xff1a;升高或降低电压幅值&#xff0c;并且转换极性。其电路如如下。 该转换器通过电容进行能量传输。当开关打到位置2时&#xff0c;电容 C 1 C_1 C1​通过 L 1 L_1 L1​连到输入电源…

buck-boost基本模型

1.电容模型 2.电感模型 3.伏秒平衡 4.电容电感 5.BUCK 6.boost 7.参考资料 《开关电源的基本概念和分析方法》

2、Principles of Steady-State Converter Analysis

2、Principles of Steady-State Converter Analysis 伏秒平衡与安秒平衡 在电路平衡时&#xff0c;作为存储元件的电感与电容&#xff0c;其储存的能量不可能无穷大&#xff0c;必然会稳在一个稳定值。 稳定后必然有在一个开关周期内有 所以 在求解时&#xff0c;只要根据…

1dB压缩点和三阶交调点、相位差与延时

1dB压缩点与三阶交调点 要知道放大器是一个非线性系统&#xff0c;传输函数基本用泰勒级数表示 如果输入信号幅度很小&#xff0c;那么上式中2次及以上的项就可以忽略而成为小信号的情况。在许多情况下我们可以忽略3次以上的项。 如果输入一个正弦信号 1、可以看到一个单频率…

半桥电路注意事项

应注意的几点问题 偏磁问题 原因&#xff1a;由于两个电容连接点A的电位是随Q1、Q2导通情况而浮动的&#xff0c;所以能够自动的平衡每个晶体管开关的伏秒值&#xff0c;当浮动不满足要求时&#xff0c;假设 Q1、Q2具有不同的开关特性&#xff0c;即在相同的基极脉冲宽度tt1下&…