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

C++青少年简明教程:C++的指针入门

C++青少年简明教程:C++的指针入门

说到指针,就不可能脱离开内存。了解C++的指针对于初学者来说可能有些复杂,我们可以试着以一种简单、形象且易于理解的方式来解释:

  1. 首先,我们可以将计算机内存想象成一个巨大的有许多格子的储物柜。每个柜子都有一个编号,我们可以用这个编号来记住我们在哪个柜子里存放了东西。
  2. 在编程世界中,这个编号就叫做“地址”。当我们在程序中创建一个变量,例如 int i = 5;,其实就是在告诉计算机:“在你的储物柜里找一个地方,给这个地方打上i的标签,然后把5存入里面。”
  3. 指针就相当于一张包含了柜子编号(地址)的便签。通过它,我们可以快速地找到我们存储的东西。也就是说,在我们创建一个指针时,例如 int *p = &i;,我们其实就是在说:“我们找一个便签,写下i的地址,然后我们在需要时就可以通过查看这个便签来直接找到i。”
  4. 对于初学者来说,能理解“指针是什么”以及“怎么使用”指针,那就已经非常不错了。

指针的应用非常广泛,像是动态内存管理、数组、字符串、函数指针、数据结构等等都离不开指针。它可以让我们更加灵活地操作和管理内存,可以实现很多强大的功能。更深入的内容可以等到以后在学习的过程中逐步了解。

指针是C和C++语言中非常重要的概念,初学的时候会被指针搞蒙。想学好指针,我的经验是不要试图一开始就想理解指针概念,而是要耐心准确的了解指针的各个方面,这是一个过程,随着学习的深入,自然就知道指针是什么了。

指针是C和C++语言中非常重要的概念,初学的时候会被指针搞蒙。想学好指针,我的经验是不要试图一开始就想理解指针概念,而是要耐心准确的了解指针的各个方面,这是一个过程,随着学习的深入,自然就知道指针是什么了。

【C++指针(pointer)权威文档

Microsoft Ignite 指针 (C++) 指针 (C++) | Microsoft Learn

英文 Pointer declaration - cppreference.com  中文 指针声明 - cppreference.com ​】

在C++中,地址和指针是紧密相关的。地址是一个变量或对象在内存中的位置,而指针是一个变量,它存储了一个地址。换句话说,指针是指向一个特定类型的变量或对象的地址。

通过指针,我们可以使用间接的方式访问或修改变量或对象的值。我们可以通过将变量的地址赋给指针来创建一个指针。

在C和C++中,*前后的空格是可选的,而且编译器都会将它们解析为相同的意思。在C++中,声明指针的一般语法格式如下:

type* pointerName;

其中, type 通常是指被指向的数据类型,例如 int, float, char, 或者是结构体或类的名称。

pointerName 是你为指向变量的指针所取的名称,也称为指针变量名,可以是任何有效的标识符。注意指针的名称前缀* 是用于表示它是一个指针的。

以下这些声明是等价的:

int* ptr;

int *ptr;

int * ptr;

int*ptr;

如果在一条语句中定义几个指针变量,每个变量前必须有符号*,例如:

int *ip1, *ip2;  //ip1和ip2都是指向int型对象的指针

double dp, *dp2;  //dp2是指向double型对象的指针,dp是指向double型对象

C++中的指针变量和普通变量有很大的不同。

首先,指针变量存储的是内存地址,而普通变量存储的是实际的数据值。指针变量可以用来访问和修改存储在该内存地址中的数据,而普通变量不能。

其次,指针变量可以动态地分配内存,而普通变量的内存大小是在编译时就确定了的。这使得指针变量非常有用,因为它们允许程序在运行时动态地创建和管理内存。

最后,指针变量可以用来传递内存地址,而不是将整个数据复制到另一个变量中。这可以节省内存,并提高程序的性能。

需要注意的是,使用指针变量需要小心,因为它们可以很容易地导致内存泄漏、悬空指针和其他问题。因此,在使用指针变量时应该非常谨慎,并且尽可能使用更安全的方法来处理内存。

C++中,指针是一种特殊的变量,它存储的是另一个变量的内存地址。这使得你可以通过指针间接地访问或修改那个变量的值。

以下是一个简单的示例:

int num = 10; // 定义一个整数变量

int *ptr = # // 创建一个整数指针,指向num的地址

cout << num << endl; // 输出变量的值

cout << &num << endl; // 输出变量的地址

cout << *ptr << endl; // 输出指针所指向的变量的值

cout << ptr << endl; // 输出指针的值,即存储的地址

在上面的示例中,我们使用&运算符获取变量num的地址,并将其赋给指针ptr。我们可以通过*运算符来访问指针所指向的变量的值,如*ptr。

需要注意的是,指针的类型必须与其指向的变量或对象的类型匹配。例如,指向整数的指针必须是int*类型。这是因为在读取或修改指针指向的内容时,编译器需要知道要读取或修改的变量的类型。

定义指针变量时的 * 运算符和使用指针变量时的 * 运算符的含义和作用却是完全不同的

在定义指针变量时,* 运算符用于表示该变量是一个指针变量,即可存储地址的变量。例如:

int* ptr; // 定义一个 int 类型的指针变量 ptr

在使用指针变量时,* 运算符用于访问指针所指向的地址上存储的数据。这个过程通常被称为解引用(Dereferencing)。例如:

int num = 42;

int* ptr = &num; // 定义一个指向 num 的指针变量 ptr

*ptr = 24; // 在访问指针所指向的地址上的数据,并将其修改为 24

在这个例子中,*ptr 用于访问指针 ptr 所指向的地址上存储的数据 num,并将其修改为 24。

指针变量是一个存储指针的变量,通过指向的地址可以定位到具体的数据。

地址是一个数值,是内存单元的编号,用于确定计算机内存中特定位置的位置。

参加下图:0x231001是指针变量p的地址,0x231007是变量i的地址。指针变量存放的是变量i的地址,也就是指针变量的值。所以p=0x231007,*p=5,&p=0x231001。注意其中地址值是示意性的。

说明:

计算机内存想象成一个巨大的有许多格子储物柜。每个格子都有一个编号——内存地址(常称为地址),我们可以用这个编号来记住我们在放了东西的位置。

定义一个变量:

int i  = 5;

这样就将i 和5关联起来了,i 相当于标签名,对i 的存取操作就是5所在的计算机内存空间存取,5在计算机内存空间的存放位置就是地址。这个地址可以通过&i 获得。【地址值的分配是由计算机系统完成的,不固定。】

定义指针变量:

int *p;

给指针变量p赋值:

p = &i

就是把变量i 的地址给了p,也常称为p指向i 。这时*p和i 等价——值一样。

上面两句可合写为一句:

int *p = &i;

注意点

(1) 对于上面示例语句, &ip是一样的,i*p也是一样的

(2) 如果*、&在类型说明符之后,则为定义指针、引用;如果出现在表达式中,则为解引用、取地址。

(3) 不允许把一个数赋给指针变量。如:

int *pA;

//pA = 10; //不可以 ,报错

int a = 10;    

 //pA = a;  //不可以,报错

(4) 除指针变量初始化赋值(如int *p = &i;),被赋值的指针变量前不能有*(如*p = &i;是错误的)。

示例代码:

#include <iostream>
using namespace std;int main() {  int a = 10;  //星号符作为指针类型声明符  int * p = & a;  // 声明一个指向整型变量 a 的指针  // i和*p是一样的   cout << "*p = " << * p << endl;  // 输出 10。星号符作为指针解引用运算符cout << "a = " << a << endl;  // 输出 10。// &i和p是一样的cout << "p = " << p << endl;cout << "&a = " << &a << endl;     return 0;  
}

运行结果:

注意,你的运行结果 p和&a显示的地址值是随机的(地址值的分配是由计算机系统完成的,不固定),但两者值相等。

下面是一些常见的指针操作:

1.声明指针:可以使用"*"运算符来声明一个指针变量,其指向的是某个数据类型的地址。例如:

int* ptr; // 声明一个指向int类型数据的指针ptr

2.获取地址:可以使用"&"运算符获取某个变量的地址,将其赋值给指针。例如:

int num = 10;  // 定义一个整型变量num

int* ptr = &num;  // 定义一个指向num的指针ptr

3.解引用操作:使用解引用运算符"*"可以获取指针所指向的变量的值。例如:

int num = 10;

int* ptr = &num;

std::cout << "The value of the variable pointed by ptr is: " << *ptr << std::endl; // 输出:10

4.指针算术运算:指针可以进行加、减、自增、自减等算术运算。例如:

int arr[] = {1, 2, 3, 4, 5};

int* ptr = arr; // 将指针指向数组首元素

std::cout << "The first element of the array is: " << *ptr << std::endl; // 输出:1

ptr++; // 将指针指向下一个元素

std::cout << "The second element of the array is: " << *ptr << std::endl; // 输出:2

5.数组和指针:数组名本身就是一个指针,指向数组的首元素。因此,可以使用指针来操作数组(例如上面的例子),也可以使用数组名来操作数组。例如:

int arr[] = {1, 2, 3, 4, 5};

std::cout << "The first element of the array is: " << arr[0] << std::endl; // 输出:1

std::cout << "The second element of the array is: " << *(arr+1) << std::endl; // 输出:2

6.指针和字符串:指针可以用来处理字符串,因为指针可以指向字符数组的第一个元素。通过指针,我们可以访问和操作字符串中的字符。下面是一个示例,演示了如何使用指针处理字符串:

#include <iostream>
#include <string>
using namespace std;int main() {string str = "Hello";  // 字符串使用string类型表示char *ptr = &str[0];   // 通过指针获取字符串的第一个字符// 通过指针遍历字符串并打印每个字符while (*ptr != '\0') {cout << *ptr << " ";ptr++;  // 指针移到下一个字符位置}cout << endl;int a = 10;int& ref = a;  // 引用引用变量acout << "a = " << a << endl;cout << "ref = " << ref << endl;ref = 20;  // 通过引用直接操作变量a的值cout << "a = " << a << endl;return 0;
}

7.指针和函数:

以下是一些指针和函数的常见用法:

指针作为函数参数:将指针传递给函数,允许函数修改指针指向的变量。例如,使用指针实现一个交换两个整数的函数:

void swap(int* a, int* b) {

    int temp = *a;

    *a = *b;

    *b = temp;

}

函数返回指针:函数可以返回指针,指向函数内部创建的动态对象。例如,实现一个创建整数对象并返回其指针的函数可以写为:

int* create_int(int value) {

    int* ptr = new int(value);

    return ptr;

}

下面给出几个完整示例。

例1、一个简单例子源码:

#include <iostream>
using namespace std;int main()
{int num = 10;int *ptr = &num; // 定义一个指向整型变量num的指针ptr,&num是num的地址cout << "num的值为:" << num << endl; // 输出变量num的值cout << "指针ptr所指向的变量的值为:" << *ptr << endl; // 输出指针ptr所指向的变量的值cout << "变量num的地址为:" << &num << endl; // 输出变量num的地址cout << "指针ptr所存储的地址为:" << ptr << endl; // 输出指针ptr所存储的地址return 0;
}

在这个例子中,定义了一个整型变量num,并将它的值设置为10;接着定义了一个指向num的指针ptr,并将它的值设为num的地址。使用了&运算符获取num的地址。然后通过指针ptr,输出了num的值,以及指针ptr的存储地址(ptr自己的地址)和所指向的变量的地址(即num的地址)。最后,返回0以结束程序。

运行结果:

num的值为:10
指针ptr所指向的变量的值为:10
变量num的地址为:0x23fe1c
指针ptr所存储的地址为:0x23fe1c

2、通过指针来访问和操作数组元素:

#include <iostream>
using namespace std;int main() {int arr[5] = {1, 2, 3, 4, 5};int* ptr = arr;  // 将指针ptr指向数组arr的第一个元素// 使用指针访问数组元素for (int i = 0; i < 5; ++i) {cout << "Element at index " << i << ": " << *(ptr + i) << endl;}return 0;
}

上面的例子中,定义了一个包含5个整数的数组arr,并初始化了其元素。然后,将指针ptr指向数组的第一个元素,也就是arr[0]。通过使用指针ptr和偏移量i,可以访问数组中的各个元素。

在循环中,使用*(ptr + i)的方式来访问数组元素。这里的ptr + i表示指针ptr加上偏移量i,得到了指向数组中第i个元素的指针,然后通过*操作符解引用指针,即可获取该元素的值。在每次迭代中,输出当前索引和对应元素的值。

输出结果是:

Element at index 0: 1
Element at index 1: 2
Element at index 2: 3
Element at index 3: 4
Element at index 4: 5

以上是一些常见的指针操作。下面的部分初学者可以了解,不需深究。

还有一些指针操作,例如,动态内存分配和释放:可以使用“new”运算符在堆上分配一块内存,并返回该内存块的首地址。例如:

int* ptr = new int; // 在堆上分配一个int类型的内存块,并将其地址赋给指针ptr

*ptr = 10; // 给该内存块赋值

std::cout << "The value of the variable pointed by ptr is: " << *ptr << std::endl; // 输出:10

使用“delete”运算符来释放在堆上分配的内存。例如:

int* ptr = new int;

// 做一些操作

delete ptr; // 释放ptr所指向的内存块

需要注意的是,指针操作容易引起内存泄漏和悬空指针等问题,下面解说之。

内存泄漏 (Memory Leak)

内存泄漏是指程序在运行过程中,动态分配了内存,但没有在不再需要时释放这些内存,导致系统内存被消耗殆尽。内存泄漏的常见原因是使用new分配内存后没有对应的delete操作。使用 new 运算符分配给指针的内存,需要使用 delete 运算符来释放该内存。这是为了防止内存泄漏,确保程序动态分配的内存能在不再需要时正确释放。以下是一个简单的例子:

int* p = new int; // 使用 new 动态分配内存

*p = 42;          // 使用这块内存

delete p;         // 使用 delete 释放内存

p = nullptr;      // 将指针设为 nullptr 避免悬空指针

当使用 new[] 运算符分配数组内存时,应该使用 delete[] 运算符来释放:

int* arr = new int[10]; // 使用 new[] 动态分配数组内存

// 使用数组...

delete[] arr;           // 使用 delete[] 释放数组内存

arr = nullptr;          // 将指针设为 nullptr 避免悬空指针

通过遵循这些规则,可以有效避免内存泄漏和悬空指针问题。建议使用C++标准库提供的智能指针(如 std::unique_ptr 和 std::shared_ptr)来自动管理内存,这样可以进一步减少手动管理内存的风险。

悬空指针 (Dangling Pointer)

悬空指针是指一个指向已释放或无效内存区域的指针。当访问悬空指针时,会导致未定义行为,可能引发程序崩溃或数据损坏。以下是几个常见的悬空指针情况:

1. 指向局部变量的指针超出作用域:

int* getPointer() {

    int x = 42;     // 局部变量

    return &x;      // 返回局部变量的地址

} // x超出作用域被销毁

void danglingPointerExample() {

    int* p = getPointer(); // p现在是一个悬空指针

    // *p 引用已被销毁的内存,未定义行为

}

2. 释放内存后未将指针设为nullptr:

void danglingPointerExample() {

    int* p = new int(10);

    delete p;       // 释放p指向的内存

    // p现在成为悬空指针

    // *p = 20;    // 访问已释放的内存,未定义行为

    p = nullptr;    // p设置为nullptr避免悬空指针

}

如何避免这些问题

  1. 及时释放内存: 动态分配内存后,在不再使用时应及时释放。
  2. 初始化指针: 使用指针前,确保其指向有效内存或nullptr。
  3. 使用智能指针: 使用C++标准库中的智能指针(如std::unique_ptr和std::shared_ptr),它们可以自动管理内存,减少内存泄漏和悬空指针的风险。

智能指针(Smart Pointers)是C++11及其后续版本引入的一种用于管理动态分配内存的指针类型。智能指针通过封装原始指针,并以对象的方式管理内存,提供了自动内存管理的能力。它们可以自动地释放分配的内存,避免内存泄漏和悬空指针问题。智能指针是现代C++中推荐使用的方式之一,能够提高代码的安全性和可维护性。C++标准库提供了几种智能指针类型,其中最常用的是std::unique_ptr和std::shared_ptr。

C++标准库提供了几种智能指针类型,其中最常用的是std::unique_ptr和std::shared_ptr。若想使用时,需要包含<memory>头文件。

<memory> 是 C++ 标准库中的一个头文件,它提供了对内存管理功能的支持,包括智能指针(如 std::unique_ptr 和 std::shared_ptr)、内存分配器、对齐和未初始化内存等功能。

std::unique_ptr是一种独占式智能指针,它在任何时刻都只允许一个std::unique_ptr对象拥有对其指向的内存的控制权。这有助于防止内存泄漏。当std::unique_ptr超出作用域或者被重新赋值时,它自动释放所指向的内存。

std::shared_ptr是一种共享式智能指针,它允许多个std::shared_ptr对象共同拥有对同一内存地址的控制权。通过引用计数来管理内存,当最后一个拥有该内存的std::shared_ptr对象被销毁时,内存会被自动释放。

【提示:在 C++ 标准库中,std:: 命名空间包含了所有标准库组件。因此,当我们使用标准库中的类或函数时,必须要指定 std:: 命名空间。如果不想在每次使用标准库组件时都加上 std:: 前缀,可以通过 using 指令来引入整个命名空间或者指定的组件成员:using namespace std;只引入 std 命名空间中的某个成员如 unique_ptr 可用 using std::unique_ptr;】

示例:unique_ptr 管理动态分配的数组

#include <iostream>
#include <memory> // 引入 <memory> 头文件
using namespace std;int main() {// 创建一个 std::unique_ptr 管理 int 数组unique_ptr<int[]> arr(new int[5]);for (int i = 0; i < 5; ++i) {arr[i] = i * 10;}for (int i = 0; i < 5; ++i) {cout << "arr[" << i << "] = " << arr[i] << endl;}// 不需要显式删除数组,智能指针会在离开作用域时自动释放内存return 0;
}

在这个示例中,我们使用 new int[5] 来创建一个包含 5 个整数的动态数组,并将其赋值给 std::unique_ptr<int[]>。这样可以正确地管理数组的内存,并且当 arr 超出作用域时,内存将自动释放。

、C++指针(pointer)介绍https://blog.csdn.net/cnds123/article/details/108981367

C++指针(这是一篇正经知识总结)https://zhuanlan.zhihu.com/p/517099946

相关文章:

C++青少年简明教程:C++的指针入门

C青少年简明教程&#xff1a;C的指针入门 说到指针&#xff0c;就不可能脱离开内存。了解C的指针对于初学者来说可能有些复杂&#xff0c;我们可以试着以一种简单、形象且易于理解的方式来解释&#xff1a; 首先&#xff0c;我们可以将计算机内存想象成一个巨大的有许多格子的…...

Apache Doris 基础 -- 数据表设计(分层存储)

1、应用场景 未来一个重要的用例是类似于ES日志存储&#xff0c;其中日志场景中的数据是根据日期分割的。许多数据都是查询不频繁的冷数据&#xff0c;因此需要降低此类数据的存储成本。考虑到节约成本: 来自不同厂商的常规云磁盘的定价比对象存储更昂贵。Doris 集群实际在线…...

使用Spring Boot设计一套BI系统

商业智能&#xff08;Business Intelligence&#xff0c;简称BI&#xff09;系统是一种将数据转化为可操作信息&#xff0c;帮助企业进行决策支持的技术与工具的集合。随着大数据时代的到来&#xff0c;BI系统在企业中的应用变得越来越广泛。本文旨在探讨如何使用Spring Boot框…...

2024.6.12总结

今天是排毕业照的日子&#xff0c;拍照的时候并没有太过兴奋。后来受到主管说明天就能签offer了&#xff0c;这才喜极而泣。 自从得知自己面试通过后&#xff0c;我是非常高兴&#xff0c;开始幻想着今后的生活。可是&#xff0c;后面在等offer的过程中&#xff0c;我是无比的…...

1027 - 求任意三位数各个数位上数字的和

问题描述 对于一个任意的三位自然数 x &#xff0c;编程计算其各个数位上的数字之和 S 。 输入 输入一行&#xff0c;只有一个整数 x(100≤x≤999) 。 输出 输出只有一行&#xff0c;包括 1 个整数。 样例 输入 123 输出 6 以下是C实现的代码&#xff1a; 代码1 #…...

K8s 卷快照类

卷快照类 卷快照类 这个警告信息通常出现在使用 kubectl 删除 Kubernetes 集群资源时&#xff0c;如果尝试删除的是集群作用域&#xff08;cluster-scoped&#xff09;的资源&#xff0c;但指定了命名空间&#xff08;namespace&#xff09;&#xff0c;就会出现这个警告。 集…...

从零手写实现 nginx-23-directive IF 条件判断指令

前言 大家好&#xff0c;我是老马。很高兴遇到你。 我们为 java 开发者实现了 java 版本的 nginx https://github.com/houbb/nginx4j 如果你想知道 servlet 如何处理的&#xff0c;可以参考我的另一个项目&#xff1a; 手写从零实现简易版 tomcat minicat 手写 nginx 系列 …...

08_基于GAN实现人脸图像超分辨率重建实战_超分辨基础理论

1. 超分辨的概念与应用 我们常说的图像分辨率指的是图像长边像素数与图像短边像素数的乘积,比如iPhoneX手机拍摄照片的分辨率为 4032px3024px,为1200万像素。 显然,越高的分辨率能获得更清晰的成像。与之同时,分辨率越高也意味着更大的存储空间,对于空间非常有限的移动设…...

React.ReactElement 与 React.ReactNode

React.ReactNode 在 JSX 中作为子元素传递的所有可能类型的并集&#xff0c;这是对子元素的一个非常宽泛的定义。 <RNode><p>One element</p></RNode><RNode><><p>Fragments for</p><p>More elements</p></&g…...

深度解析服务发布策略之蓝绿发布

目录 什么是蓝绿发布 蓝绿发布的优点 蓝绿发布的缺点 蓝绿发布的实现步骤 小结 在软件开发和运维中&#xff0c;发布新版本是一个风险较高的操作。为了降低风险&#xff0c;提高发布的稳定性和可靠性&#xff0c;通常会采取一系列的技术策略。其中蓝绿发布&#xff08;Blu…...

【Mysql】 深入理解MySQL的执行计划

文章目录 前言一、字段解释二、代码实现三、总结 前言 在日常的数据库操作中&#xff0c;我们经常会遇到一些复杂的查询&#xff0c;这些查询可能会涉及到多个表的联合查询&#xff0c;或者是一些复杂的条件筛选。为了更好地理解和优化这些查询&#xff0c;了解MySQL的执行计划…...

说下你对Spring IOC 的理解

说下你对Spring IOC 的理解 1. Spring IOC是一个管理对象之间依赖关系的容器&#xff0c;它实现了依赖注入技术&#xff0c;可以解决传统的紧耦合问题&#xff0c;降低了项目维护难度。 2. Spring IOC将对象之间的依赖关系交由容器来管理对象&#xff0c;开发者只需要告诉容器…...

前缀和算法:算法秘籍下的数据预言家

✨✨✨学习的道路很枯燥&#xff0c;希望我们能并肩走下来! 文章目录 目录 文章目录 前言 一. 前缀和算法的介绍 二、前缀和例题 2.1 【模版】前缀和 2.2 【模板】二维前缀和 2.3 寻找数组的中间下标 2.4 除自身以外数组的乘积 2.5 和为k的子数组 2.6 和可被k整除的子数组 2.7 …...

基于PointNet / PointNet++深度学习模型的激光点云语义分割

一、场景要素语义分割部分的文献阅读笔记 1.1 PointNet PointNet网络模型开创性地实现了直接将点云数据作为输入的高效深度学习方法&#xff08;端到端学习&#xff09;。最大池化层、全局信息聚合结构以及联合对齐结构是该网络模型的三大关键模块&#xff0c;最大池化层解决了…...

LabVIEW调用DLL时需注意的问题

在LabVIEW中调用DLL&#xff08;动态链接库&#xff09;是实现与外部代码集成的一种强大方式&#xff0c;但也存在一些常见的陷阱和复杂性。本文将从参数传递、数据类型匹配、内存管理、线程安全、调试和错误处理等多个角度详细介绍LabVIEW调用DLL时需要注意的问题&#xff0c;…...

时序预测 | MATLAB实现TCN-Attention自注意力机制结合时间卷积神经网络时间序列预测

时序预测 | MATLAB实现TCN-Attention自注意力机制结合时间卷积神经网络时间序列预测 目录 时序预测 | MATLAB实现TCN-Attention自注意力机制结合时间卷积神经网络时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.MATLAB实现TCN-Attention自注意力机制结合时…...

上位机图像处理和嵌入式模块部署(h750 mcu vs f407)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 在目前工业控制上面&#xff0c;f103和f407是用的最多的两种stm32 mcu。前者频率低一点&#xff0c;功能少一点&#xff0c;一般用在低端的嵌入式设…...

Linux C语言:指针和指针变量

一、指针的作用 使程序简洁、紧凑、高效有效地表示复杂的数据结构动态分配内存能直接访问硬件能够方便的处理字符串得到多于一个的函数返回值 二、内存、地址和变量 1、内存地址 2、变量和地址 1&#xff09;变量用来在程序中保存数据 比如: int k 58; //声明一个int变…...

Llama模型家族之Stanford NLP ReFT源代码探索 (二)Intervention Layers层

LlaMA 3 系列博客 基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;一&#xff09; 基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;二&#xff09; 基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;三&#xff09; 基于 LlaMA…...

MATLAB神经网络---序列输入层sequenceInputLayer

序列输入层sequenceInputLayer 描述一&#xff1a; sequenceinputlayer是Matlab深度学习工具箱中的一个层&#xff0c;用于处理序列数据输入。它可以将输入数据转换为序列格式,并将其传递给下一层进行处理。该层通常用于处理文本、语音、时间序列等类型的数据。在使用该层时&…...

使用CSS、JavaScript、jQuery三种方式实现手风琴效果

手风琴效果有不少&#xff0c;王者荣耀官网&#xff08;源网址 https://pvp.qq.com/raiders/ &#xff09;有一处周免英雄&#xff0c;使用的就是手风琴效果&#xff0c;如图所示。 我试着用css、js、jQuery三种方式实现了这种效果&#xff0c;最终效果差不多&#xff0c;美中不…...

什么是无头浏览器以及其工作原理?

如果您对这个概念还不熟悉&#xff0c;那么使用无头网络浏览器的想法可能会让您感到不知所措。无头浏览器本质上与您熟悉的网络浏览器相同&#xff0c;但有一个关键区别&#xff1a;它们没有图形用户界面 (GUI)。这意味着没有按钮、选项卡、地址栏或视觉显示。 相反&#xff0c…...

计算机网络 —— 应用层(DNS域名系统)

计算机网络 —— 应用层&#xff08;DNS域名系统&#xff09; 什么是DNS域名的层次结构域名分类 域名服务器的分类域名解析方式递归查询&#xff08;Recursive Query&#xff09;迭代查询&#xff08;Iterative Query&#xff09;域名的高速缓存 我们今天来看DNS域名系统 什么…...

Linux--MQTT简介

一、简介 MQTT &#xff08; Message Queuing Telemetry Transport&#xff0c;消息队列遥测传输&#xff09;&#xff0c; 是一种基于客户端服务端架构的发布/订阅模式的消息传输协议。 与 HTTP 协议一样&#xff0c; MQTT 协议也是应用层协议&#xff0c;工作在 TCP/IP 四…...

VMware Workerstation开启虚拟机后,产生乱码名称日志文件

问题情况 如下图所示&#xff0c;我的虚拟机版本是16.1.2版本&#xff0c;每次在启动虚拟机之后&#xff0c;D盘目录下都会产生一个如图下所示的乱码名称文件。同时&#xff0c;虚拟机文件目录也是杂乱不堪&#xff0c;没有按照一台虚拟机对应一个文件夹的形式存在。 问题处理…...

Unity射击游戏开发教程:(27)创建带有百分比的状态栏

创建带有弹药数和推进器百分比的状态栏 在本文中,我将介绍如何创建带有分数和百分比文本的常规状态栏。 由于 Ammo Bar 将成为 UI 的一部分,因此我们需要向 Canvas 添加一个空的 GameObject 并将其重命名为 AmmoBar。我们需要一个文本和两个图像对象,它们是 AmmoBar 的父级。…...

Linux内存从0到1学习笔记(8.16 SMMU详解)---更新中

写在前面 前面博客已经了解过。SMMU是IOMMU在ARM架构上的实现。主要为了解决虚拟化环境中&#xff0c;GuestOS无法直接将连续的物理地址分配给硬件的问题。对于Hypervisor/GuestOS的虚拟化系统来说&#xff0c;所有的VM都运行在Hypervisor上&#xff0c;每一个VM独立运行一个O…...

标准盒模型和怪异盒模型的区别

CSS盒模型&#xff1a; 内容区&#xff08;content&#xff09;内边距&#xff08;padding&#xff09;边框&#xff08;border&#xff09;外边距&#xff08;margin&#xff09; 分为标准盒模型和IE盒模型/怪异盒模型 为了正确设置元素在所有浏览器中的宽度和高度&#xf…...

【第8章】如何利用ControlNet生成“可控画面”?(配置要求/一键安装/快速上手/生成第一张图)ComfyUI基础入门教程

这节我们来讲AI绘画领域中一个很重要的概念:ControlNet,看下如何让生成的画面更可控。 🎅什么是ControlNet? Stable Diffusion中的ControlNet是一种神经网络结构,它允许将额外的条件输入添加到预训练的图像扩散模型中,通过这种方式,ControlNet可以控制图像生成过程,…...

[qt] qt程序打包以及docker镜像打包

目录 一 环境准备: 1.1 qt环境 1.2 linuxdeplouqt打包工具 二 qt包发布: 2.1 搜索链接库 2.2 应用程序APP打包 2.3 发布 三 docker镜像包发布 3.1 环境准备 3.2 镜像生产脚本 3.3 加载镜像并运行docker容器 四 补充 4.1 时间不同步问题解决 一 环境准备: qt环境l…...