独占指针:unique_ptr 与 函数调用 笔记

news2024/10/3 2:26:13

推荐B站视频:

2.unique_ptr_哔哩哔哩_bilibiliicon-default.png?t=N7T8https://www.bilibili.com/video/BV18B4y187uL?p=2&vd_source=a934d7fc6f47698a29dac90a922ba5a3

3.unique_ptr与函数调用_哔哩哔哩_bilibiliicon-default.png?t=N7T8https://www.bilibili.com/video/BV18B4y187uL?p=3&vd_source=a934d7fc6f47698a29dac90a922ba5a3一、独占指针:unique_ptr 

  • 任何给定的时刻,只能有一个指针管理内存
  • 当指针超出作用域时,内存将自动释放
  • 该类型指针不可Copy,只可以Move

二、三种创建方式

  • 通过已有裸指针创建
  • 通过new来创建
  • 通过std::make_unique创建(推荐)

准备好头文件和源文件:

  • cat.h
#ifndef CAT_H
#define CAT_H
#include <string>
#include <iostream>
class Cat{
public:
    Cat(std::string name);
    Cat() = default;
    ~Cat();
    void catInfo() const {
        std::cout<<"cat info name : "<<m_name<<std::endl;
    }
    std::string get_name() const{
        return m_name;
    }
    void set_cat_name(const std::string &name) {
        this->m_name = name;
    }
private:
    std::string m_name{"Mimi"};
};
#endif
  • cat.cpp
#include "cat.h"
Cat::Cat(std::string name) :m_name(name) {
    std::cout<<"Constructor of Cat : "<<m_name<<std::endl;
}

Cat::~Cat() {
    std::cout<<"Destructor of Cat"<<std::endl;
}

1.通过已有裸指针创建 

(1)在栈上

#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;
int main(int argc,char* argv[]) {
    // stack 在main函数下,会在最后一条语句之后再执行析构函数
    Cat c1("maomao");
    c1.catInfo();
    { // 在这个作用域下,结束后会自动销毁
        Cat c1("Tom");
        c1.catInfo();
    }
    cout<<"over~"<<endl; 
    return 0;
}

执行结果:

PS D:\Work\C++UserLesson\cppenv\build> ."D:/Work/C++UserLesson/cppenv/build/app.exe"
Constructor of Cat : maomao
cat info name : maomao
Constructor of Cat : Tom
cat info name : Tom
Destructor of Cat
over~
Destructor of Cat
PS D:\Work\C++UserLesson\cppenv\build>

 (2)在堆上

#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;
int main(int argc,char* argv[]) {
    // roll pointer 原始指针 非常不安全
    Cat* c_p1 = new Cat("Jerry");
    c_p1->catInfo();
    {   
        Cat* c_p1 = new Cat("JiaFeiMao");
        c_p1->catInfo();
    }
    c_p1->catInfo();

    cout<<"over~"<<endl; 
    return 0;
}

执行结果:

PS D:\Work\C++UserLesson\cppenv\build> ."D:/Work/C++UserLesson/cppenv/build/app.exe"
Constructor of Cat : Jerry
cat info name : Jerry
Constructor of Cat : JiaFeiMao
cat info name : JiaFeiMao
cat info name : Jerry
over~
PS D:\Work\C++UserLesson\cppenv\build>
  • 没有执行析构函数,怎么办呢?只能手动释放
#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;
int main(int argc,char* argv[]) {
    // roll pointer 原始指针 非常不安全
    Cat* c_p1 = new Cat("Jerry");
    c_p1->catInfo();
    {   
        Cat* c_p1 = new Cat("JiaFeiMao");
        c_p1->catInfo();
        
        // 需要手动释放
        delete c_p1;
        c_p1 = nullptr; // 防止野指针
    }
    c_p1->catInfo();

    // 需要手动释放
    delete c_p1;
    c_p1 = nullptr; // 防止野指针

    cout<<"over~"<<endl; 
    return 0;
}

执行结果: 

PS D:\Work\C++UserLesson\cppenv\build> ."D:/Work/C++UserLesson/cppenv/build/app.exe"
Constructor of Cat : Jerry
cat info name : Jerry
Constructor of Cat : JiaFeiMao
cat info name : JiaFeiMao
Destructor of Cat
cat info name : Jerry
Destructor of Cat
over~
PS D:\Work\C++UserLesson\cppenv\build>

接着再来一个例子:

#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;
int main(int argc,char* argv[]) {
    // roll pointer 原始指针 非常不安全
    int* i_p1 = new int(100);
    {   
        i_p1 = new int(200);
    }
    cout<<*i_p1<<endl;// 很糟糕,说明没有自动回收该资源
    cout<<"over~"<<endl; 
    return 0;
}

执行结果:

PS D:\Work\C++UserLesson\cppenv\bin\Debug> ."D:/Work/C++UserLesson/cppenv/bin/Debug/app.exe"
200
over~
PS D:\Work\C++UserLesson\cppenv\bin\Debug>

没有执行析构函数,怎么办呢?只能手动释放

#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;
int main(int argc,char* argv[]) {
    // roll pointer 原始指针 非常不安全
    int* i_p1 = new int(100);
    {   
        i_p1 = new int(200);
        // 需要手动释放
        delete i_p1;    
        i_p1 = nullptr;
    }
    cout<<"over~"<<endl; 
    return 0;
}

但手动释放的时候,还再多释放一次或者再访问会崩溃

#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;
int main(int argc,char* argv[]) {
    // roll pointer 原始指针 非常不安全
    int* i_p1 = new int(100);
    {   
        i_p1 = new int(200);
        // 需要手动释放
        delete i_p1;    
        i_p1 = nullptr;
    }
    cout<<*i_p1<<endl;
    // 需要手动释放
    delete i_p1;    
    i_p1 = nullptr;
    cout<<"over~"<<endl; 
    return 0;
}

总结:roll pointer 原始指针 非常不安全

2.通过new来创建

#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;

int main(int argc,char* argv[]) {
    // unique_point  
    Cat* c_p2 = new Cat("ruite");
    std::unique_ptr<Cat> u_c_p2(c_p2);
    // c_p2还能用吗?
    // 否则如下:无法独占
    c_p2->catInfo();                 //ruite
    u_c_p2->catInfo();               //ruite
    c_p2->set_cat_name("lanmao");
    u_c_p2->catInfo();               //lanmao

    cout<<"over~"<<endl; 
    return 0;
}

执行结果:

PS D:\Work\C++UserLesson\cppenv\bin\Debug> ."D:/Work/C++UserLesson/cppenv/bin/Debug/app.exe"
Constructor of Cat : ruite
cat info name : ruite
cat info name : ruite
cat info name : lanmao
over~
Destructor of Cat
PS D:\Work\C++UserLesson\cppenv\bin\Debug>

解决无法独占的问题:

  • 方法一:
#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;
int main(int argc,char* argv[]) {
    // unique_point  
    Cat* c_p2 = new Cat("ruite");
    std::unique_ptr<Cat> u_c_p2(c_p2);
    c_p2 = nullptr;
    u_c_p2->catInfo();

    cout<<"over~"<<endl; 
    return 0;
}

执行结果: 

PS D:\Work\C++UserLesson\cppenv\bin\Debug> ."D:/Work/C++UserLesson/cppenv/bin/Debug/app.exe"
Constructor of Cat : ruite
cat info name : ruite
over~
Destructor of Cat
PS D:\Work\C++UserLesson\cppenv\bin\Debug>
  • 方法二:
#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;
int main(int argc,char* argv[]) {
    // 第二种 new
    std::unique_ptr<Cat> u_c_p3{new Cat("hongmao")};
    u_c_p3->catInfo();
    u_c_p3->set_cat_name("heimao");
    u_c_p3->catInfo();
    cout<<"over~"<<endl; 
    return 0;
}

执行结果:  

PS D:\Work\C++UserLesson\cppenv\bin\Debug> ."D:/Work/C++UserLesson/cppenv/bin/Debug/app.exe"
Constructor of Cat : hongmao
cat info name : hongmao
cat info name : heimao
over~
Destructor of Cat
PS D:\Work\C++UserLesson\cppenv\bin\Debug>

 3.通过std::make_unique创建(推荐)

#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;
int main(int argc,char* argv[]) {
    // 推荐创建方式 第三种 std::move_unique
    std::unique_ptr<Cat> u_c_p4 = make_unique<Cat>();
    u_c_p4->catInfo();
    u_c_p4->set_cat_name("huangmao");
    u_c_p4->catInfo();
    cout<<"over~"<<endl; 
    return 0;
}

执行结果:  

PS D:\Work\C++UserLesson\cppenv\bin\Debug> ."D:/Work/C++UserLesson/cppenv/bin/Debug/app.exe"
cat info name : Mimi
cat info name : huangmao
over~
Destructor of Cat
PS D:\Work\C++UserLesson\cppenv\bin\Debug>

三、get()与->和解引用

- unique_ptr可以通过get()获取地址
- unique_ptr实现了->与*
    - 可以调用->调用成员函数
    - 可以调用*调用 deferencing
#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;
int main(int argc,char* argv[]) {
    // 推荐创建方式 第三种 std::move_unique
    std::unique_ptr<Cat> u_c_p4 = make_unique<Cat>();
    std::unique_ptr<int> u_i_p4 = make_unique<int>(200);
    u_c_p4->catInfo();
    u_c_p4->set_cat_name("huangmao");
    u_c_p4->catInfo();

    cout<<"============================"<<endl;

    cout<<*u_i_p4<<endl;
    cout<<"int address: "<<u_i_p4.get()<<endl;
    cout<<"Cat address: "<<u_c_p4.get()<<endl;
    cout<<"over~"<<endl; 
    return 0;
}

执行结果:   

PS D:\Work\C++UserLesson\cppenv\bin\Debug> ."D:/Work/C++UserLesson/cppenv/bin/Debug/app.exe"
cat info name : Mimi
cat info name : huangmao
============================
200
int address: 00000257966B71C0
Cat address: 00000257966C3450
over~
Destructor of Cat
PS D:\Work\C++UserLesson\cppenv\bin\Debug>

四、unique_ptr 与函数调用

第三节:unique_ptr与函数调用
    - unique_ptr是不可Copy,只可以Move
    - 在做函数参数或返回值中一定要注意所有权

函数调用与unique_ptr注意事项
    - Passing by value
        - 需要用std::move来转移内存拥有权
        - 如果参数直接传入std::make_unique语句,自动转换为move
    - Passing by reference
        - 如果设置参数为const则不能改变指向
            - 比如说reset()
        - reset()方法为智能指针清空方法
    - Return by value
        - 指向一个local object
        - 可以用作链式函数

1.pass by value

(1)需要用std::move来转移内存拥有权

#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;

void do_with_cat_pass_value(std::unique_ptr<Cat> c) {
    c->catInfo();
} 

int main(int argc,char* argv[]) {
    // 1.pass by value
    std::unique_ptr<Cat> c1 = make_unique<Cat>("Tom");
    do_with_cat_pass_value(std::move(c1));
    return 0;
}

运行结果:

PS D:\Work\C++UserLesson\cppenv\bin\Debug> ."D:/Work/C++UserLesson/cppenv/bin/Debug/app.exe"
Constructor of Cat : Tom
cat info name : Tom
Destructor of Cat
PS D:\Work\C++UserLesson\cppenv\bin\Debug>

如果在do_with_cat_pass_value(std::move(c1));多加一句:c1->catInfo(); // 此时c1已经无效

#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;

void do_with_cat_pass_value(std::unique_ptr<Cat> c) {
    c->catInfo();
} 

int main(int argc,char* argv[]) {
    // 1.pass by value
    std::unique_ptr<Cat> c1 = make_unique<Cat>("Tom");
    do_with_cat_pass_value(std::move(c1));
    c1->catInfo(); // 此时c1已经无效
    return 0;
}

运行结果:

PS D:\Work\C++UserLesson\cppenv\bin\Debug> ."D:/Work/C++UserLesson/cppenv/bin/Debug/app.exe"
Constructor of Cat : Tom
cat info name : Tom
Destructor of Cat
cat info name :
PS D:\Work\C++UserLesson\cppenv\bin\Debug>

(2)如果参数直接传入std::make_unique语句,自动转换为move

#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;

void do_with_cat_pass_value(std::unique_ptr<Cat> c) {
    c->catInfo();
} 

int main(int argc,char* argv[]) {
    do_with_cat_pass_value(make_unique<Cat>("JiaFeiMao")); //move
    return 0;
}

运行结果:

PS D:\Work\C++UserLesson\cppenv\bin\Debug> ."D:/Work/C++UserLesson/cppenv/bin/Debug/app.exe"
Constructor of Cat : JiaFeiMao
cat info name : JiaFeiMao
Destructor of Cat
PS D:\Work\C++UserLesson\cppenv\bin\Debug>
  • 总结:如果是pass by value ,传进去以后,这个值就不存在了。它的所有权就转移了,转移到函数里边,函数结束之后就直接消失了 

2.pass by reference

#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;

void do_with_cat_pass_ref(std::unique_ptr<Cat>& c) {
    c->set_cat_name("TomCat");
    c->catInfo();
    c.reset();
}

int main(int argc,char* argv[]) {
    // 2. pass by ref
    // (不加const)
    std::unique_ptr<Cat> c2 = make_unique<Cat>("heimao");
    do_with_cat_pass_ref(c2); 
    // c2->catInfo(); // 此时c2已经无效
    cout<<"address: "<<c2.get()<<endl;
    return 0;
}

 运行过程:

PS D:\Work\C++UserLesson\cppenv\bin\Debug> ."D:/Work/C++UserLesson/cppenv/bin/Debug/app.exe"
Constructor of Cat : heimao
cat info name : TomCat
Destructor of Cat
address: 0000000000000000
PS D:\Work\C++UserLesson\cppenv\bin\Debug>

 注意:如果do_with_cat_pass_ref函数里不添加c.reset();那么c2->catInfo();还是可以的

#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;

void do_with_cat_pass_ref(std::unique_ptr<Cat>& c) {
    c->set_cat_name("TomCat");
    c->catInfo();
    // c.reset();
}

int main(int argc,char* argv[]) {
    // 2. pass by ref
    // (不加const)
    std::unique_ptr<Cat> c2 = make_unique<Cat>("heimao");
    do_with_cat_pass_ref(c2); 
    c2->catInfo(); 
    cout<<"address: "<<c2.get()<<endl;
    return 0;
}

运行结果:

PS D:\Work\C++UserLesson\cppenv\bin\Debug> ."D:/Work/C++UserLesson/cppenv/bin/Debug/app.exe"
Constructor of Cat : heimao
cat info name : TomCat
cat info name : TomCat
address: 0000018F1CF14640
Destructor of Cat
PS D:\Work\C++UserLesson\cppenv\bin\Debug>

也可以加上const,使得do_with_cat_pass_ref函数内不能使用reset

#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;

void do_with_cat_pass_ref(const std::unique_ptr<Cat>& c) {
    c->set_cat_name("TomCat");
    c->catInfo();
    // c.reset();// 如果加上了const,无法使用reset()
}

int main(int argc,char* argv[]) {
    // 2. pass by ref
    // (不加const)
    std::unique_ptr<Cat> c2 = make_unique<Cat>("heimao");
    do_with_cat_pass_ref(c2); 
    c2->catInfo(); 
    cout<<"address: "<<c2.get()<<endl;
    return 0;
}

运行结果:

PS D:\Work\C++UserLesson\cppenv\bin\Debug> ."D:/Work/C++UserLesson/cppenv/bin/Debug/app.exe"
Constructor of Cat : heimao
cat info name : TomCat
cat info name : TomCat
address: 000001D2F5343170
Destructor of Cat
PS D:\Work\C++UserLesson\cppenv\bin\Debug>

 链式调用

#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;

std::unique_ptr<Cat> get_unique_ptr() {
    std::unique_ptr<Cat> p_cat = std::make_unique<Cat>("local cat");
    p_cat->catInfo(); // 输出: local cat
    cout<<p_cat.get()<<endl;
    cout<<&p_cat<<endl;
    p_cat->set_cat_name("TomCat");
    p_cat->catInfo(); // 输出: TomCat
    return p_cat;
}

int main(int argc,char* argv[]) {
    get_unique_ptr()->catInfo();
    cout<<"over~"<<endl;
    return 0;
}

运行结果:

PS D:\Work\C++UserLesson\cppenv\bin\Debug> ."D:/Work/C++UserLesson/cppenv/bin/Debug/app.exe"
Constructor of Cat : local cat
cat info name : local cat
0000023AC98439B0
00000077859AF7C8
cat info name : TomCat
cat info name : TomCat
Destructor of Cat
over~
PS D:\Work\C++UserLesson\cppenv\bin\Debug>

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

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

相关文章

如何阅读xml电子发票

xml电子发票是官方给出的电子存档的文件格式&#xff0c;本质是文本&#xff0c;所以文件很小&#xff0c;大量发票存储&#xff0c;能够更加凸显优势。 但是xml电子发票不方便阅读&#xff0c;因为里面是xml格式&#xff0c;对于财务人员来讲&#xff0c;看“代码”简直太难了…

Android App开发基础(3)——App的设计规范

3 App的设计规范 本节介绍了App工程的源码设计规范&#xff0c;首先App将看得见的界面设计与看不见的代码逻辑区分开&#xff0c;然后利用XML标记描绘应用界面&#xff0c;同时使用Java代码书写程序逻辑&#xff0c;从而形成App前后端分离的设计规约&#xff0c;有利于提高App集…

CSMA/CD 协议——笔记

目录 CSMA/CD 协议 以太网采取的 2 种重要措施 CSMA/CD 协议的要点 CSMA/CD 协议工作流程 碰撞后重传的时机 CSMA/CD 协议的要点 CSMA/CD 协议 最早的以太网&#xff1a;将许多计算机都连接到一根总线上。 总线特点&#xff1a;易于实现广播通信&#xff0c;简单&…

Linux详细笔记大全

第0章 Linux基础入门 什么是计算机 计算机的组成: 控制器,是整个计算机的中枢神经,根据程序要求进行控制,协调计算机各部分工作及内存与外设的访问等。 运算器,功能是对数据进行各种算术运算和逻辑运算。 存储器,功能是存储程序、数据和各种信号、命令等信息。 输入设备…

JavaScript 学习笔记(WEB APIs Day6)

「写在前面」 本文为 b 站黑马程序员 pink 老师 JavaScript 教程的学习笔记。本着自己学习、分享他人的态度&#xff0c;分享学习笔记&#xff0c;希望能对大家有所帮助。推荐先按顺序阅读往期内容&#xff1a; 1. JavaScript 学习笔记&#xff08;Day1&#xff09; 2. JavaSc…

网页首页案例(使用框架:继上一篇博客结尾)

文章目录 新认识的快捷键1.先写好组件并导入App.vue2.往组件中一个一个填内容3.整体静态完成后&#xff0c;发现某些小部分相同&#xff0c;其实可以分装成小组件4.最后通过js动态渲染 新认识的快捷键 1.Ctrl滚轮按住往下拖可以部分选中 .用同样的方法选中下面的111&#xff0…

temu跨境电商怎么样?做temu蓝海项目有哪些优势?

在全球电商市场激烈的竞争中&#xff0c;Temu跨境电商平台以其独特的优势和策略&#xff0c;逐渐崭露头角。对于许多想要拓展海外市场的商家来说&#xff0c;Temu的蓝海项目提供了一个充满机遇的新平台。本文将深入探讨Temu跨境电商的优势以及在蓝海市场中的发展前景。 全球化市…

32人联机自建服务器攻略【幻兽帕鲁多人游玩】

创建幻兽帕鲁服务器1分钟部署教程&#xff0c;阿里云和腾讯云均推出幻兽帕鲁服务器服务器和部署教程&#xff0c;4核16G和4核32G配置可选&#xff0c;阿腾云atengyun.com分享1分钟自建幻兽帕鲁Palworld服务器教程&#xff1a; 幻兽帕鲁服务器创建教程 幻兽帕鲁服务器官方推荐…

JavaScript DOM对象的尺寸和位置详解

在DOM对象操作中&#xff0c;其尺寸和位置也是DOM的核心内容&#xff0c;因为js的“交互式应用”几乎少不了对DOM对象的尺寸和位置进行操作&#xff0c;特别是js动画效果。 一、关于DOM对象的尺寸和位置介绍 二、DOM文档对象的尺寸 1、obj.scrollWidth 和 obj.scrollHeight …

MATLAB环境下使用训练好的卷积神经网络进行大地电磁数据噪声抑制

大地电磁MT是一种比较成熟的地球物理勘探方法&#xff0c;通过计算地面测量的正交电场分量和磁场分量的扰动值研究地下介质的电性结构。MT在油气和工程勘探领域得到了广泛应用。但是由于该方法以天然电磁场为场源&#xff0c;存在地面信号弱和源激发随机的缺点&#xff0c;极易…

Doris 与 Clickhouse 对比(一)

1. 常用引擎 ☕️ Doris 表数据模型 duplicate key &#x1f3ac; 场景&#xff1a;适用于数据无需提前聚合的分析业务。 ⚠️ 注意点&#xff1a;只指定排序列&#xff0c;相同的行并不会合并。 unique key &#x1f3ac; 场景&#xff1a;适用于有更新需求的业务。 ⚠…

Dlearning

Deep Learning Basic 神经网络&#xff1a; #mermaid-svg-rR22a8Udy5SxGOoP {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-rR22a8Udy5SxGOoP .error-icon{fill:#552222;}#mermaid-svg-rR22a8Udy5SxGOoP .error-t…

JPDA框架和JDWP协议

前言 在逆向开发中,一般都需要对目标App进行代码注入。主流的代码注入工具是Frida,这个工具能稳定高效实现java代码hook和native代码hook,不过缺点是需要使用Root设备,而且用js开发,入门门槛较高。最近发现一种非Root环境下对Debug App进行代码注入的方案,原理是利用Jav…

使用js判断list中是否含有某个字符串,存在则删除,

显示上图中使用了两种方式&#xff0c; 左边的是filter将不等于userCode的元素筛选出来组成一个新的list&#xff0c; userCodeList.filter(item> item!userCode)&#xff1b;但是上面这个方法在IE浏览器中不支持&#xff0c; 所以改成了右边的方法&#xff0c;使用splice…

【代码随想录-数组】有序数组的平方

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学习,不断总结,共同进步,活到老学到老导航 檀越剑指大厂系列:全面总结 jav…

MAIA ACTIVE×实在RPA丨低成本、高效率管理达人推广计划,业务提效超6倍

MAIA ACTIVE&#xff08;以下简称“MAIA”&#xff09;是一个专为亚洲女性设计的运动服品牌&#xff0c;于2016年成立于上海。作为女装细分市场的头部企业&#xff0c;MAIA凭借与抖音、小红书等平台达人合作&#xff0c;迅速积累了知名度&#xff0c;并长期保持品牌曝光度和销售…

STM32标准库——(4)OLED显示屏

1.STM32调试方式 串口调试&#xff1a;通过串口通信&#xff0c;将调试信息发送到电脑端&#xff0c;电脑使用串口助手显示调试信息显示屏调试&#xff1a;直接将显示屏连接到单片机&#xff0c;将调试信息打印在显示屏上Keil调试模式&#xff1a;借助Keil软件的调试模式&…

假期刷题打卡--Day15

1、MT1152韩信又生气了 韩信点兵(大于10人)&#xff0c;三个三个一排少1个人&#xff0c;五个五个一排又少1个人&#xff0c;七个七个一排还少1个人。韩信生气了&#xff0c;从别的队伍里调来一个人!这样不管是三个一排五个一排还是七个一排都完美了。问原本最少应该有多少人。…

STM32标准库——(3)GPIO输入

1.按键简介 按键&#xff1a;常见的输入设备&#xff0c;按下导通&#xff0c;松手断开 按键抖动&#xff1a;由于按键内部使用的是机械式弹簧片来进行通断的&#xff0c;所以在按下和松手的瞬间会伴随有一连串的抖动 1.1 硬件电路图 上面两个是外加上拉电阻&#xff08;常用…

一款颜值与实力并存的翻页时钟(免费)

FliTik是一款颜值与实力并存的翻页时钟&#xff0c;安卓端是完全免费的&#xff0c;无任何广告&#xff0c;极简风 &#xff0c;软件默认是12小时制&#xff0c;可以在设置中启用24小时制&#xff0c;并且还支持设置显示秒钟、日期、文案&#xff0c;滴答声和语音报时。 支持横…