深入探讨C存储类和存储期——Storage Duration

news2024/9/23 15:33:52

   🔗 《C语言趣味教程》👈 猛戳订阅!!!

—— 热门专栏《维生素C语言》的重制版 ——

  • 💭 写在前面:这是一套 C 语言趣味教学专栏,目前正在火热连载中,欢迎猛戳订阅!本专栏保证篇篇精品,继续保持本人一贯的幽默式写作风格,当然,在有趣的同时也同样会保证文章的质量,旨在能够产出 "有趣的干货" !本系列教程不管是零基础还是有基础的读者都可以阅读,可以先看看目录! 标题前带星号 (*) 的部分不建议初学者阅读,因为内容难免会超出当前章节的知识点,面向的是对 C 语言有一定基础或已经学过一遍的读者,初学者可自行选择跳过带星号的标题内容,等到后期再回过头来学习。值得一提的是,本专栏 强烈建议使用网页端阅读! 享受极度舒适的排版!你也可以展开目录,看看有没有你感兴趣的部分!希望需要学 C 语言的朋友可以耐下心来读一读。最后,可以订阅一下专栏防止找不到。

" 有趣的写作风格,还有特制的表情包,而且还干货满满!太下饭了!"

—— 沃兹基硕德

【C语言趣味教程】(7) 存储类:auto 关键字 | register 关键字 | 存储期 | 自动存储期 | 动态存储期 | 线程存储期 | 动态分配存储期 | 静态变量

📜 本章目录:

Ⅰ. 存储类(Storage Class)

0x00 引入:什么是存储类?

0x01 auto 关键字

0x01 注意:auto 只能修饰局部变量!

* 0x02 拓展阅读:C++ 中改版后的 auto

0x03 static 关键字初探

* 0x04 register 关键字

0x05 extern 关键字

Ⅱ. 存储期(Storage Duration)

0x00 引入:存储器的概念

0x01 自动存储期

0x02 静态存储期

* 0x03 动态分配存储期

* 0x04 线程存储期

Ⅲ. 静态变量(Static)

0x00 static 关键字

0x01 局部静态变量

0x02 全局静态变量

0x03 静态变量的初始值默认为0


Ⅰ. 存储类(Storage Class)

0x00 引入:什么是存储类?

❓ 你没有听说过存储类的概念?

存储类 (Storage Class) 在 C 语言标准中用来 规定变量与函数的可访问性与生命周期。

"可访问性" 的概念就是我们上一章说的作用域范围,我们先关注以下 4 种存储类别:

auto
static
register
extern

简单来说,存储类别定义了变量和函数的存储位置、生命周期和作用域。 

为什么要引出存储类的概念?


大多数教程似乎并不涉及 "存储类" 的说法概念,讲解 auto, static 等关键字的时候都是直接介绍,而不引出存储类 (即 Storage Class) 的概念。

正因如此,我们想把存储类的概念单独抽出来作为一个章节去讲解,介绍存储类的概念,介绍一些常见的存储类别 (auto, staitc, register...) 。而不是单独的介绍这些关键字,孤立疏远它们的联系。

当然了,如果你是 C 语言初学者,一开始就接触存储类的概念大有裨益,利于体系化学习。如果你掌握 C语言基础,但是似乎之前没有听说过这个概念,也不用担心。像常见的 auto, extern, register, static 等关键字就属于 "存储类",通过本章的学习,可以体系化地了解这些东西,把它们归类起来。

0x01 auto 关键字

auto 是 "自动" 的意思,代表 变量在函数开始时自动创建,在函数结束时被自动销毁。

即使用 auto 修饰的变量,是具有自动存储器的局部变量。

auto int a = 0;   // 表示a是一个自动存储类型,会在函数结束后自动销毁。

  遗憾的是,大家都懒得去用它,这是为什么呢?

因为定义在函数中的所有变量都是自带 auto 的,即局部变量都是自带 auto 的。

💭 举个例子:

auto int a = 10; (A)
int a = 10;      (B)

(A) 和 (B) 是一样的效果,我们不需要手动去加,因为 auto 是所有局部变量的默认存储类。

当使用 auto 修饰后,表示 a 是一个自动存储类型,它会在函数结束以后自动销毁。

0x01 注意:auto 只能修饰局部变量!

值得注意的是,auto 只能在函数内使用!这就意味着 auto 只能修饰局部变量。

❌ 错误演示:auto 修饰全局变量

#include <stdio.h>    

auto int a = 10;   // 全局变量

int main(void)
{
	auto int b = 20;   // 局部变量

	return 0;
}

🚩 运行结果:error E0149

此时必然会触发报错和警告:warning C4042: “a”: 有坏的存储类

* 0x02 拓展阅读:C++ 中改版后的 auto

温馨提示:以下内容涉及 C++,读者可按自身情况阅读。

 C++ 标准委员会觉得这 auto 也太尴尬了,我们得给它来一波加强。为了缓解 auto 的尴尬,C++ 标准委员会把 auto 原来的功能给废弃了。并赋予了 auto 全新的含义!

📚 游戏更新补丁(bushi):auto 现在不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器。auto 声明的变量必须由编译器在编译时推导而得。

也就是说,它可以自动推导出数据的类型:

int a = 0;
auto c = a;  // C++11给auto关键字赋予了新的意义:自动推导c的类型

你的右边是什么,它就会推导出相应的类型,任何类型都可以实现,包括但不限于:

auto ch = 'A';
auto e = 10.11;
auto pa = &a;

为了方便测试,我们来打印一下对象的类型看看:

#include<iostream>
using namespace std;

int main()
{
    int a = 0;
    auto c = a;  // 自动推导c的类型

    auto ch = 'A';
    auto e = 10.11;
    auto pa = &a;

    // typeid - 打印对象的类型
    cout << typeid(c).name() << endl;   // i
    cout << typeid(ch).name() << endl;  // c
    cout << typeid(e).name() << endl;   // d
    cout << typeid(pa).name() << endl;  // Pi

    return 0;
}

🚩 运行结果如下:

 emmm... 确实

 这时候可能有人会觉得,这一波操作好像也没啥意义啊,

直接写数据类型不香吗?int c = a,我们继续往下看~

💭 举个例子:auto 的使用场景

 

处理又臭又长的数据类型 

💬 遇到这种场景,就能体会到 auto 的香了:

#include <iostream>
#include <map>

int main(void) 
{
    std::map<std::string, std::string> dict = {{"sort", "排序"}, {"insert", "插入"}};
    std::map<std::string, std::string>::iterator it = dict.begin();
    // 这个类型又臭又长,写起来太麻烦了。。。
    
    auto it = dict.begin();   // 可以改成这样,爽!
    // ↑ 根据右边的返回值去自动推导it的类型,写起来就方便多了

    return 0;
}

 像遇到这种又臭又长的类型,而且还要经常使用。

这时候使用 auto 帮你自动推到类型,就很爽了!

📌 注意事项:使用 auto 是必须要给值的!

int i = 0;
auto j;  ❌

auto j = i;  必须给值!!

这就意味着,auto 是不能做参数的!

auto 不能作为函数的参数

void TestAuto(auto a); ❌

此处代码编译失败,auto 不能作为形参类型,因为编译器无法对 a 的类型进行推导!

auto 不能直接用来声明数组

 auto b[3] = {4,5,6};   ❌

📌 为了避免与 C++98 中的 auto 发生混淆,C++11 只保留了 auto 作为类型指示符的用法。

 auto 在实际中最常见的优势用法就是 C++11 提供的新式 for 循环,

还有 lambda 表达式等进行配合使用。我们可以继续往下看~

auto 与指针结合起来使用:

📚 改版后的 auto 非常聪明,它在推导的时候其实是非常灵活的:

int main(void)
{
    int x = 10;
    auto a = &x;  // int*
    auto* b = &x; // int*
    auto& c = x;  // int

    return 0;
}

在同一行定义多个变量

当在同一行声明多个变量时,这些变量必须是相同的类型!

否则编译器将会报错,因为编译器实际只对第一个类型进行推导,

然后用推导出来的类型定义其他变量。

auto a = 1, b = 2;
auto c = 3, d = 4.0;  ❌ 该行代码会编译失败,因为c和d的初始化表达式类型不同

0x03 static 关键字初探

static 是全局变量的默认存储类,它指示编译器在程序的生命周期内保持局部变量的存在。

static int a;

而不会像 auto 那样,每次进入和离开作用域时都会进行创建和销毁。

因此,我们可以使用 static 修饰局部变量在 "延长" 局部变量的生命周期。

让它能在函数调用之间保持局部变量的值。

static 也可以作用于全局变量,当 static 修饰全局变量时会让作用于提升至声明它的文件内。

静态变量的初始化:静态变量只被初始化一次,及时函数调用多次该变量的值也不会重置。

* 0x04 register 关键字

寄存器变量通常被存储在内存中,如果运气不错,寄存器变量就可以被存储在 CPU 寄存器中。

 寄存器变量的访问速度比普通变量快的多。

register 关键字就是用来建议编译器把局部变量或函数的形参放入 CPU 的寄存器中的。

放到寄存器可以提高访问速度,如果一个变量比较常用,我们可以考虑加上 register 修饰:

register int count;

值得注意的是,register 对编译器只是一个 "建议",具体情况得看硬件和各种限制是否通过。

准确来说这是对编译器的一个请求,而不是一个命令,请求需要同意,命令无需同意。

这也是为什么在开头我说 "如果运气不错",用了 register 能不能放进去是要看天时地利人和的。

"天时地利人和,缺一不可。"

register 修饰的变量,编译器将尽可能地将其存入 CPU 的寄存器中。

并且,既然要存到寄存器中,那么 变量的字节长度应小于等于寄存器的长度。

局部变量存储在 RAM 中,而 register 可以建议编译器将某变量存到 CPU 寄存器中。

因此,如果一个变量需要频繁访问,可以使用 register 声明一下,提高程序的运行速度。

📌 注意事项:不能对 register 使用取地址 &,因为它没有内存位置。

0x05 extern 关键字

extern 关键字用于定义在其他文件中声明的全局变量或函数。

extern 让全局变量可以被各个对象模块访问。

使用 extern 关键字时,表示变量已经在别处定义,不能再初始化。

Ⅱ. 存储期(Storage Duration)

0x00 引入:存储器的概念

存储期描述了通过这些标识访问对象的生命周期,简单来说就是变量在内存中的 "存活期"。

 C 语言中有 4 种存储期,分别是:

我们下面将逐个介绍它们,对于初学者来说只需做一个简单的了解即可。

0x01 自动存储期

我们一般在函数中创建的变量 (没被 static 定义的变量),都具有 "自动存储期"。

int main(void)
{
    int a;      // 具有自动存储期
}

具有自动存储期的变量,仅存在于当前代码块内(大括号)。

如果不给自动存储期的变量初始化,会自动初始化一个不确定的随机值。

0x02 静态存储期

函数中用 static 关键字定义出来的变量,或在函数外声明定义的对象都具有 "静态存储期"。

int A;   // 具有静态存储期

int main(void)
{
    static int b;    // 具有静态存储期
}

具有静态存储期的变量,从程序开始结束该变量会一直存在,寿 (生命周期) 与天 (程序) 齐。

同时具备自动初始化为 0 的特性,即不给这个变量初始化,变量的初始值默认为 0。

* 0x03 动态分配存储期

C 语言中的动态存储期是指在程序运行时分配和释放内存的过程。

这种存储期允许程序在运行时根据需要来管理内存,以适应不同的数据结构和问题需求。

动态存储期主要通过 malloc 和 free 实现。

(该部分知识点将在动态内存分配章节补充讲解)

* 0x04 线程存储期

线程存储期 (Thread-Local Storage),它的生命周期是创建它的线程的整个执行过程。

比如并发中具有线程存储期的对象,在该线程开始执行时创建,在线程结束时销毁。

这意味着每个线程都拥有其自己的一组变量副本,这些副本在不同的线程中具有不同的值。

举个例子,我们使用线程存储期来存储线程特定的数据。

💬 代码演示:线程 ID 计数器

#include <stdio.h>
#include <pthread.h>

// 定义线程存储期变量
__thread int threadSpecificValue = 0;

// 线程执行的函数
void* threadFunction(void* arg) {
    // 每个线程可以独立地修改 threadSpecificValue 的值
    threadSpecificValue = threadSpecificValue + 1;
    printf("Thread ID: %ld, \
        threadSpecificValue: %d\n", \
        pthread_self(), \
        threadSpecificValue);
    return NULL;
}

int main() {
    pthread_t thread1, thread2;

    // 创建两个线程
    pthread_create(&thread1, NULL, threadFunction, NULL);
    pthread_create(&thread2, NULL, threadFunction, NULL);

    // 等待线程结束
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    return 0;
}

💡 解读:我们定义了线程存储期变量 threadSpecificValue,每个线程都有其自己的副本。可以看到在 threadFunction 中,每个线程独立地对 threadSpecificValue 进行递增操作,并打印出线程的 ID 以及变量的值。因为每个线程都有自己的变量副本,所以每个线程的输出是独立的。(这里用的 __thread 是 GCC 编译器的扩展,用于声明线程存储期变量)

使用存储类说明符声明标识符的对象 _Thread_local(自C11开始)具有线程存储持续时间。它的生命周期是创建它的线程的整个执行过程,并且在线程启动时初始化它的存储值。每个线程都有一个独特的对象,并且在表达式中使用声明的名称是指与评估表达式的线程相关联的对象。尝试从与对象关联的线程以外的线程间接访问具有线程存储持续时间的对象的结果是实现定义的。

这边再多提一下,C++ 11 引入了 thread_local 关键字,用于声明线程局部变量。线程局部变量在每个线程中都有独立的实例,因此在不同线程中访问这些变量时不会相互干扰。

#include <stdio.h>
#include <threads.h>

thread_local int tls_var = 0;

int main() {
    thrd_t thread;
    thrd_create(&thread, another_thread, NULL);

    tls_var = 42;
    printf("Main thread TLS: %d\n", tls_var);

    thrd_join(thread, NULL);
    return 0;
}

int another_thread(void *arg) {
    tls_var = 99;
    printf("Another thread TLS: %d\n", tls_var);
    return 0;
}

 还可以使用 POSIX 线程局部存储函数,在 POSIX 线程库中,可以使用这些函数来创建和操作线程局部存储:

pthread_key_create()
pthread_setspecific()
pthread_getspecific()

线程局部存储允许每个线程维护一份独立的数据副本,这对于需要在线程之间保持独立状态的情况非常有用,例如线程特定的配置信息、日志句柄等操作。

Ⅲ. 静态变量(Static)

0x00 static 关键字

 我们可以用 static 关键字来修饰一个变量为静态变量,修饰方法如下:

static 数据类型 变量名;

如果我们想让一个变量为静态变量,我们就在其数据类型前加一个 static 关键字就行了。

静态变量可以重复赋值,默认初始化的值为 0。

静态变量会被分配在静态存储区,静态变量在数据段中,函数退出后变量值不变。

上一章中我们学习了全局变量和局部变量,静态变量也是分全局和局部的。

 分别是 静态局部变量静态全局变量,下面我们将逐个介绍。

0x01 局部静态变量

 静态局部变量的作用域和局部变量一致,在自己所处的代码块内有效。

但是生命周期被 "提升" 成全局的了,生命周期与全局变量一致,在整个程序运行期间有效。

0x02 全局静态变量

静态全局变量的作用域在定义它的源文件内。

它的生命周期和全局变量一致,在整个程序运行期间有效。

举个例子,如果我们在一个源文件中定义了静态全局变量,那么该变量只能在该源文件内使用。

0x03 静态变量的初始值默认为0

静态变量的初始值都是 0,静态局部变量和静态全局变量的初始值都是 0。

💬 代码演示:静态变量的初始值为 0

#include <stdio.h>

static A;

int main(void)
{
	static a;
	printf("静态局部变量 a = %d\n", a);
	printf("静态局部变量 A = %d\n", a);

	return 0;
}

🚩 运行结果如下:

📌 [ 笔者 ]   王亦优 | 雷向明
📃 [ 更新 ]   2023.8.27
❌ [ 勘误 ]   /* 暂无 */
📜 [ 声明 ]   由于作者水平有限,本文有错误和不准确之处在所难免,
              本人也很想知道这些错误,恳望读者批评指正!

📜 参考文献:

- C++reference[EB/OL]. []. http://www.cplusplus.com/reference/.

- Microsoft. MSDN(Microsoft Developer Network)[EB/OL]. []. .

- 百度百科[EB/OL]. []. https://baike.baidu.com/.

- 维基百科[EB/OL]. []. https://zh.wikipedia.org/wiki/Wikipedia

- R. Neapolitan, Foundations of Algorithms (5th ed.), Jones & Bartlett, 2015.

- B. 比特科技. C/C++[EB/OL]. 2021[2021.8.31]

- 林锐博士. 《高质量C/C++编程指南》[M]. 1.0. 电子工业, 2001.7.24.

- 陈正冲. 《C语言深度解剖》[M]. 第三版. 北京航空航天大学出版社, 2019.

- 侯捷. 《STL源码剖析》[M]. 华中科技大学出版社, 2002.

- T. Cormen《算法导论》(第三版),麻省理工学院出版社,2009年。

- T. Roughgarden, Algorithms Illuminated, Part 1~3, Soundlikeyourself Publishing, 2018.

- J. Kleinberg&E. Tardos, Algorithm Design, Addison Wesley, 2005.

- R. Sedgewick&K. Wayne,《算法》(第四版),Addison-Wesley,2011

- S. Dasgupta,《算法》,McGraw-Hill教育出版社,2006。

- S. Baase&A. Van Gelder, Computer Algorithms: 设计与分析简介》,Addison Wesley,2000。

- E. Horowitz,《C语言中的数据结构基础》,计算机科学出版社,1993

- S. Skiena, The Algorithm Design Manual (2nd ed.), Springer, 2008.

- A. Aho, J. Hopcroft, and J. Ullman, Design and Analysis of Algorithms, Addison-Wesley, 1974.

- M. Weiss, Data Structure and Algorithm Analysis in C (2nd ed.), Pearson, 1997.

- A. Levitin, Introduction to the Design and Analysis of Algorithms, Addison Wesley, 2003. - A. Aho, J. 

- E. Horowitz, S. Sahni and S. Rajasekaran, Computer Algorithms/C++, Computer Science Press, 1997.

- R. Sedgewick, Algorithms in C: 第1-4部分(第三版),Addison-Wesley,1998

- R. Sedgewick,《C语言中的算法》。第5部分(第3版),Addison-Wesley,2002

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

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

相关文章

软件设计师学习笔记7-输入输出技术+总线+可靠性+性能指标

目录 1.输入输出技术 1.1数据传输控制方式 1.2中断处理过程 2.总线 3.可靠性 3.1可靠性指标 3.2串联系统与并联系统 3.3混合模型 4.性能指标 1.输入输出技术 即CPU控制主存与外设交互的过程 1.1数据传输控制方式 (1)程序控制&#xff08;查询&#xff09;方式&…

使用windeployqt和InstallShield打包发布Qt软件的流程

前言 Qt编译之后需要打包发布&#xff0c;并且发布给用户后需要增加一个安装软件&#xff0c;通过安装软件可以实现Qt软件的安装&#xff1b;用于安装软件的软件有很多&#xff0c;这里主要介绍InstallShield使用的流程&#xff1b; 使用windeployqt打包Qt编译后的程序 Qt程序…

【八股】2023秋招八股复习笔记5(计算机网络-CN)

文章目录 八股目录目录1、应用层 & HTTP一些http题HTTPS 加密原理&#xff08;问过&#xff09;HTTP/1.1 新特性HTTP/2.0 与 RPC&#xff08;问过&#xff09;GET 和 POST 比较 2、传输层 & TCPTCP三次握手 & 四次挥手&#xff08;问过&#xff09;为什么每次TCP 连…

Java的异常与错误

对比 Exception 和 Error&#xff0c;另外&#xff0c;运行时异常与一般异常有什么区别&#xff1f; Exception 和 Error 都是继承了 Throwable 类&#xff0c;在 Java 中只有 Throwable 类型的实例才可以被抛出&#xff08;throw&#xff09;或者捕获&#xff08;catch&#x…

浅析Linux SCSI子系统:IO路径

文章目录 概述scsi_cmd&#xff1a;SCSI命令result字段proto_op字段proto_type字段 SCSI命令下发scsi_request_fnscsi_dev_queue_readyscsi_host_queue_ready SCSI命令响应命令请求完成的软中断处理 相关参考 概述 SCSI子系统向上与块层对接&#xff0c;由块层提交的对块设备的…

桌面图标不显示

问题 桌面图标不显示 解决办法 鼠标 右击->选择-查看->显示桌面图标

学习创建第一个 React 项目

目标 本篇的目标是配置好基础的环境并创建出第一个 React 项目。 由于之前没接触过相关的知识&#xff0c;所以还需要了解其依赖的一些概念。 步骤主要参考First React app using create-react-app | VS code | npx | npm - YouTube 0. 简单了解相关概念 JavaScript 一种语…

基于未来搜索算法优化的BP神经网络(预测应用) - 附代码

基于未来搜索算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码 文章目录 基于未来搜索算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码1.数据介绍2.未来搜索优化BP神经网络2.1 BP神经网络参数设置2.2 未来搜索算法应用 4.测试结果&#xff1a;5…

MLCC产生噪音的原因及解决方案

1.内部构造及工作原理 MLCC是Multilayer Ceramic Capacitor多层片式陶瓷电容 决定电容容值大小的主要参数&#xff1a; 真空介电率 相对介电常数K&#xff1a;和MLCC使用材料有关的常数 有效面积S 介电层厚度d 堆叠层数N 所以面积越大堆叠层数越多的MLCC容值越高 2.MLCC产生啸…

shell数据结构

less可以创建一个文件分页 3次a&#xff0c;是不是连续的 重定向输出>会清空文件内容 cp一份新的&#xff0c;或者新建一个 journalctl 查看启动日志 将前面id传给 xargs 通过journalctl -b 查找对应的日志&#xff0c; pi好像的地址 &#xff1f;&#xff1f;&#xff1f…

用Cmake build OpenCV后,在VS中查看OpenCV源码的方法(环境VS2022+openCV4.8.0) Part III

用Cmake build OpenCV后&#xff0c;在VS中查看OpenCV源码的方法(环境VS2022openCV4.8.0) Part III 用Cmake build OpenCV后&#xff0c;在VS中查看OpenCV源码的方法&#xff08;环境VS2022openCV4.8.0&#xff09; Part I_松下J27的博客-CSDN博客 用Cmake build OpenCV后&…

C++设计模式_01_设计模式简介(多态带来的便利;软件设计的目标:复用)

文章目录 本栏简介1. 什么是设计模式2. GOF 设计模式3. 从面向对象谈起4. 深入理解面向对象5. 软件设计固有的复杂性5.1 软件设计复杂性的根本原因5.2 如何解决复杂性 ? 6. 结构化 VS. 面向对象6.1 同一需求的分解写法6.1.1 Shape1.h6.1.2 MainForm1.cpp 6.2 同一需求的抽象的…

时序预测 | MATLAB实现基于TSO-XGBoost金枪鱼算法优化XGBoost的时间序列预测(多指标评价)

时序预测 | MATLAB实现基于TSO-XGBoost金枪鱼算法优化XGBoost的时间序列预测(多指标评价) 目录 时序预测 | MATLAB实现基于TSO-XGBoost金枪鱼算法优化XGBoost的时间序列预测(多指标评价)预测效果基本介绍程序设计参考资料 预测效果 基本介绍 Matlab实现基于TSO-XGBoost金枪鱼算…

Android学习之路(11) ActionBar与ToolBar的使用

自android5.0开始&#xff0c;AppCompatActivity代替ActionBarActivity&#xff0c;而且ToolBar也代替了ActionBar&#xff0c;下面就是ActionBar和ToolBar的使用 ActionBar 1、截图 2、使用 2.1、AppCompatActivity和其对应的Theme AppCompatActivity使用的是v7的ActionBa…

数据分析基础(1)——超实用‼️Excel 常用函数和实用技巧

学习教程&#xff1a;☑️ 懒人Excel - Excel 函数公式、操作技巧、数据分析、图表模板、VBA、数据透视表教程 目录 一、Excel知识体系✨ 二、Excel 常用函数&#x1f4a1; 三、Excel 技巧 &#x1f914; 补充&#xff1a; 1、自学数据分析学习路线 2、数据查询网站 一、…

服务器安全-增加clamav杀毒

1.安装epel源 yum install epel-release 2.安装 clamav yum install clamav clamav-server clamav-data clamav-update clamav-filesystem clamav-scanner-systemd clamav-devel clamav-lib clamav-server-systemd pcre* gcc zlib zlib-devel libssl-devel libssl openssl …

代码随想录第32天|122.买卖股票的最佳时机 II,55. 跳跃游戏 ,45. 跳跃游戏 II

122.买卖股票的最佳时机 II 122. 买卖股票的最佳时机 II 思路比较简单 class Solution {public int maxProfit(int[] prices) {int res0,sum0;for(int i0;i<prices.length-1;i){if(prices[i1]-prices[i]>0){sumprices[i1]-prices[i];}ressum>res?sum:res;}return …

比较重合点的排斥能

( A, B )---3*30*2---( 1, 0 )( 0, 1 ) 让网络的输入只有3个节点&#xff0c;AB训练集各由5张二值化的图片组成&#xff0c;让A中有2个1&#xff0c;B中有1个1&#xff0c;有一个点重合&#xff0c;排列组合&#xff0c;统计迭代次数并排序。 得到数据 构造平均列A 构造平均列…

JDK介绍

JDK,JRE和JVM之间的关系 JVM是运行环境&#xff0c;JRE是含运行环境和相关的类库&#xff0c;跟node环境是一个意思 JDK目录介绍 目录名称说明bin该路径下存放了JDK的各种工具命令。javac和java就放在这个目录。conf该路径下存放了JDK的相关配置文件include该路径下存放了一些…

DevOps系列文章 之 Python基础

流程控制和循环 if语句 它由三部分组成: 关键字本身, 用于判断结果真假的条件表达式, 以及当表达式为真或者非零时执行的代码块 可支持else和elif;条件表达式并不需要用括号括起来 1、标准if 条件语句的语法如下&#xff1a; if expression:expr_true_suite 如果表达式的值…