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

深入理解 C 语言的内存管理

文章目录

    • 引言
    • 内存管理的重要性
    • C语言内存布局
    • C语言内存管理
    • 堆和栈内存的区别和用途
    • 内存分配和释放的过程
    • C语言动态内存分配的概念和原因
    • malloc()、calloc() 和 realloc() 等函数的使用
    • 悬挂指针和野指针
    • 内存泄漏和如何避免
    • 结论

引言

C语言是充满力量且灵活的编程语言,其最大的优点之一就是它允许编程者进行精密的内存管理。
此文章主旨在于提供C语言内存管理的全方位解析。

内存管理的重要性

对于任何一种编程语言,有效的内存管理都是非常重要的。内存管理关系到一个应用程序的性能和效率,良好的内存管理能避免内存泄露和溢出,以及其他类型的内存错误。

C语言内存布局

一个运行中的C程序在内存中的布局主要包括以下几个部分:

  • 代码区:存放函数体的二进制代码。
  • 全局/静态区:存放全局变量和静态变量。
  • 堆:通常用于动态内存分配。
  • 栈:在函数调用时,存储局部变量和函数调用的上下文。

C语言内存管理

在C语言中,我们有几种方式可以获取和释放内存。最典型的就是使用malloc(), calloc(), realloc()free() 四个函数。它们都是定义在 C 标准库 <stdlib.h> 中的。

  • malloc():为指定字节的内存分配空间,并返回一个指向该空间的指针。该内存块初始化的值是不确定的。

  • calloc():为指定数量、指定长度的对象分配空间,并返回一个指向该空间的指针。该内存块初始化为零。

  • realloc():尝试调整之前调用 malloccalloc 所分配的内存块的大小。

  • free():释放之前调用 malloc, callocrealloc 所分配的内存。

注意:在使用动态分配的内存后,你必须记住用 free() 来释放内存。否则,可能会导致内存泄漏。

堆和栈内存的区别和用途

在C语言中,堆和栈是两种用于管理内存的不同方式,它们具有不同的特点和用途。

栈(Stack)

栈是一种后进先出(LIFO)的数据结构,用于存储函数的参数值、局部变量等。
栈内存由系统自动分配和释放,通常用于存储函数调用的上下文信息(例如局部变量、函数参数、返回地址等)。
栈内存的分配和释放速度较快,但大小受限于系统栈的大小。
栈内存的生存期与其所在的函数相关联,当函数执行结束时,栈中的数据也会被自动释放。

堆(Heap)

堆是一种动态分配的内存空间,用于存储程序运行时动态分配的数据。
堆内存的分配和释放由程序员手动管理,通常通过 malloc、calloc、realloc 等函数进行分配,通过 free 函数进行释放。
堆内存的大小一般较大,且没有固定的分配和释放顺序,可以灵活地分配和释放内存。
堆内存的生存期由程序员控制,需要手动释放以避免内存泄漏。

用途

栈内存用于存储函数调用的上下文信息,包括局部变量、函数参数、返回地址等。栈内存的使用是自动的,无需程序员手动管理。

堆内存主要用于存储动态分配的数据,比如动态创建的对象、数组等。程序员可以根据需要手动分配和释放堆内存,以满足程序动态变化的需求。

在实际编程中,栈内存通常用于存储函数调用中的临时数据,而堆内存则用于存储动态分配的数据结构,比如链表、树等。合理地利用栈和堆,可以更有效地管理内存,并避免内存泄漏和溢出等问题。

内存分配和释放的过程

在C语言中,内存分配和释放是非常重要的操作,主要通过标准库中的函数来实现。常见的内存分配函数包括 malloc、calloc、realloc,而内存释放函数则是 free。下面是它们的基本用法和相应的内存管理过程:

内存分配

malloc 函数用于动态分配指定大小的内存空间,并返回一个指向分配内存起始位置的指针。其基本用法如下:

void *malloc(size_t size);

其中 size 参数表示要分配的内存大小,单位为字节。如果分配成功,返回指向分配内存的指针;如果分配失败,返回 NULL。

calloc 函数用于动态分配指定数量、指定大小的内存空间,并将分配的内存初始化为零。其基本用法如下:

void *calloc(size_t num, size_t size);

其中 num 表示要分配的元素个数,size 表示每个元素的大小,单位都是字节。如果分配成功,返回指向分配内存的指针;如果分配失败,返回 NULL。

realloc 函数用于重新调整先前分配的内存空间的大小,可以扩大或缩小。其基本用法如下:

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

其中 ptr 是先前分配的内存指针,size 是要重新分配的内存大小。如果调整成功,返回指向重新分配内存的指针;如果调整失败,返回 NULL。

内存释放

free 函数用于释放先前动态分配的内存空间,将这部分内存标记为可用。其基本用法如下:

void free(void *ptr);

其中 ptr 是待释放的动态分配内存的指针,释放后该指针不再可用。

内存分配和释放的一般过程如下:

  • 使用 malloc、calloc 或 realloc 来分配所需内存空间,并得到指向该空间的指针。
  • 对分配的内存空间进行必要的初始化,写入数据。
  • 当不再需要这部分内存时,使用 free 函数将其释放,以避免内存泄漏。

需要注意的是,动态分配的内存一定要及时释放,否则容易导致内存泄漏,使得程序运行时占用的内存越来越多。同时,在调用 free 函数后,应确保不再使用指向已释放内存的指针,以避免出现悬挂指针的情况。

C语言动态内存分配的概念和原因

在C语言中,动态内存分配是指在程序运行时根据需要分配内存空间,而不是在编译时确定固定的内存分配大小。

动态内存分配的主要原因和概念如下:

概念
在程序运行期间,有时候可能无法确定需要使用多少内存,或者需要存储的数据量会动态地改变。这就需要在运行时根据需要分配和释放内存空间,这就是动态内存分配的概念。动态内存分配允许程序在运行时根据实际需要动态地分配内存空间,以满足程序运行时复杂、不确定的内存需求。

原因

  1. 灵活性:动态内存分配允许程序根据需要动态地增加或减少内存空间,从而提供更大的灵活性。特别是对于某些需要存储可变数量数据的情况,如链表、树等数据结构,动态内存分配非常有用。
  2. 大内存需求:有时程序需要处理的数据量可能非常大,静态分配的方式可能无法满足需求。动态内存分配可以允许程序在需要时动态地获取更多的内存空间。
  3. 存储持续性:动态内存分配允许在函数调用结束后,数据仍然可以保持存在,这是因为动态分配的内存空间在程序员手动释放之前将一直保持存在。
  4. 有效利用内存:动态内存分配可以帮助程序更有效地利用内存资源,节省内存空间并避免浪费。

总之,动态内存分配提供了更大的灵活性和适应性,使得程序能够根据实际需求来动态管理内存,从而更好地满足复杂的内存需求。然而,动态内存分配也需要程序员负责手动管理内存的分配和释放,以避免内存泄漏和悬挂指针等问题。

malloc()、calloc() 和 realloc() 等函数的使用

当涉及动态内存分配时,C语言提供了几个常用的函数来满足不同的需求:malloc()、calloc() 和 realloc()。

  1. malloc()
    malloc() 函数用于在堆内存中动态分配指定大小的内存空间,并返回指向该内存空间起始位置的指针。其函数原型为:
void *malloc(size_t size);

其中 size 参数表示要分配的内存大小,单位为字节。如果分配成功,返回指向分配内存的指针;如果分配失败,返回 NULL。

使用示例:

int *ptr = (int *)malloc(10 * sizeof(int));
if (ptr != NULL) {// 内存分配成功,可以使用ptr指向的内存空间// ...
} else {// 内存分配失败
}
  1. calloc()
    calloc() 函数用于在堆内存中动态分配指定数量、指定大小的内存空间,并将分配的内存初始化为零。其函数原型为:
void *calloc(size_t num, size_t size);

其中 num 表示要分配的元素个数,size 表示每个元素的大小,单位都是字节。如果分配成功,返回指向分配内存的指针;如果分配失败,返回 NULL。

使用示例:

int *ptr = (int *)calloc(10, sizeof(int));
if (ptr != NULL) {// 内存分配成功,可以使用ptr指向的内存空间// ...
} else {// 内存分配失败
}
  1. realloc()
    realloc() 函数用于重新调整先前分配的内存空间的大小,可以扩大或缩小。其函数原型为:
void *realloc(void *ptr, size_t size);

其中 ptr 是先前分配的内存指针,size 是要重新分配的内存大小。如果调整成功,返回指向重新分配内存的指针;如果调整失败,返回 NULL。需要注意的是,realloc() 可能会在内部将原有的数据复制到新的内存块中,因此在调用 realloc() 后,应该谨慎处理原指针的引用。

使用示例:

int *ptr = (int *)malloc(10 * sizeof(int));
// 对ptr指向的内存空间进行操作
// ...
int *new_ptr = (int *)realloc(ptr, 20 * sizeof(int));
if (new_ptr != NULL) {// 重新分配成功,new_ptr指向新的内存空间// 原来的ptr指针不再可用
} else {// 重新分配失败,原来的ptr指针仍然有效
}

在使用这些函数时,需要特别注意以下几点:

  1. 确保检查分配内存是否成功,避免使用未分配或者分配失败的内存。
  2. 在不再需要使用动态分配的内存时,必须使用 free() 函数释放内存,以避免内存泄漏。
  3. 对于 realloc() 函数,需要小心处理原指针和新指针的关系,以避免造成数据丢失或内存泄漏的问题。

总之,这些动态内存分配函数在C语言中非常重要,但也需要谨慎使用,以确保正确地管理内存,避免出现内存泄漏和悬挂指针等问题。

悬挂指针和野指针

在C语言中,悬挂指针(dangling pointer)和野指针(wild pointer)都是指针的一种特殊情况,它们都可能导致程序的行为不可预测,甚至崩溃。

  1. 悬挂指针(dangling pointer)是指一个指针仍然指向一个已经释放或无效的内存地址。这通常发生在以下情况下:

    • 指针指向的内存被显式释放,但指针本身没有被重置为NULL。
    • 指针指向的内存是通过函数返回值返回的,但在函数返回后,指针仍然保持有效。
    • 指针指向的内存是通过被释放的内存块重新分配得到的。

    使用悬挂指针可能导致访问无效内存,造成程序崩溃或产生不可预测的结果。为了避免悬挂指针,应该在释放内存后将指针设置为NULL,并且不要在指针指向的内存被释放后继续使用该指针。

  2. 野指针(wild pointer)是指一个指针没有被初始化,或者指向一个未知的内存地址。野指针通常是由于指针变量声明后没有被正确初始化,或者指针在使用之前被误用而产生的。

    使用野指针可能会导致访问未知的内存地址,造成程序崩溃或产生不可预测的结果。为了避免野指针,应该始终在使用指针之前将其初始化为有效的内存地址,或者将其设置为NULL。

避免悬挂指针和野指针一些常见的方法和调试技巧
下面是一些常见的方法和调试技巧来避免这些问题:

  1. 初始化指针:在声明指针变量时,始终将其初始化为NULL或有效的内存地址。这样可以避免野指针的问题。

  2. 及时释放内存:在不再需要使用指针指向的内存时,要确保及时释放该内存,并将指针设置为NULL。这样可以避免悬挂指针的问题。同时,要注意避免在指针被释放后继续使用该指针。

  3. 避免重复释放:确保每个内存块只被释放一次。重复释放同一块内存可能导致悬挂指针的问题。

  4. 注意函数返回值:如果函数返回一个指针,要确保返回的指针在函数返回后仍然有效。避免返回指向局部变量或已释放内存的指针。

  5. 使用动态内存分配函数:当需要动态分配内存时,使用malloccallocrealloc等函数,并检查返回值是否为NULL。这样可以确保分配内存成功,避免野指针的问题。

  6. 使用静态分析工具:使用静态分析工具可以帮助检测悬挂指针和野指针等内存错误。这些工具可以在编译时或运行时对代码进行检查,并提供警告或错误信息。

  7. 调试技巧:如果遇到悬挂指针或野指针的问题,可以使用以下调试技巧来识别和解决问题:

    • 使用调试器:使用调试器可以逐步执行代码,并观察指针的值和内存状态。这样可以帮助找到指针问题的具体位置。
    • 打印调试信息:在关键位置打印指针的值和相关变量的信息,以帮助跟踪指针的状态和使用情况。
    • 使用内存检测工具:使用内存检测工具(如Valgrind)可以检测内存错误,包括悬挂指针和野指针等问题。

通过遵循良好的编码实践、使用适当的内存管理技术和调试工具,可以有效地避免悬挂指针和野指针的问题,并增加代码的健壮性和可靠性。

总之,悬挂指针和野指针都是指针在使用过程中出现的问题,需要注意避免。在编写C代码时,应该始终注意正确初始化指针,并在释放内存后将指针设置为NULL,以避免悬挂指针的问题。同时,要避免使用未初始化的指针,以防止野指针的问题。

内存泄漏和如何避免

C语言中的内存泄漏是指在程序运行过程中分配的内存没有被正确释放,导致这部分内存无法再次被程序使用,从而造成内存资源的浪费。内存泄漏会逐渐消耗系统的可用内存,最终可能导致程序运行出现问题,如程序崩溃或系统变慢。

内存泄漏的影响包括:

  1. 内存资源浪费:每次发生内存泄漏,系统的可用内存就会减少。如果内存泄漏发生在循环中或频繁执行的代码段中,内存资源的浪费可能会迅速累积,导致系统的可用内存逐渐减少。

  2. 内存耗尽:如果内存泄漏的累积导致系统的可用内存耗尽,系统将无法满足新的内存分配请求。这可能导致程序崩溃、运行异常或系统变得非常缓慢。

  3. 性能下降:内存泄漏会导致系统内存的不断减少,从而增加了系统的内存管理负担。当可用内存不足时,系统可能会频繁进行内存交换或使用虚拟内存技术,这会导致程序的性能下降。

  4. 不可预测的行为:内存泄漏可能导致程序出现不可预测的行为。当程序试图访问已经泄漏的内存时,可能会读取到无效的数据,导致程序产生错误的结果或崩溃。

为了避免内存泄漏,应该遵循以下做法:

  1. 在动态分配内存后,确保在不再需要使用该内存时进行释放。

  2. 避免重复分配内存或多次释放同一块内存。

  3. 注意处理函数返回的指针,确保在不再需要使用时进行释放。

  4. 使用工具和技术来检测内存泄漏,如静态分析工具、内存检测工具和代码审查。

  5. 试着将内存管理集中到一个或者少数几个地方,这样可以方便你进行跟踪和调试。

结论

虽然C语言提供了程序员对内存的详细控制,这无疑增加了编程的复杂性。然而,借助良好的内存管理策略,我们可以创建出高效且稳定的程序。记住,内存是一种宝贵的资源,合适而及时的管理是每一个程序员的责任。

希望这篇文章提供了你需要的关于C语言内存管理的信息,也希望你现在对如何更好地管理并防止内存泄漏有了更深的理解。祝你开发顺利!

参考文献:

C Programming - Memory Management

Understanding and Using C Pointers

C Dynamic Memory Allocation

相关文章:

深入理解 C 语言的内存管理

文章目录 引言内存管理的重要性C语言内存布局C语言内存管理堆和栈内存的区别和用途内存分配和释放的过程C语言动态内存分配的概念和原因malloc()、calloc() 和 realloc() 等函数的使用悬挂指针和野指针内存泄漏和如何避免结论 引言 C语言是充满力量且灵活的编程语言&#xff0…...

利用Caddy实现http反向代理

利用Caddy实现http反向代理 1 Caddy是什么 Caddy是一个开源的&#xff0c;使用Golang编写的&#xff0c;支持HTTP/2的Web服务端。它的一个显著特征就是默认启用HTTPS。 和nginx类似。 2 多个后端服务 假如现在有3个后端http服务&#xff1a;分别在启动在 app1 http://10…...

【Qt之QVariant】使用

介绍 QVariant类类似于最常见的Qt数据类型的联合。由于C禁止联合类型包括具有非默认构造函数或析构函数的类型&#xff0c;大多数有趣的Qt类不能在联合中使用。如果没有QVariant&#xff0c;则QObject::property()和数据库操作等将会受到影响。 QVariant对象同时持有一个单一…...

xv6实验课程--xv6的写时复制fork(2023)

7. xv6实验课程--xv6的写时拷贝(COW)(2021) 7. xv6实验课程--xv6懒惰分页分配&#xff08;lazy)(2020) 本文来源&#xff1a; https://mp.weixin.qq.com/s/XJkhjrlP232ZDsRyXd0oHQ 已完成的实验代码可以从下列网站获取&#xff1a; git clone https://gitee.com/lhwhit196…...

在Windows或Mac上安装并运行LLAMA2

LLAMA2在不同系统上运行的结果 LLAMA2 在windows 上运行的结果 LLAMA2 在Mac上运行的结果 安装Llama2的不同方法 方法一&#xff1a; 编译 llama.cpp 克隆 llama.cpp git clone https://github.com/ggerganov/llama.cpp.git 通过conda 创建或者venv. 下面是通过conda 创建…...

Spring底层原理学习笔记--第七讲--(初始化与销毁)

初始化与销毁 Spring提供了多种初始化和销毁手段它们的执行顺序 A07Application.java package com.lucifer.itheima.a07;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springfram…...

基于斑马算法的无人机航迹规划-附代码

基于斑马算法的无人机航迹规划 文章目录 基于斑马算法的无人机航迹规划1.斑马搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用斑马算法来优化无人机航迹规划。 1.斑马搜索算法 …...

干货 | 接口自动化测试分层设计与实践总结

接口测试三要素&#xff1a; 参数构造 发起请求&#xff0c;获取响应 校验结果 一、原始状态 当我们的用例没有进行分层设计的时候&#xff0c;只能算是一个“苗条式”的脚本。以一个后台创建商品活动的场景为例&#xff0c;大概流程是这样的(默认已经是登录状态下)&#…...

【Linux】服务器与磁盘补充知识,硬raid操作指南

服务器硬件 cpu 主板 内存 硬盘 网卡 电源 raid卡 风扇 远程管理卡 1.硬盘尺寸: 目前生产环境中主流的两种类型硬盘 3.5寸 和2.5寸硬盘 2.5寸硬盘可以通过使用硬盘托架后适用于3.5寸硬盘的服务器 但是3.5寸没法转换成2.5寸 2.如何在服务器上制作raid 华为服务器为例子做…...

【java】实现自定义注解校验——方法二

自定义注解校验的实现步骤&#xff1a; 1.创建注解类&#xff0c;编写校验注解&#xff0c;即类似NotEmpty注解 2.编写自定义校验的逻辑实体类&#xff0c;编写具体的校验逻辑。(这个类可以实现ConstraintValidator这个接口&#xff0c;让注解用来校验) 3.开启使用自定义注解进…...

算法通关村第六关|白银|二叉树的层次遍历【持续更新】

1.二叉树基本的层序遍历 仅仅遍历并输出全部元素。 List<Integer> simpleLevelOrder(TreeNode root) {if (root null) {return new ArrayList<Integer>();}List<Integer> res new ArrayList<Integer>();LinkedList<TreeNode> queue new Lin…...

vue中通过js控制scss变量

<!--* Description:* Author: 李大玄* Date: 2022-07-28 20:34:43* FilePath: /web-framework-demo/src/views/layout.vue* LastEditors: 李大玄* LastEditTime: 2022-11-01 09:25:31 --> <template><div height"100%" class"b"><inp…...

深度学习理论知识入门【EM算法、VAE算法、GAN算法】和【RBM算法、MCMC算法、HMC算法】

目录 深度学习理论知识入门首先&#xff0c;让我们了解第一个流程&#xff1a;现在&#xff0c;让我们看看第二个流程&#xff1a; EM算法GMM&#xff08;高斯混合模型&#xff09; 深度学习理论知识入门 首先&#xff0c;让我们了解第一个流程&#xff1a; EM&#xff08;Exp…...

Java8实战-总结47

Java8实战-总结47 CompletableFuture&#xff1a;组合式异步编程让代码免受阻塞之苦使用定制的执行器 对多个异步任务进行流水线操作 CompletableFuture&#xff1a;组合式异步编程 让代码免受阻塞之苦 使用定制的执行器 就这个主题而言&#xff0c;明智的选择似乎是创建一个…...

功能: 在web应用程序中、读取文件

通过使用文件 API&#xff0c;web 内容可以要求用户选择本地文件&#xff0c;然后读取这些文件的内容。这种选择可以通过使用 HTML <input type"file"> 元素或通过拖放来完成。 1.通过 click() 方法使用隐藏的文件 input 元素 你可以隐藏公认难看的文件 <…...

TDD、BDD、ATDD以及SBE的概念和区别

在软件开发或是软件测试中会遇到以下这些词&#xff1a;TDD 、BDD 、ATDD以及SBE&#xff0c;这些词代表什么意思呢&#xff1f; 它们之间有什么关系吗&#xff1f; TDD 、BDD 、ATDD以及SBE的基本概念 TDD&#xff1a;&#xff08;Test Driven Development&#xff09;是一种…...

Android studio:打开应用程序闪退的问题

目录 问题描述分析原因解决方法 在开发Android应用程序的过程中遇到的问题 问题描述 在开发&#xff08;或者叫测试&#xff0c;这么简单的程序可能很难叫开发&#xff09;好一个android之后&#xff0c;在Android studio中调试开发好的app时&#xff0c;编辑器没有提示错误&a…...

Mysql数据库性能优化--performance_SCHEMA.STATEMENTS语句分析

使用performance_schema解决常见的故障案例 1 检查sql语句 使用performance_schema很容易找到引起性能问题的查询以及原因。 要启动语句检测&#xff0c;需要启动statement类型的插装。 插装类&#xff1a; statement/sql sql语句&#xff0c;如select,或者create table。s…...

[C/C++]数据结构 链表OJ题: 反转链表

描述: 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表 示例: 方法一: 让链表指向反向 如图所示: 代码思路: struct ListNode* reverseList(struct ListNode* head) {struct ListNode* n1NULL;struct ListNode* n2head;struct ListNode*…...

深度学习之基于YoloV5交通信号标志识别系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 基于YoloV5交通信号标志识别系统介绍 基于YoloV5的交通信号标志识别系统是一种深度学习应用&#xff0c;旨在通过使…...

树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频

使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

网络编程(UDP编程)

思维导图 UDP基础编程&#xff08;单播&#xff09; 1.流程图 服务器&#xff1a;短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

(一)单例模式

一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...

OD 算法题 B卷【正整数到Excel编号之间的转换】

文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的&#xff1a;a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...

Ubuntu Cursor升级成v1.0

0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开&#xff0c;快捷键也不好用&#xff0c;当看到 Cursor 升级后&#xff0c;还是蛮高兴的 1. 下载 Cursor 下载地址&#xff1a;https://www.cursor.com/cn/downloads 点击下载 Linux (x64) &#xff0c;…...

数据结构:递归的种类(Types of Recursion)

目录 尾递归&#xff08;Tail Recursion&#xff09; 什么是 Loop&#xff08;循环&#xff09;&#xff1f; 复杂度分析 头递归&#xff08;Head Recursion&#xff09; 树形递归&#xff08;Tree Recursion&#xff09; 线性递归&#xff08;Linear Recursion&#xff09;…...

【无标题】湖北理元理律师事务所:债务优化中的生活保障与法律平衡之道

文/法律实务观察组 在债务重组领域&#xff0c;专业机构的核心价值不仅在于减轻债务数字&#xff0c;更在于帮助债务人在履行义务的同时维持基本生活尊严。湖北理元理律师事务所的服务实践表明&#xff0c;合法债务优化需同步实现三重平衡&#xff1a; 法律刚性&#xff08;债…...