当前位置: 首页 > news >正文

<C语言> 动态内存管理

1.动态内存函数

为什么存在动态内存分配?

int main(){int num = 10;  //向栈空间申请4个字节int arr[10];   //向栈空间申请了40个字节return 0;
}

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

  1. 空间开辟大小是固定的。
  2. 数组在声明的时候,必须指定数组的长度,它所需要的内存在编译时分配。

但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道,那数组的编译时开辟空间的方式就不能满足了。这时候就需要动态内存开辟了。

1.1 malloc和free

malloc()是用于在程序执行期间动态分配内存。它的全称是"memory allocation",意为内存分配。malloc()函数是C标准库的一部分,它的声明在stdlib.h头文件中。

函数原型如下:

void* malloc(size_t size);

在这里,size是你想要分配的字节数,函数返回一个指向分配的内存块起始地址的指针。malloc()函数的返回类型是void*,这意味着返回的指针可以赋值给任何指针类型而无需显式转换。

下面简要解释一下malloc()的工作原理:

1.你提供想要分配的字节数,malloc()在堆内存中搜索一个足够大的连续内存块来存储这些字节。

2.如果找到了合适的内存块,它将其标记为已使用,并返回该内存块的起始地址的指针。

3.如果找不到足够大的内存块,它将返回一个NULL指针,表示内存分配失败。

注意:使用malloc()分配的内存需要使用free()函数显式地释放,否则会导致内存泄漏。

void free(void* ptr);

free()函数接受之前分配的内存块的指针,并将其释放,使其可供将来的动态分配使用。如果忘记释放之前分配的内存,程序每次运行分配代码时都会消耗更多内存,最终可能导致内存耗尽。

#include <stdio.h>
#include <stdlib.h>int main() {int n = 5;int* dynamicArray = (int*)malloc(n * sizeof(int));if (dynamicArray == NULL) {printf("内存分配失败!\n");} else {// 使用分配的内存块for (int i = 0; i < n; i++) {dynamicArray[i] = i + 1;}// 当不再需要分配的内存时,记得释放它free(dynamicArray);dynamicArray = NULL}return 0;
}

在调用free()函数释放动态分配的内存后,将指针dynamicArray设置为NULL是一个良好的习惯,但不是必须的。

设置指针为NULL的优点:

  1. 避免悬挂指针(Dangling Pointer):如果在释放内存后不将指针设置为NULL,该指针将仍然保留先前的地址。如果你在后续代码中继续使用该指针,可能会导致悬挂指针,即指针指向的内存已经被释放,这可能导致程序崩溃或产生难以调试的错误。将指针设置为NULL可以帮助你避免这种情况,因为如果尝试使用空指针,程序将产生明确的错误(空指针解引用)。
  2. 避免重复释放:在释放内存后,如果将指针设置为NULL,你可以通过检查指针是否为NULL来确定是否已经释放了内存。如果你在后续代码中错误地再次调用free(),会导致未定义的行为。

如果你在后续代码中小心地避免悬挂指针和重复释放内存,那么不设置为NULL也不会导致问题。然而,这是一个简单且有助于防范错误的额外保护措施,所以建议在释放内存后将指针设置为NULL

1.2 calloc

calloc()是另一个动态内存分配函数,也属于标准C库(stdlib.h头文件)。与malloc()功能类似,但在使用上有一些区别。

calloc()函数的原型如下:

void* calloc (size_t num, size_t size);

其中num是你想要分配的元素数量,size是每个元素的大小(以字节为单位)。calloc()函数会为num * size字节的内存块分配空间,并将该内存块中的所有位初始化为零。

相对于malloc()calloc()的一个优势是它会自动初始化分配的内存,这意味着你不需要手动将分配的内存清零。在某些情况下,这可能是非常有用的,特别是当你需要确保分配的内存一开始就是零值时。

实例:

#include <stdio.h>
#include <stdlib.h>int main() {int n = 5;int* dynamicArray = (int*)calloc(n, sizeof(int));if (dynamicArray == NULL) {printf("内存分配失败!\n");} else {// 使用分配的内存块,这里的内存已经被初始化为零for (int i = 0; i < n; i++) {printf("%d ", dynamicArray[i]); // 输出: 0 0 0 0 0}// 当不再需要分配的内存时,记得释放它free(dynamicArray);}return 0;
}

总结:

calloc = malloc+memset 初始化为0

1.3 realloc

realloc是一个用于重新分配内存块大小的函数。具体而言,它可以用于更改之前通过malloccalloc分配的内存块的大小。

realloc函数的声明如下:

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

参数说明:

  • ptr:指向之前已分配内存块的指针。如果ptr为NULL,则realloc的行为就相当于malloc,即分配一个新的内存块。
  • size:新的内存块大小,以字节为单位。

realloc的工作原理如下:

  1. 如果ptr为NULL,那么realloc的行为就等同于malloc(size),它将分配一个新的大小为size字节的内存块,并返回指向该内存块的指针。
  2. 如果size为0,且ptr不为NULL,那么realloc的行为就等同于free(ptr),即释放掉之前分配的内存块,并返回NULL指针。
  3. 如果ptr不为NULL且size不为0,realloc将尝试重新分配之前分配的内存块。可能发生以下几种情况:
    • 如果之前分配的内存块大小大于或等于size,则不会分配新的内存块,而是简单地返回原始内存块的指针,不会改变原内存块的内容。
    • 如果之前分配的内存块大小小于sizerealloc会尝试将原始内存块扩展到新的大小。这可能会**在原始内存块后面的可用内存空间进行扩展,如果没有足够的连续空间来扩展,则realloc可能会在另一个地方重新分配一个新的内存块,并将原始内容复制到新的内存块中。**这意味着realloc有可能返回一个新的指针,而不是原始指针,所以在使用realloc后,最好将返回的指针赋值给原来的指针。
    • 如果realloc在新的内存块分配失败时,将返回NULL,并且之前分配的内存块仍然保持未更改。

使用realloc时,应该特别注意以下几点:

  • 如果realloc返回NULL,表示重新分配失败,原来的指针仍然有效,为避免内存泄漏,应该保存原来的指针,并根据需要释放之前的内存块。
  • 当使用realloc时,最好不要直接修改原始指针,而是将realloc的结果赋值给原始指针,以防止意外的内存问题。

实例:

#include <stdio.h>
#include <stdlib.h>
int main() {int *p = (int *) malloc(40);if (p == NULL)return 1;//使用int i = 0;for (i = 0; i < 10; i++) {*(p + i) = i;}for (i = 0; i < 10; i++) {printf("%d ", *(p + i));}//增加空间// p = (int *)realloc(p, 80); //如果开辟失败的话,p变成了空指针,不能这么写int *ptr = (int *) realloc(p, 80);if (ptr != NULL) {p = ptr;ptr = NULL;}//当realloc开辟失败的时候,返回的也是空指针//使用for (i = 10; i < 20; i++) {*(p + i) = i;}for (i = 10; i < 20; i++) {printf("%d ", *(p + i));}//释放free(p);p = NULL;return 0;
}//输出结果:0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

2.常见的动态内存错误

2.1 对NULL指针的解引用操作

#include <stdio.h>
#include <stdlib.h>
int main() {int* p = (int*)malloc(20);*p = 5;  //错误,空指针解引用//为了不对空指针解引用  需要进行判断if (p == NULL) {perror("malloc");return 1;}else {*p = 5;}free(p);p = NULL;return 0;
}

2.2 对动态开辟空间的越界访问

#include <stdio.h>
#include <stdlib.h>
int main() {int *p = (int *) malloc(20);if (p == NULL)return 1;int i = 0;for (i = 0; i < 20; i++)//越界访问    20个字节 只能访问5个整型{*(p + i) = i;}free(p);p = NULL;return 0;
}

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

#include <stdio.h>
#include <stdlib.h>
int main() {int a = 10;int* p = &a;free(p);// ok?return 0;
}

在这里插入图片描述

编译器会直接报错

2.4 使用free释放一块动态开辟内存的一部分

#include <stdio.h>
#include <stdlib.h>
int main() {int *p = (int *) malloc(40);if (p = NULL)return 1;int i = 0;for (i = 0; i < 5; i++) {*p = i;p++;}//释放//在释放的时候,p指向的不再是动态内存空间的起始位置free(p);// p不再指向动态内存的起始位置p++;return 0;
}

2.5 对同一块动态内存多次释放

#include <stdio.h>
#include <stdlib.h>
int main() {int* p = (int*)malloc(40);if (p == NULL)return 1;int i = 0;for (i = 0; i < 5; i++) {*(p + i) = i;}//重复freefree(p);p = NULL;//如果将p赋值为NULL  就可以在free,否则编译器会直接报错free(p);return 0;
}

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

#include <stdio.h>
#include <stdlib.h>
int *get_memory() {int *p = (int *) malloc(40);return p;
}int main() {int *ptr = get_memory();//使用//释放  如果不释放 就会导致内存泄漏free(ptr);return 0;
}

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

在这里插入图片描述

C/C++程序内存分配的几个区域:

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

普通的局部变量是在栈区分配空间的,栈区的特点是在上面创建的变量出了作用域就销毁。 但是被static修饰的变量存放在数据段(静态区),数据段的特点是在上面创建的变量,直到程序结束才销毁,所以生命周期变长。

4.经典笔试题

4.1 题目1

#include <stdio.h>
#include <stdlib.h>
void GetMemory(char *p) {p = (char *) malloc(100);
}void Test(void) {char *str = NULL;GetMemory(str);strcpy(str, "hello world");printf(str);
}int main() {Test();return 0;
}

请问运行Test 函数会有什么样的结果?

运行Test函数会导致未定义行为。

GetMemory函数中,传入的char *p是一个局部变量,当在函数内部对其进行修改,并不会影响到原始调用函数中的指针。这是因为函数的参数是通过值传递的,即函数得到的是实参的副本,对参数的修改不会影响原始的实参。

Test函数中,将一个NULL指针str传递给GetMemory函数,然后在GetMemory函数中分配了内存并将新的地址赋给p。但这对str并没有影响,str仍然是一个NULL指针,指向未分配的内存。

接着,在Test函数中使用strcpy将字符串拷贝到str指向的内存,但是str指向的内存并没有被分配,这将导致未定义行为。

为了正确地分配内存并使用指针,需要修改GetMemory函数,使其返回分配的内存地址,并在Test函数中接收返回的指针。另外,别忘了在使用完内存后,需要使用free函数来释放动态分配的内存。

改写1:

#include <stdio.h>
#include <stdlib.h>
void GetMemory(char **p) {*p = (char *) malloc(100);
}void Test(void) {char *str = NULL;GetMemory(&str);   //传指针的地址strcpy(str, "hello world");printf(str);//释放free(str);str = NULL;
}int main() {Test();return 0;
}

改写2:

#include <stdio.h>
#include <stdlib.h>
char *GetMemory() {char *p = (char *) malloc(100);return p;
}void Test(void) {char *str = NULL;str = GetMemory();   //接受返回的pstrcpy(str, "hello world");printf(str);//释放free(str);str = NULL;
}int main() {Test();return 0;
}

4.2 题目2

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

请问运行Test函数会有什么样的结果?

GetMemory函数中,定义了一个局部数组char p[] = "hello world";,然后将该数组的地址返回给调用者。但是,一旦GetMemory函数执行完毕,其局部变量(p数组)将被销毁,因为它是一个自动存储类别的局部变量。所以,返回的指针指向的是已经无效的内存。

Test函数中,你将GetMemory的返回值赋给指针str,然后使用printf打印str指向的内容。由于GetMemory返回的是一个无效的指针(指向已经被销毁的局部数组),printf可能会打印出垃圾值,或者程序崩溃,或者导致其他不可预测的结果。

这个问题被称为"悬挂指针"问题,因为指针悬挂在指向已经无效的内存位置上。

要解决这个问题,可以考虑使用动态内存分配来分配存储字符串的内存,并在使用完后记得使用free来释放内存。

修改后的代码示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>char *GetMemory(void) {char *p = (char *)malloc(strlen("hello world") + 1);if (p != NULL) {strcpy(p, "hello world");}return p;
}void Test(void) {char *str = NULL;str = GetMemory();if (str != NULL) {printf("%s\n", str);free(str); // 释放内存}
}int main() {Test();return 0;
}

4.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函数会有什么样的结果?

没有释放内存,导致内存泄漏

修改后的代码实例:

void GetMemory(char **p, int num) {*p = (char *)malloc(num);
}void Test(void) {char *str = NULL;GetMemory(&str, 100);if (str != NULL) {strcpy(str, "hello");printf("%s\n", str);free(str); // 释放内存}
}

4.4 题目4

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

请问运行Test 函数会有什么样的结果?

str被提前释放,再次访问str会导致野指针行为

相关文章:

<C语言> 动态内存管理

1.动态内存函数 为什么存在动态内存分配&#xff1f; int main(){int num 10; //向栈空间申请4个字节int arr[10]; //向栈空间申请了40个字节return 0; }上述的开辟空间的方式有两个特点&#xff1a; 空间开辟大小是固定的。数组在声明的时候&#xff0c;必须指定数组的…...

【ASPICE】:学习记录

学习记录 ASPICE中文资料什么是ASPICE过程参考模型 ASPICE全称“Automotive Software Process Improvement and Capability dEtermination”&#xff0c;即“汽车软件过程改进及能力评定”模型框架 ASPICE中文资料 主要资料来源 什么是ASPICE 过程参考模型...

图论--最短路问题

图论–最短路问题 邻接表 /* e[idx]:存储点的编号 w[idx]:存储边的距离&#xff08;权重&#xff09; */ void add(int a, int b, int c) {e[idx] b;ne[idx] h[a];w[idx] ch[a] idx ; }1.拓扑排序 给定一个 n 个点 m 条边的有向图&#xff0c;点的编号是 11 到 n&#xf…...

go 结构体 - 值类型、引用类型 - 结构体转json类型 - 指针类型的种类 - 结构体方法 - 继承 - 多态(interface接口) - 练习

目录 一、结构体 1、python 与 go面向对象的实现&#xff1a; 2、初用GO中的结构体&#xff1a;&#xff08;实例化一个值类型的数据&#xff08;结构体&#xff09;&#xff09; 输出结果不同的三种方式 3、实例化一个引用类型的数据&#xff08;结构体&#xff09; 4、…...

盘点16个.Net开源项目

今天一起盘点下&#xff0c;16个.Net开源项目&#xff0c;有博客、商城、WPF和WinForm控件、企业框架等。&#xff08;点击标题&#xff0c;查看详情&#xff09; 一、一套包含16个开源WPF组件的套件 项目简介 这是基于WPF开发的&#xff0c;为开发人员提供了一组方便使用自…...

记录对 require.js 的理解

目录 一、使用 require.js 主要是为了解决这两个问题二、require.js 的加载三、main.js 一、使用 require.js 主要是为了解决这两个问题 实现 js 文件的异步加载&#xff0c;避免网页失去响应&#xff1b;管理模块之间的依赖性&#xff0c;便于代码的编写和维护。 二、require.…...

minio-分布式文件存储系统

minio-分布式文件存储系统 minio的简介 MinIO基于Apache License v2.0开源协议的对象存储服务&#xff0c;可以做为云存储的解决方案用来保存海量的图片&#xff0c;视频&#xff0c;文档。由于采用Golang实现&#xff0c;服务端可以工作在Windows,Linux, OS X和FreeBSD上。配置…...

Kindling the Darkness: A Practical Low-light Image Enhancer论文阅读笔记

这是ACMMM2019的一篇有监督暗图增强的论文&#xff0c;KinD其网络结构如下图所示&#xff1a; 首先是一个分解网络分解出R和L分量&#xff0c;然后有Restoration-Net和Adjustment-Net分别去对R分量和L分量进一步处理&#xff0c;最终将处理好的R分量和L分量融合回去。这倒是很常…...

AcWing 4575. Bi数和Phi数

文章目录 题意:思路:代码 题意: 就是给你n个数&#xff0c;对于每一个数y你都需要找到一个最小x使得 ϕ ( x ) ≥ y \phi(x) \ge y ϕ(x)≥y&#xff0c;然后再求一个最小平和。 思路: 其实最开始以来的思路就是二分&#xff0c;我先进行线性筛求出每个数的欧拉函数&#xf…...

《Federated Unlearning via Active Forgetting》论文精读

文章目录 1、概述2、方法实验主要贡献框架概述 3、实验结果比较方法实验结果忘却完整性忘却效率模型实用性 4、总结 原文链接&#xff1a; Federated Unlearning via Active Forgetting 1、概述 对机器学习模型隐私的⽇益关注催化了对机器学习的探索&#xff0c;即消除训练数…...

Java课题笔记~Maven基础知识

一、什么是Maven&#xff1f; Maven是专门用于管理和构建Java项目的工具。 它的主要功能有&#xff1a; 提供了一套标准化的项目结构提供了一套标准化的构建流程&#xff08;编译&#xff0c;测试&#xff0c;打包&#xff0c;发布……&#xff09;提供了一套依赖管理机制 …...

xcode中如何显示文件后缀

xcode14.3 用不惯mac电脑真恶心&#xff0c;改个显示文件后缀找半天 1、首先双击打开xcode软件 2、此时&#xff0c;电脑左上角出现xcode字样(左上角如果看不到xcode字样&#xff0c;再次点击xcode软件弹出来就有了)&#xff0c;鼠标右键它&#xff0c;点击setting或者Prefere…...

SpringBoot使用JKS或PKCS12证书实现https

SpringBoot使用JKS或PKCS12证书实现https 生成JKS类型的证书 可以利用jdk自带的keytool工具来生成证书文件&#xff0c; 默认生成的是JKS证书 cmd命令如下: 执行如下命令&#xff0c;并按提示填写证书内容&#xff0c;最后会生成server.keystore文件 keytool -genkey tomcat…...

云原生势不可挡,如何跳离云原生深水区?

云原生是云计算领域一大热词&#xff0c;伴随云原生概念而来的是数字产业迎来井喷、数字变革来临、数字化得以破局以及新一波的技术红利等等。云原生即“云”原生&#xff0c;顾名思义是让“应用”最大程度地利用云的能力&#xff0c;发挥云价值的最佳路径。具体来说&#xff0…...

python的decimal或者叫Decimal,BigDecimal

前言 在python中进行小数计算时&#xff0c;很容易发生精度错误问题&#xff01;&#xff01;&#xff01;&#xff01;一定要注意&#xff01;&#xff01;&#xff01;或者说&#xff0c;只要进行小数的运算都要用decimal。如&#xff1a;银企对账&#xff1b;工程计算等等在…...

Mac环境变量问题

查询环境变量 echo $PATH 查询当前使用的Shell&#xff0c;这里注意SHELL需要大写 echo $SHELL >>>如果输出的是/bin/zsh&#xff0c;说明使用的是zsh。zsh读取的个人配置文件是~/.zshrc (mac10.15.x 后对应的是~/.zprofile) >>>如果输出的是/bin/bash&…...

Shell脚本学习-Web服务监控

参考我的博客文章《Centos安装nginx》&#xff0c;先来安装下nginx。我按照该文档操作了一遍&#xff0c;还是很快就能安装好nginx的。 确认可以安装成功&#xff1a; [rootvm1 sbin]# netstat -atunlp |grep 80 tcp 0 0 0.0.0.0:80 0.0.0.0:* …...

【ChatGPT】基于WSL+Docker的ChatGPT PLUS共享服务部署

最近买了ChatGPT PLUS服务&#xff0c;想通过web服务将它共享给其他人使用&#xff0c;搜了一下目前GitHub上比较热门的服务有 ChatGPT-Next-Webchatgpt-web-share 其中chatgpt-web-share支持API和PLUS账号分享两种方式&#xff0c;且架构为PythonJSDocker&#xff0c;相对比…...

【论文阅读24】Better Few-Shot Text Classification with Pre-trained Language Model

论文相关 论文标题&#xff1a;Label prompt for multi-label text classification&#xff08;基于预训练模型对少样本进行文本分类&#xff09; 发表时间&#xff1a;2021 领域&#xff1a;多标签文本分类 发表期刊&#xff1a;ICANN&#xff08;顶级会议&#xff09; 相关代…...

119、Spring容器启动流程是怎样的(配有Spring启动完整流程图)

Spring容器启动流程是怎样的 在创建Spring容器&#xff0c;也就是启动Spring时&#xff1a;首先会进行扫描&#xff0c;扫描得到所有的BeanDefinition对象&#xff0c;并存在一个Map中然后筛选出非懒加载的单例BeanDefinition进行创建Bean&#xff0c;对于多例Bean不需要在启动…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

Angular微前端架构:Module Federation + ngx-build-plus (Webpack)

以下是一个完整的 Angular 微前端示例&#xff0c;其中使用的是 Module Federation 和 npx-build-plus 实现了主应用&#xff08;Shell&#xff09;与子应用&#xff08;Remote&#xff09;的集成。 &#x1f6e0;️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题

分区配置 (ptab.json) img 属性介绍&#xff1a; img 属性指定分区存放的 image 名称&#xff0c;指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件&#xff0c;则以 proj_name:binary_name 格式指定文件名&#xff0c; proj_name 为工程 名&…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...

【Go语言基础【12】】指针:声明、取地址、解引用

文章目录 零、概述&#xff1a;指针 vs. 引用&#xff08;类比其他语言&#xff09;一、指针基础概念二、指针声明与初始化三、指针操作符1. &&#xff1a;取地址&#xff08;拿到内存地址&#xff09;2. *&#xff1a;解引用&#xff08;拿到值&#xff09; 四、空指针&am…...

虚拟电厂发展三大趋势:市场化、技术主导、车网互联

市场化&#xff1a;从政策驱动到多元盈利 政策全面赋能 2025年4月&#xff0c;国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》&#xff0c;首次明确虚拟电厂为“独立市场主体”&#xff0c;提出硬性目标&#xff1a;2027年全国调节能力≥2000万千瓦&#xff0…...