C/C++ 回调函数 callback 异步编程

一、C语言的回调函数

1.小试牛刀 

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

int add(int a, int b) {
    return a + b;
}

void test01() {
    // 函数指针可以指向任何类型的函数,只要函数的参数列表和返回值类型匹配即可
    int (*pFunc)(int,int) = add;
    // 函数指针可以像普通函数一样被调用,通过函数指针变量名加上括号的方式
    int result = (*pFunc)(1,2);
    cout << result << endl; // 输出 3
}

// typedef 返回类型(*新的函数名)(参数列表)
typedef int (*INT_func)(int,int);
void test02() {
    INT_func pFunc = add;
    int result = pFunc(2,3);
    cout << result << endl; // 输出 5
}

// 回调函数,它允许一个函数作为参数传递给另一个函数
// 这种特性使得我们可以将一些特定的任务委托给其他函数来完成

// 定义一个函数指针类型
typedef void(*Callback)(int);
// 定义一个函数,该函数接受一个回调函数作为参数
void doSomething(Callback callback) {
    cout<<"Doing something..."<<endl;
    // 调用回调函数
    int data = 1024;
    callback(data);
}

// 定义一个回调函数
void printMyData(int data) {
    cout<<"My data is: "<<data<<endl;
}

int main() {
    test01();
    test02();
    // 将回调函数传递给doSomething函数
    /*
        doSomething函数接受一个Callback类型的参数,这是
        一个指向函数的指针.doSomethings函数调用这个回调函数,
        并且将一个整型变量作为参数传递给它
        printMyData在此是一个简单的回调函数,它接受一个整型变量作为
        参数并且把它打印出来
    */
    doSomething(printMyData);
    return 0;
}
  • 打印结果:
PS D:\Work\c++> ./bin/app     
3
5
Doing something...
My data is: 1024
PS D:\Work\c++>

2.动态函数指针 

在学习这个知识点的时候,我遇到的坑,非常感谢这位大佬给我指点迷津:

动态函数指针free报错_编程语言-CSDN问答icon-default.png?t=N7T8https://ask.csdn.net/questions/8061857?spm=1001.2014.3001.5505

  • micthis大佬写的代码
#include <iostream>
using namespace std;
#include <memory>
#include <stdlib.h>
int add(int a, int b) {
    return a + b;
}
/*
    动态函数指针是指在运行时根据需要动态分配和修改的函数指针
    它可以在程序运行时根据需要指向不同的函数,从而实现更加灵活
    和动态的函数调用
    在c++中,可以使用动态内存分配函数(如malloc或new)来创建
    动态函数指针
*/
int test01() {
    // 创建一个指向函数的指针
    int(**pFunc)(int, int);
    // 使用malloc动态分配内存
    int size = sizeof(int(*)(int, int));
    pFunc = (int(**)(int, int))malloc(size);
    // 将函数指针指向 add函数
    *pFunc = add;
    // 调用函数
    int result = (*pFunc)(2, 3);
    cout << result << endl; // 输出 5
    // 释放内存
    free(pFunc);
    return 0;
}
int main() {
    test01();
    return 0;
}

打印结果: 

PS D:\Work\c++> ./bin/app
5
PS D:\Work\c++>

3.异步编程

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

// A的实现,一般会隐藏
typedef void (*CallbackPtr)(int);// 函数指针定义

typedef struct dataCB{
    int data;
    CallbackPtr callback;
}dataCB;


// 创建实例
dataCB dataCBInstance = {0, NULL};

void* callback_thread(void* arg) { // 此处用的是一个线程
    // 循环改变p->a的值为 0 1 2 3 4 5 6 7 8 9,每个3s改变一次
    dataCB* p = (dataCB*)arg;
    while (1) {
        sleep(3);// 延时3s执行callback函数
        p->callback(p->data);// 函数指针执行函数,这个函数来自于应用层B
        p->data = (p->data + 1) % 10;
    }
}

void startup_app_A() {
    // 创建线程
    pthread_t tid;
    pthread_create(&tid, NULL, callback_thread, (void*)&dataCBInstance);   
}

// 给B的接口,接收注册函数
extern void SetCallBackFun(CallbackPtr cb) {
    printf("SetCallBackFun print! \n");
    dataCBInstance.callback = cb;
}

// //-----------------------应用者B-------------------------------
void recieve(int data)       // 应用者增加的函数,此函数会在A中被执行
{
    //do something
    printf("B得到A的数据 = %d\n",data);
}


int main(void) {
    // 启动A
    startup_app_A();
    SetCallBackFun(recieve);
    // 主函数
    while (1) {
        // std::cout << "main function" << std::endl;
        printf("main function\n");
        sleep(2);
    }
    return 0;
}
PS D:\Work\c++> ./bin/app
SetCallBackFun print!
main function
main function
B得到A的数据 = 0
main function
B得到A的数据 = 1
main function
main function
B得到A的数据 = 2
main function
B得到A的数据 = 3
main function
main function
B得到A的数据 = 4
main function
B得到A的数据 = 5
main function
main function
B得到A的数据 = 6
main function
B得到A的数据 = 7
main function
main function
B得到A的数据 = 8
main function
B得到A的数据 = 9
main function
main function
B得到A的数据 = 0
main function
B得到A的数据 = 1
main function
main function
B得到A的数据 = 2
main function
B得到A的数据 = 3
main function
main function
B得到A的数据 = 4
main function
B得到A的数据 = 5
main function
main function
B得到A的数据 = 6
main function
B得到A的数据 = 7
main function
main function
B得到A的数据 = 8
main function
B得到A的数据 = 9
main function
main function
B得到A的数据 = 0
main function

参考文章:C/C++面向对象(OOP)编程-回调函数详解(回调函数、C/C++异步回调、函数指针)-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_47324800/article/details/135315345

二、C++回调函数

1.动态函数指针

#include <iostream>
using namespace std;
#include <memory>
#include <stdlib.h>
int add(int a, int b) {
    return a + b;
}
/*
    动态函数指针是指在运行时根据需要动态分配和修改的函数指针
    它可以在程序运行时根据需要指向不同的函数,从而实现更加灵活
    和动态的函数调用
    在c++中,可以使用动态内存分配函数(如malloc或new)来创建
    动态函数指针
*/
typedef int(*handleFunc)(int,int);
int test01() {
    // 创建一个指向函数的指针
    int(**pFunc)(int, int);
    pFunc = new handleFunc;
    // 将函数指针指向 add函数
    *pFunc = add;
    // 调用函数
    int result = (*pFunc)(2, 3);
    cout << result << endl; // 输出 5
    // 释放内存
    delete pFunc;
    pFunc = nullptr;
    return 0;
}
int main() {
    test01();
    return 0;
}

  2.简单回调

#include <iostream>
#include <functional>

// 定义一个回调函数类型
typedef std::function<void(int)> Callback;

// 定义一个接受回调函数的函数
void process(int value,Callback callback) {
    std::cout<<"传入处理值: "<<value<<std::endl;
    callback(value); // 调用回调函数
}

// 定义一个回调函数
int add(int value) {
    value += 10;
    std::cout<<"传出结果值: "<<value<<std::endl;
    return value;
}

int main() {
    int value = 42;
    process(value,add); // 传递回调函数给process函数
    return 0;
}

执行结果:

PS D:\Work\c++> ./bin/app
传入处理值: 42
传出结果值: 52
PS D:\Work\c++> 

 3.使用包装器function 

参考文章:C++之可调用对象、bind绑定器和function包装器_完整实现bind和function代码c++-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_65743593/article/details/128963676

 (1) 可调用对象

// 可调用对象
/*
    在C++中,可以像函数一样的调用的有:普通函数,
    类的静态成员函数、仿函数、lambda函数,类的
    非静态成员函数、可被转换为函数的类的对象,
    统称可调用对象或函数对象
    可调用对象有类型,可以用指针存储它们的地址,可以
    被引用(类的成员函数除外)
*/

#include <iostream>
using namespace std;
class Object {
public:
    // 仿函数
    void operator()(int age, string name) {
        cout << "年龄:" << age << ",姓名:" << name << endl;
    }
    // 类的非静态成员函数
    void show(int age, string name) {
        cout << "年龄:" << age << ",姓名:" << name << endl;
    }
};

// 仿函数
void test01() {
    Object obj;
    obj(20, "呵呵哒");
    Object& objRef = obj; // 引用函数
    objRef(18, "小比尔");
}

// lambda函数
void test02() {
    auto func = [](int age, string name) {
        cout << "年龄:" << age << ",姓名:" << name << endl;
    };
    func(20, "heheda");
    auto& funcRef = func;// 引用lambda对象
    funcRef(23, "小比尔");
}

// 类的非静态成员函数有地址,但是只能通过类的对象才能调用它,
// C++对它做了特别处理,类的非静态成员函数只有指针类型,
// 没有引用类型,不能引用
void test03() {
    Object obj;
    obj.show(30, "智慧老人");
    void(Object:: *pobj)(int, string) = &Object::show; // 定义类的成员函数的指针
    (obj.*pobj)(20, "呵呵哒");

    using PFun = void(Object::*)(int, string);
    PFun pShow = &Object::show;
    (obj.*pShow)(78, "圣诞老人");
}

int main() {
    test03();
    return 0;
}

(2)C++之可调用对象,bind绑定器和function包装器

// 包装器function
// 包含头文件:#include <functional>
// std::function<返回值类型(参数类型列表)> diy_name = 可调用对象;

#include <iostream>
#include <functional>
#include <string>
using namespace std;
enum OP {
    ADD,
    MUL,
    SUB
};

int add(int a, int b) {
    return a + b;
}

using handleFunc = function<int(int, int)>;
class Object {
public:
    int add(int a, int b) {
        return a + b;
    }
    static int sub(int a, int b) {
        return a - b;
    }
    static int mul(int a, int b) {
        return a * b;
    }
    // 仿函数
    int operator()(int a, int b, handleFunc cb, OP op) {
        switch (op) {
        case ADD:
            cout << "("<< a << "+" << b << ") = ";
            break;
        case MUL:
            cout << "(" << a << "*" << b << ") = ";
            break;
        case SUB:
            cout << "(" << a << "-" << b << ") = ";
            break;
        }
        cout << cb(a, b) << endl;
        return cb(a, b);
    }
};

void test01() {
    Object obj;
    function<int(int, int)> func = add;
    cout << func(1, 2) << endl;
}

void test02() {
    Object obj;
    handleFunc addCB = std::bind(&Object::add, &obj, std::placeholders::_1, std::placeholders::_2);
    cout << "addCB(1, 2): " << addCB(1, 2) << endl;

    handleFunc subCB = Object::sub;
    cout << "subCB(9, 3): " << subCB(9, 3) << endl;
    subCB = obj.mul;
    cout << "subCB(10, 6): " << subCB(10, 6) << endl;

    handleFunc mulCB = Object::mul;
    cout << "mulCB(3, 3): " << subCB(3, 3) << endl;
    subCB = obj.mul;
    cout << "mulCB(2, 6): " << subCB(2, 6) << endl;

    function<int(int, int, handleFunc, OP)> operCB = obj;
    operCB(2, 3, add, ADD);
    operCB(4, 1, obj.sub, SUB);
    operCB(2, 9, obj.mul, MUL);
}

int main() {
    //test01();
    test02();
    return 0;
}

#include <iostream>
#include <functional>
using namespace std;
using handleFunc = function<void()>;
class Object {
public:
    // 构造函数参数是一个包装器对象
    Object(const handleFunc& f) :m_callback(f) {}
    void notify() {
        m_callback();// 调用通过构造函数得到的函数指针
    }
private:
    handleFunc m_callback;
};

class Subject{
public:
    void operator()() { cout << "heheda" << endl; }
};

int main() {
    Subject s;
    Object obj(s);
    obj.notify();
    return 0;
}

#include <iostream>
#include <functional>
using namespace std;
class Person {
public:
    // 仿函数
    void operator()(int age, string name) {
        cout << "age: " << age << ",name: " << name << endl;
    }

    void show(int age, string name) {
        cout << "age: " << age << ",name: " << name << endl;
    }
};

void test01() {
    Person person;
    // 仿函数
    function<void(int, string)> opFunc = bind(Person(), placeholders::_1, placeholders::_2);
    opFunc(20,"heheda");

    // 类成员函数需要绑定该类的this指针 
    Person p1;
    function<void(Person&, int, string)> showFunc = 
        bind(&Person::show,placeholders::_1, placeholders::_2, placeholders::_3);
    showFunc(p1, 17, "Tom");

    // 为了统一,将对象提前绑定
    function<void(int, string)> showFunc2 =
        bind(&Person::show, p1, placeholders::_1, placeholders::_2);
    showFunc2(8, "Jerry");
}

int main() {
    test01();
}

#include <iostream>
#include <functional>
#include <thread>
#include <unistd.h>
using namespace std;

// A的实现,一般会隐藏
using CallbackPtr = std::function<void(int)>;

typedef struct dataCB{
    int data;
    CallbackPtr callback;
}dataCB;


// 创建实例
dataCB dataCBInstance = {0, NULL};

void* callback_thread(void* arg) { // 此处用的是一个线程
    // 循环改变p->a的值为 0 1 2 3 4 5 6 7 8 9,每个3s改变一次
    dataCB* p = (dataCB*)arg;
    while (1) {
        sleep(3);// 延时3s执行callback函数
        p->callback(p->data);// 函数指针执行函数,这个函数来自于应用层B
        p->data = (p->data + 1) % 10;
    }
}

void startup_app_A() {
    // 创建线程
    std::thread(callback_thread, (void*)&dataCBInstance).detach(); // .detach()分离线程
}

// 给B的接口,接收注册函数
extern void SetCallBackFun(CallbackPtr cb) {
    printf("SetCallBackFun print! \n");
    dataCBInstance.callback = cb;
}

// //-----------------------应用者B-------------------------------
void recieve(int data)       // 应用者增加的函数,此函数会在A中被执行
{
    //do something
    printf("B得到A的数据 = %d\n",data);
}


int main(void) {
    // 启动A
    startup_app_A();
    SetCallBackFun(recieve);
    // 主函数
    while (1) {
        printf("main function\n");
        sleep(2);
    }
    return 0;
}

(3)异步编程

#include <iostream>
#include <functional>
#include <thread>
#include <unistd.h>
using namespace std;

// A的实现,一般会隐藏
using CallbackPtr = std::function<void(int)>;

typedef struct dataCB{
    int data;
    CallbackPtr callback;
}dataCB;


// 创建实例
dataCB dataCBInstance = {0, NULL};

void* callback_thread(void* arg) { // 此处用的是一个线程
    // 循环改变p->a的值为 0 1 2 3 4 5 6 7 8 9,每个3s改变一次
    dataCB* p = (dataCB*)arg;
    while (1) {
        sleep(3);// 延时3s执行callback函数
        p->callback(p->data);// 函数指针执行函数,这个函数来自于应用层B
        p->data = (p->data + 1) % 10;
    }
}

void startup_app_A() {
    // 创建线程
    std::thread(callback_thread, (void*)&dataCBInstance).detach(); // .detach()分离线程
}

// 给B的接口,接收注册函数
extern void SetCallBackFun(CallbackPtr cb) {
    printf("SetCallBackFun print! \n");
    dataCBInstance.callback = cb;
}

// //-----------------------应用者B-------------------------------
void recieve(int data)       // 应用者增加的函数,此函数会在A中被执行
{
    //do something
    printf("B得到A的数据 = %d\n",data);
}


int main(void) {
    // 启动A
    startup_app_A();
    SetCallBackFun(recieve);
    // 主函数
    while (1) {
        printf("main function\n");
        sleep(2);
    }
    return 0;
}
PS D:\Work\c++> ./bin/app
SetCallBackFun print! 
main function
main function
B得到A的数据 = 0
main function
main function
B得到A的数据 = 1
main function
B得到A的数据 = 2
main function
main function
B得到A的数据 = 3
main function
B得到A的数据 = 4
main function
main function
B得到A的数据 = 5
main function
B得到A的数据 = 6
main function
B得到A的数据 = 7
main function
main function
B得到A的数据 = 8
main function
B得到A的数据 = 9
main function
PS D:\Work\c++> cmake --build build
[100%] Built target app
PS D:\Work\c++> ./bin/app
SetCallBackFun print! 
main function
main function
B得到A的数据 = 0
main function
B得到A的数据 = 1
main function
main function
B得到A的数据 = 2
main function
B得到A的数据 = 3
main function
main function
B得到A的数据 = 4
main function
main function
B得到A的数据 = 5
main function
B得到A的数据 = 6
main function
main function
B得到A的数据 = 7
main function
B得到A的数据 = 8
main function
main function
B得到A的数据 = 9
main function
B得到A的数据 = 0
main function
main function
B得到A的数据 = 1
main function
B得到A的数据 = 2
main function
B得到A的数据 = 3
main function
main function
B得到A的数据 = 4
main function
B得到A的数据 = 5
main function
main function
B得到A的数据 = 6
main function
B得到A的数据 = 7
main function
main function
B得到A的数据 = 8
main function
B得到A的数据 = 9
main function
main function
B得到A的数据 = 0
main function
B得到A的数据 = 1
main function
main function
B得到A的数据 = 2
main function
B得到A的数据 = 3
main function
main function
B得到A的数据 = 4
main function
B得到A的数据 = 5
main function
main function
B得到A的数据 = 6
main function
B得到A的数据 = 7
main function
main function
B得到A的数据 = 8
main function
B得到A的数据 = 9
main function
main function
B得到A的数据 = 0
main function
B得到A的数据 = 1
main function
main function
B得到A的数据 = 2
main function
B得到A的数据 = 3
main function
main function
B得到A的数据 = 4
main function
B得到A的数据 = 5
main function
main function
B得到A的数据 = 6
main function
B得到A的数据 = 7
main function
main function
B得到A的数据 = 8
main function
B得到A的数据 = 9
main function
main function
B得到A的数据 = 0
main function
B得到A的数据 = 1
main function
main function
B得到A的数据 = 2
main function
B得到A的数据 = 3
main function
main function
B得到A的数据 = 4
main function
B得到A的数据 = 5
main function
main function
B得到A的数据 = 6
main function
B得到A的数据 = 7
main function
main function
B得到A的数据 = 8
main function
B得到A的数据 = 9
main function
main function
B得到A的数据 = 0
main function
B得到A的数据 = 1
main function
main function
B得到A的数据 = 2
main function
B得到A的数据 = 3
main function
main function
B得到A的数据 = 4
main function
B得到A的数据 = 5
main function
main function
B得到A的数据 = 6
main function
B得到A的数据 = 7
main function
main function
B得到A的数据 = 8
 

参考文章:

c++ 用std::function包装类的非静态成员_c++ function 绑定非静态成员函数-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_62953519/article/details/128438241

未完待续 ~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

单片机串口 奇偶校验 配置问题

一、问题描述 使用GD32单片机串口进行通信测试&#xff0c;单片机的串口配置的是偶校验(Even)、数据位为8、停止位为1、波特率为9600。串口测试软件用的格西烽火&#xff0c;软件的配置如下&#xff1a;   单片机通过串口和串口测试软件进行通信交互&#xff0c;软件收到的数…

绩效主义不可取,为什么还有那么多企业在使用KPI?KPI到底行不行!

“绩效主义毁了索尼” “企业差点被KPI害死” “绩效主义就是企业的脓包” 相信这些言论在过去的若干年里都听过&#xff0c;都是国内外知名企业的大佬说过的话&#xff0c;KPI绩效考核犹如过街老鼠&#xff0c;人人喊打。 虽然近几年&#xff0c;随着小米、知乎等互联网企业…

【HTML 基础】语义化标签

文章目录 1. <header>2. <nav>3. <article>4. <section>5. <footer>为什么使用语义化标签结语 在现代的 Web 开发中&#xff0c;语义化标签成为设计网页结构的重要组成部分。通过使用 <header>, <nav>, <article>, <sectio…

新型生成式 AI 助手 Amazon Q(预览版)上线

今天&#xff0c;我们宣布推出 Amazon Q&#xff0c;这是一种新型的生成式人工智能助手&#xff0c;专门用于满足办公场景需要&#xff0c;可以根据客户业务进行定制。客户可以使用 Amazon Q 进行对话、解决问题、生成内容、获取见解并采取行动&#xff0c;所有这些都基于客户自…

RibbonOpenFeign源码(待完善)

Ribbon流程图 OpenFeign流程图

亚马逊认证考试系列 - 知识点 - 安全组介绍

第一部分&#xff1a;AWS简介 Amazon Web Services&#xff08;AWS&#xff09;是全球领先的云计算服务提供商&#xff0c;为个人、企业和政府机构提供广泛的云服务解决方案。AWS的服务包括计算、存储、数据库、分析、机器学习、人工智能、物联网、安全和企业应用等领域。AW…

2寸证件照多大?怎么裁剪?分享3个工具!

在我们的日常生活中&#xff0c;证件照是必不可少的。不同的场合需要不同尺寸的证件照&#xff0c;其中2寸证件照是最为常见的一种。那么&#xff0c;2寸证件照是多大呢&#xff1f;又有哪些软件可以编辑证件照呢&#xff1f;本文将为你一一解答。 首先&#xff0c;让我们来了解…

大数据企业应用场景分析

目录 一、企业分析 1.1 企业领域维度分析 1.2 技术服务型维度分析 1.3 细分领域维度分析 二、大数据应用场景 2.1 数据分析 2.2 智能推荐 2.3 产品/流程优化 2.4 异常监测 2.5 智能管理 2.6 人工智能和机器学习 三、总结 前言&#xff1a;想讲清楚大数据应用对企业…

第十四篇【传奇开心果系列】Python的OpenCV库技术点案例示例:图像特征提取与描述

传奇开心果短博文系列 系列短博文目录Python的OpenCV库技术点案例示例系列短博文目录前言一、OpenCV图像特征提取与描述介绍二、OpenCV图像特征提取与描述初步示例代码三、扩展思路介绍四、特征点筛选和匹配优化示例代码五、多尺度特征提取示例代码六、非局部特征描述子示例代码…

运行vue3项目出现的问题

Mac 系统运行 vue 启动项目时报错: Permission denied 的解决方式 控制台运行 chmod 777 node_modules/.bin/vue-cli-service 如果 npm run dev 还报这个错 控制台运行 node node_modules/esbuild/install.js

c++之说_10|自定义类型 union 联合体

之前我们说了一些 struct 结构体 现在来了解新的自定义类型 union 联合体 语法 union ptr {void* fptr;CLassFunPtr p;FunPtr p2;ptr& operator(CLassFunPtr ptr){p ptr;return *this;}ptr& operator(FunPtr Fptr){p2 Fptr;return *this;} } FunPtr_; 我们看到了…

代驾应用系统(ssm)

登录首页 管理员界面 代驾司机界面 普通用户界面 前台页面 1、系统说明 &#xff08;1&#xff09; 框架&#xff1a;spring、springmvc、mybatis、mysql、jsp &#xff08;2&#xff09; 系统分为前台系统、后端管理系统 2、欢迎留言联系交流学习讨论&#xff1a;qq 97820625…

seatunnel数据集成(三)多表同步

seatunnel数据集成&#xff08;一&#xff09;简介与安装seatunnel数据集成&#xff08;二&#xff09;数据同步seatunnel数据集成&#xff08;三&#xff09;多表同步seatunnel数据集成&#xff08;四&#xff09;连接器使用 seatunnel除了单表之间的数据同步之外&#xff0c;…

Elasticsearch:基本 CRUD 操作 - Python

在我之前的文章 “Elasticsearch&#xff1a;关于在 Python 中使用 Elasticsearch 你需要知道的一切 - 8.x”&#xff0c;我详细讲述了如何建立 Elasticsearch 的客户端连接。我们也详述了如何对数据的写入及一些基本操作。在今天的文章中&#xff0c;我们针对数据的 CRUD (cre…

Dockerfile文件参数配置和使用

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

算法学习——LeetCode力扣链表篇2

算法学习——LeetCode力扣链表篇2 24. 两两交换链表中的节点 24. 两两交换链表中的节点 - 力扣&#xff08;LeetCode&#xff09; 描述 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&…

零售新业态,让老牧区焕发新生命

敦煌老马一声魔性“浇给”勾起了无数人对羊肉的食欲&#xff0c;而当大家集体涌入餐厅或者在网上下单&#xff0c;都想要尝一尝网红同款的时候&#xff0c;可能并没有想过这样一个问题——为什么在今天&#xff0c;即便是远离牧区的现代大城市&#xff0c;草原羊肉却一样能触手…

12. UE5 RPG使用GameplayEffect修改角色属性(三)

书接 11. UE5 RPG使用GameplayEffect修改角色属性&#xff08;二&#xff09; 前面&#xff0c;介绍了GameplayEffect的Instant和Duration的使用&#xff0c;这一篇主要介绍一下无限制时间类型的infinite的使用方式。 无限时间限制模式下&#xff0c;如果你的周期时间&#xff…

tee漏洞学习-翻译-2:探索 Qualcomm TrustZone的实现

原文&#xff1a;http://bits-please.blogspot.com/2015/08/exploring-qualcomms-trustzone.html 获取 TrustZone image 从两个不同的位置提取image 从手机设备本身从google factory image 已经root的Nexus 5设备&#xff0c;image存储在eMMC芯片上&#xff0c;并且eMMC芯片…

[软件工具]文档页数统计工具软件pdf统计页数word统计页数ppt统计页数图文打印店快速报价工具

文档页数统计工具软件——打印方面好帮手 在信息化时代&#xff0c;文档已成为我们工作、学习、生活中不可或缺的一部分。无论是学术论文、商业报告&#xff0c;还是个人日记&#xff0c;都需要我们对其进行有效的管理。而在这个过程中&#xff0c;文档页数统计工具软件就显得…