C++学习——指针篇

本篇文章记录我学习C++的指针内容,希望我的分享能给你带来不一样的收获!

目录

一、指针有什么好处

二、什么是指针

三、C++指针内容详解

(一)、空指针(Null)

(二)、指针的算数运算

1、递增一个指针

2、递减一个指针

3、指针的比较

(三)、指针与数组的比较 

1. 数组和指针的关系

2. 数组名和指针

3. 初始化和赋值

4. 指针与数组的访问

5. 数组的性质

6. 指针的灵活性

7. 指针与数组的区别

(四)、指针数组 

1、声明指针数组

2、初始化指针数组

3、访问指针数组元素

 4、动态分配内存给指针数组

5、释放内存

6、示例

(五)、指向指针的指针

(六)、C++传递指针给函数

(七)、C++从函数返回指针


一、指针有什么好处

通过指针,可以简化一些 C++ 编程任务的执行,还有一些任务,如动态内存分配,没有指针是无法执行的。每一个变量都有一个内存位置,每一个内存位置都定义了可使用连字号(&)运算符访问的地址,它表示了在内存中的一个地址。

#include <iostream>using namespace std;int main (){int var1;char var2[10];cout << "var1 变量的地址: ";cout << &var1 << endl;cout << "var2 变量的地址: ";cout << &var2 << endl;return 0;}执行结果如下:var1 变量的地址: 0xbfebd5c0var2 变量的地址: 0xbfebd5b6

二、什么是指针

指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。就像其他变量或常量一样,必须在使用指针存储其他变量地址之前,对其进行声明。指针变量声明的一般形式为:

type *var-name;

在这里,type 是指针的基类型,它必须是一个有效的 C++ 数据类型,var-name 是指针变量的名称。用来声明指针的星号 * 与乘法中使用的星号是相同的。但是,在这个语句中,星号是用来指定一个变量是指针。以下是有效的指针声明:

int *ip; /* 一个整型的指针 */

double *dp; /* 一个 double 型的指针 */

float *fp; /* 一个浮点型的指针 */

char *ch; /* 一个字符型的指针 */

所有指针的值的实际数据类型,不管是整型、浮点型、字符型,还是其他的数据类型,都是一样的,都是一个代表内存地址的长的十六进制数。不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同。

三、C++指针内容详解

(一)、空指针(Null)

在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针。

NULL 指针是一个定义在标准库中的值为零的常量。请看下面的程序:

实例

#include <iostream>

using namespace std;

int main ()

{

   int *ptr = NULL;

   cout << "ptr 的值是 " << ptr ;

 

   return 0;

}

当上面的代码被编译和执行时,它会产生下列结果:

ptr 的值是 0

在大多数的操作系统上,程序不允许访问地址为 0 的内存,因为该内存是操作系统保留的。然而,内存地址 0 有特别重要的意义,它表明该指针不指向一个可访问的内存位置。但按照惯例,如果指针包含空值(零值),则假定它不指向任何东西。

如需检查一个空指针,可以使用 if 语句,如下所示:

if(ptr) /* 如果 ptr 非空,则完成 */

if(!ptr) /* 如果 ptr 为空,则完成 */

因此,如果所有未使用的指针都被赋予空值,同时避免使用空指针,就可以防止误用一个未初始化的指针。很多时候,未初始化的变量存有一些垃圾值,导致程序难以调试。

(二)、指针的算数运算

指针是一个用数值表示的地址。因此,可以对指针执行算术运算。可以对指针进行四种算术运算:++、--、+、-。

假设 ptr 是一个指向地址 1000 的整型指针,是一个 32 位的整数,让我们对该指针执行下列的算术运算:

ptr++

执行 ptr++ 后,指针 ptr 会向前移动 4 个字节,指向下一个整型元素的地址。这是由于指针算术运算会根据指针的类型和大小来决定移动的距离。在这种情况下,由于是一个 32 位整数指针,每个整数占据 4 个字节,因此 ptr++ 会将指针 ptr 向前移动 4 个字节,指向下一个整型元素的地址。

如果 ptr 指向一个地址为 1000 的字符,执行 ptr++ 指针 ptr 的值会增加,指向下一个字符元素的地址,由于 ptr 是一个字符指针,每个字符占据 1 个字节,因此 ptr++ 会将 ptr 的值增加 1,执行后 ptr 指向地址 1001。

指针算术运算的详细解析:

加法运算:可以对指针进行加法运算。当一个指针p加上一个整数n时,结果是指针p向前移动n个元素的大小。例如,如果p是一个int类型的指针,每个int占4个字节,那么p + 1将指向p所指向的下一个int元素。

减法运算:可以对指针进行减法运算。当一个指针p减去一个整数n时,结果是指针p向后移动n个元素的大小。例如,如果p是一个int类型的指针,每个int占4个字节,那么p - 1将指向p所指向的前一个int元素。

指针与指针之间的减法运算:可以计算两个指针之间的距离。当从一个指针p减去另一个指针q时,结果是两个指针之间的元素个数。例如,如果p和q是两个int类型的指针,每个int占4个字节,那么p - q将得到两个指针之间的元素个数。

指针与整数之间的比较运算:可以将指针与整数进行比较运算。可以使用关系运算符(如<、>、<=、>=)对指针和整数进行比较。这种比较通常用于判断指针是否指向某个有效的内存位置。

1、递增一个指针

我们喜欢在程序中使用指针代替数组,因为变量指针可以递增,而数组不能递增,因为数组是一个常量指针。下面的程序递增变量指针,以便顺序访问数组中的每一个元素:

实例:

#include <iostream>using namespace std;const int MAX = 3;int main (){int var[MAX] = {10, 100, 200};int *ptr;// 指针中的数组地址ptr = var;for (int i = 0; i < MAX; i++){cout << "Address of var[" << i << "] = ";cout << ptr << endl;cout << "Value of var[" << i << "] = ";cout << *ptr << endl;// 移动到下一个位置ptr++;}return 0;}当上面的代码被编译和执行时,它会产生下列结果:Address of var[0] = 0xbfa088b0Value of var[0] = 10Address of var[1] = 0xbfa088b4Value of var[1] = 100Address of var[2] = 0xbfa088b8Value of var[2] = 200

2、递减一个指针

同样地,对指针进行递减运算,即把值减去其数据类型的字节数,如下所示:

实例:

#include <iostream>using namespace std;const int MAX = 3;int main (){int var[MAX] = {10, 100, 200};int *ptr;// 指针中最后一个元素的地址ptr = &var[MAX-1];for (int i = MAX; i > 0; i--){cout << "Address of var[" << i << "] = ";cout << ptr << endl;cout << "Value of var[" << i << "] = ";cout << *ptr << endl;// 移动到下一个位置ptr--;}return 0;}当上面的代码被编译和执行时,它会产生下列结果:Address of var[3] = 0xbfdb70f8Value of var[3] = 200Address of var[2] = 0xbfdb70f4Value of var[2] = 100Address of var[1] = 0xbfdb70f0Value of var[1] = 10

3、指针的比较

指针可以用关系运算符进行比较,如 ==、< 和 >。如果 p1 和 p2 指向两个相关的变量,比如同一个数组中的不同元素,则可对 p1 和 p2 进行大小比较。

下面的程序修改了上面的实例,只要变量指针所指向的地址小于或等于数组的最后一个元素的地址 &var[MAX - 1],则把变量指针进行递增:

实例:

#include <iostream>using namespace std;const int MAX = 3;int main (){int var[MAX] = {10, 100, 200};int *ptr;// 指针中第一个元素的地址ptr = var;int i = 0;while ( ptr <= &var[MAX - 1] ){cout << "Address of var[" << i << "] = ";cout << ptr << endl;cout << "Value of var[" << i << "] = ";cout << *ptr << endl;// 指向上一个位置ptr++;i++;}return 0;}当上面的代码被编译和执行时,它会产生下列结果:Address of var[0] = 0xbfce42d0Value of var[0] = 10Address of var[1] = 0xbfce42d4Value of var[1] = 100Address of var[2] = 0xbfce42d8Value of var[2] = 200

(三)、指针与数组的比较 

从某种意义上来讲,指针和数组在一些情况下是可以相互互换的。一个指向数组开头的指针,可以通过使用指针的算术运算或数组索引来访问数组。

在C++中,指针和数组是相关但不完全相同的概念。下面是它们之间的一些比较:

1. 数组和指针的关系
  • 数组是一系列相同类型的元素的集合,它们在内存中是连续存储的。
  • 指针是一个变量,其值为另一个变量的地址。指针可以指向数组的首元素,也可以指向任意其他内存位置。
2. 数组名和指针
  • 在大多数情况下,数组名会转换为指向数组首元素的指针。例如,对于数组 int arr[5];arr 可以被视为指向 arr[0] 的指针。
3. 初始化和赋值
  • 数组的初始化int arr[5] = {1, 2, 3, 4, 5};
  • 指针的初始化int* ptr = arr; 这里 ptr 指向 arr 的首元素。
4. 指针与数组的访问
  • 数组元素访问:使用下标访问 arr[i]
  • 指针访问数组元素:可以使用指针进行数组元素的访问,比如 *(arr + i) 或者 ptr[i](等效于 *(ptr + i))。
5. 数组的性质
  • 数组是常量指针:数组名本身在大多数情况下是一个常量指针,不能被重新赋值。
6. 指针的灵活性
  • 指针的灵活性:指针可以指向数组的任意位置,也可以通过指针进行遍历和修改数组元素。
7. 指针与数组的区别
  • 大小和维度:数组具有固定的大小和维度,而指针没有固定大小,可以指向不同大小的内存块。
  • 内存分配:数组在声明时需要分配固定大小的内存空间,而指针可以动态分配或指向已分配的内存块。

下面举一个实例: 

#include <iostream>int main() {int arr[5] = {1, 2, 3, 4, 5};int* ptr = arr; // ptr指向arr的首元素// 使用数组下标访问元素for (int i = 0; i < 5; ++i) {std::cout << arr[i] << " ";}std::cout << std::endl;// 使用指针访问元素for (int i = 0; i < 5; ++i) {std::cout << *(ptr + i) << " ";}std::cout << std::endl;return 0;
}

(四)、指针数组 

指针数组是一个数组,其中的每一个元素都是指针。每个指针可以指向数组、字符串、函数或者其他数据类型的内存地址。这种数据结构在C和C++等编程语言中经常被使用。

1、声明指针数组
int *ptrArray[5]; // 声明一个包含5个指向int类型数据的指针数组
2、初始化指针数组

 指针数组可以通过循环或者手动赋值的方式进行初始化

int a = 10, b = 20, c = 30, d = 40, e = 50;
int *ptrArray[5] = {&a, &b, &c, &d, &e}; // 初始化指针数组
3访问指针数组元素

可以使用数组索引来访问指针数组的元素,每个元素是一个指针,可以通过解引用操作符 * 来获取指向的值。

printf("%d\n", *ptrArray[0]); // 输出指针数组第一个元素指向的值
 4动态分配内存给指针数组

也可以动态分配内存给指针数组,这在需要根据程序运行时情况动态调整数组大小时很有用。

int **ptrArray;
int size = 5;
ptrArray = (int **)malloc(size * sizeof(int *)); // 分配存储指针的内存空间

ptrArray = (int **)malloc(size * sizeof(int *));

  • malloc(size * sizeof(int *)): malloc 是 C 标准库中的函数,用于动态分配内存。sizeof(int *) 是指针类型 int * 的大小(在大多数系统上通常是4字节或8字节,取决于系统的位数),size 是要分配的指针的数量。因此,size * sizeof(int *) 表示要分配的总字节数,即存储 size 个指针所需的总内存空间。

  • (int **): 这是一种类型转换,将 malloc 返回的通用指针 void * 转换为 int ** 类型的指针。int ** 表示指向指针的指针,因此它用于指向指针数组的指针。

所以,整体来说,这行代码的意思是:动态分配一个可以存储 sizeint 类型指针的内存空间,并将其地址赋值给 ptrArray,这样 ptrArray 就成为了一个指向 int 类型指针数组的指针。

5释放内存

如果使用了动态分配内存的指针数组,在使用完毕后需要进行释放内存,以避免内存泄漏。

free(ptrArray); // 释放内存
6、示例
#include <stdio.h>int main() {int a = 10, b = 20, c = 30, d = 40, e = 50;int *ptrArray[5] = {&a, &b, &c, &d, &e}; // 初始化指针数组// 访问指针数组元素并输出for (int i = 0; i < 5; i++) {printf("%d ", *ptrArray[i]);}printf("\n");return 0;
}

(五)、指向指针的指针

指向指针的指针是指一个指针变量,它存储的是另一个指针变量的地址。在C和C++中,指针本身也是一种变量,它存储的是内存地址,而指向指针的指针则是存储指针变量的地址的变量。

下面举一个简单的例子来说明一下:

#include <stdio.h>int main() {int x = 10;int *ptr1 = &x;  // ptr1 指向 x 的地址int **ptr2 = &ptr1;  // ptr2 指向 ptr1 的地址printf("x = %d\n", x);  // 输出 x 的值printf("*ptr1 = %d\n", *ptr1);  // 输出 ptr1 指向的值,即 x 的值printf("**ptr2 = %d\n", **ptr2);  // 输出 ptr2 指向的值,即 ptr1 指向的值,即 x 的值return 0;
}

在这个例子中:

  • ptr1 是一个指向 x 的指针,它存储了 x 的地址。
  • ptr2 是一个指向 ptr1 的指针,它存储了 ptr1 的地址。
  • **ptr2 指的是通过 ptr2 找到 ptr1,再通过 ptr1 找到 x,因此输出的是 x 的值。

指向指针的指针在某些情况下很有用,特别是在函数中传递指针的地址以便能够修改指针指向的内容时。

(六)、C++传递指针给函数

通过传递指针给函数来实现对函数外部变量的引用或者修改。这种方式在函数调用时不会对原始数据进行拷贝,而是直接操作原始数据的地址。以下是传递指针给函数的基本方法。

1、函数声明和定义

// 函数声明
void modifyValue(int* ptr);// 函数定义
void modifyValue(int* ptr) {*ptr = 100; // 修改指针所指向的变量的值为100
}

2、调用函数并且传递指针

int main() {int value = 10;int* ptr = &value; // 指针ptr指向value的地址// 调用函数并传递指针modifyValue(ptr);// 打印修改后的值std::cout << "Modified value: " << value << std::endl;return 0;
}

3、解析

  • 在 main 函数中创建了一个整型变量 value,并将其地址赋给指针 ptr
  • modifyValue 函数接受一个指针作为参数,通过该指针可以修改原始数据的值。
  • 在调用 modifyValue 函数时,将指针 ptr 作为参数传递给函数,函数内部通过解引用指针来修改变量 value 的值。
  • 打印修改后的值,可以看到 value 的值已经被修改为100。

注意事项

  • 在使用指针传递参数时,要确保指针不为NULL,否则可能会导致未定义的行为或错误。
  • 使用指针传递参数时,要注意指针所指向的内存区域的生命周期,确保在函数使用期间该内存区域是有效的。
  • 当需要在函数内部修改函数外部变量的值时,传递指针是一种有效的方法,但需要注意函数的副作用。

(七)、C++从函数返回指针

在C++中,函数可以返回指针以提供对动态分配内存或函数外部变量的访问。返回指针的函数通常用于以下情况:

  1. 动态内存分配:函数可以在堆上动态分配内存,并返回指向该内存的指针,允许调用者在函数外部访问分配的内存。

  2. 函数外部变量的访问:函数可以返回指向函数外部变量的指针,以便在函数外部修改该变量的值。

1、返回指向动态分配内存的指针

#include <iostream>int* createArray(int size) {int* arr = new int[size]; // 在堆上动态分配内存for (int i = 0; i < size; ++i) {arr[i] = i * 2; // 初始化数组元素}return arr; // 返回指针指向分配的内存
}int main() {int* ptr = createArray(5); // 调用函数并接收返回的指针// 使用返回的指针访问动态分配的内存for (int i = 0; i < 5; ++i) {std::cout << ptr[i] << " ";}std::cout << std::endl;// 释放动态分配的内存delete[] ptr;return 0;
}

2、返回指向函数外部变量的指针

#include <iostream>int* findLarger(int a, int b) {if (a > b) {return &a; // 返回指向a的指针} else {return &b; // 返回指向b的指针}
}int main() {int x = 5, y = 10;int* larger = findLarger(x, y); // 调用函数并接收返回的指针// 使用返回的指针修改函数外部变量的值*larger = 100;std::cout << "x: " << x << std::endl; // 输出修改后的x的值std::cout << "y: " << y << std::endl; // 输出修改后的y的值return 0;
}

注意事项

  • 返回指针的函数必须确保返回的指针在函数外部仍然有效。在第一个例子中,返回的指针指向动态分配的内存,因此在使用完指针后需要负责释放内存。
  • 当函数返回指向函数外部变量的指针时,要确保函数外部变量的生命周期足够长,以免在指针使用期间变量被销毁而导致悬挂指针(dangling pointer)问题。
  • 在使用返回指针的函数时,要注意对返回的指针进行空指针检查,以确保指针的有效性。

 

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

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

相关文章

DL00198-基于3DUnet的脑肿瘤语义分割完整代码+数据集含输出结果

完整代码数据集见文末 3DUNet是一种卷积神经网络&#xff08;CNN&#xff09;&#xff0c;专为处理3D图像而设计。它基于U-Net架构&#xff0c;是一种对称的卷积网络&#xff0c;具有上采样和下采样的过程。PyTorch 3DUNet在U-Net的基础上添加了更多的卷积层和跳跃连接&#xf…

在git上先新建仓库-把本地文件提交远程

一.在git新建远程项目库 1.选择新建仓库 以下以gitee为例 2.输入仓库名称&#xff0c;点击创建 这个可以选择仓库私有化还公开权限 3.获取仓库clone链接 这里选择https模式就行&#xff0c;就不需要配置对电脑进行sshkey配置了。只是需要每次提交输入账号密码 二、远…

网站基本建设基本上步骤

网站基本建设基本上步骤 一.领取一个免费域名和SSL证书&#xff0c;和CDN 1.打开网站链接&#xff1a;https://www.rainyun.com/ycpcp_ 首先创建一个CDN&#xff0c;这里以我加速域名“cdntest.biliwind.com 1”为例 这里就要填写 cdntest.biliwind.com 1 &#xff0c;而不是…

4.1 JavaScript的使用

JavaScript有两种使用方式&#xff1a;一是在HTML文档中直接添加代码&#xff1b;二是将JavaScript脚本代码写到外部的JavaScript文件中&#xff0c;再在HTML文档中引用该文件的路径地址。 这两种使用方式的效果完全相同&#xff0c;可以根据使用率和代码量选择相应的开发方式。…

Qt5.15以上版本在线安装步骤,可选择更多早期版本

以ubuntu系统为例&#xff1a; 1、先去下载在线安装程序&#xff1a; https://download.qt.io/official_releases/online_installers/ 选择合适的版本&#xff0c;这里是在x64机器的ubuntu虚拟机里安装QT&#xff0c;所以选择如下版本&#xff1a; 或者直接在终端执行如下命令…

Qt | 元对象系统

一、QByteArray 类简介 1、QByteArray 类简介  该类是一个用于处理字符串的类似于 C++的 string 类型的类,在 Qt 中,对字符串的处理,经常使用的是 QString 类,该类保证字符串以\0结尾,并使用隐式共享(copy-on-write)来减少内存用量和不必要的数据复制。  QByteArra…

【ControlNet v3版本论文阅读】

网络部分最好有LDM或者Stable Diffusion的基础&#xff0c;有基础的话会看的很轻松 Abstract 1.提出了一种网络结构支持额外输入条件控制大型预训练的扩散模型。利用预训练模型学习一组不同的条件控制。 2.ControlNet对于小型&#xff08;<50k&#xff09;或大型&#xff…

Halcon的HWindowControl控件在C#WinForm中的使用介绍(包括绘制ROI)

Halcon的HSmartWindowControl控件在C#WinForm中的使用介绍&#xff08;包括绘制ROI&#xff09; 文章目录 Halcon的HSmartWindowControl控件在C#WinForm中的使用介绍&#xff08;包括绘制ROI&#xff09;一、 引入hSmartWindowControl控件二、 编写打开图像功能三、 编写绘制RO…

操作系统②——内存管理

1. 栈、堆 1.1 程序的内存分配 栈区&#xff08;stack&#xff09;&#xff1a;由编译器自动分配释放 &#xff0c;存放函数的参数值&#xff0c;局部变量的值等。其操作方式类似于数据结构中的栈。堆区&#xff08;heap&#xff09;&#xff1a;一般由程序员分配释放&#x…

光猫桥接模式详细步骤

目录 一、前言 路由模式 &#xff08;宽带默认&#xff09; 桥接模式 二、桥接模式步骤 &#xff08;一&#xff09;图片记录备份 设备信息图 网络侧信息 远程管理密码 宽带上网设置 &#xff08;二&#xff09;桥接模式开始 光猫设置 路由器设置 一、前言 重点&a…

2_5.Linux存储的基本管理

实验环境&#xff1a; 系统里添加两块硬盘 ##1.设备识别## 设备接入系统后都是以文件的形式存在 设备文件名称&#xff1a; SATA/SAS/USB /dev/sda,/dev/sdb ##s SATA, dDISK a第几块 IDE /dev/hd0,/dev/hd1 ##h hard VIRTIO-BLOCK /de…

sharding‐jdbc之分库分表(mysql主从同步的数据库安装和使用)

水平分表 创建基础工程.. 引入sharding‐jdbc的maven依赖包 注意需要数据库连接池等依赖 <dependency><groupId>org.apache.shardingsphere</groupId><artifactId>sharding-jdbc-spring-boot-starter</artifactId><version>4.0.0-RC1&l…

【JavaWeb】Day36.MySQL概述——数据库设计-DDL(三)

查询 关于表结构的查询操作&#xff0c;工作中一般都是直接基于图形化界面操作。 1.查询当前数据库所有表 2.查看指定表结构 3.查询指定表的建表语句 注意&#xff1a;23版的点击导航中的转到DDL 修改 关于表结构的修改操作&#xff0c;一般也是直接基于图形化界面操作。 添…

智能感应门改造工程

今天记录一下物联网专业学的工程步骤及实施过程 智能感应门改造工程 1 规划设计1.1 项目设备清单1.2项目接线图 软件设计信号流 设备安装与调试工程函数 验收 1 规划设计 1.1 项目设备清单 1.2项目接线图 软件设计 信号流 设备安装与调试 工程函数 工程界面: using System; …

【STM32】存储器和位带映射(bit band mapping)

文章目录 0 前言1 关于地址和存储器2 STM32内部存储器3 位带映射&#xff08;bit band mapping&#xff09;4 扩展&#xff1a;IAP 0 前言 最近在研究stm32标准库&#xff0c;对使用宏定义实现位操作的函数非常感兴趣&#xff0c;简单的一句PAout(1) 0;就能实现某个引脚电平的…

Linux离线安装python3(源码编译)

1、下载python包 下载python3.9.6的源码包 python下载 下载后&#xff0c;解压&#xff0c;目录如下&#xff1a; -rw-------. 1 root root 1454 Aug 26 2023 anaconda-ks.cfg -rw-r--r--. 1 root root 25640094 Apr 4 21:52 Python-3.9.6.tgz drwxrwxr…

前端三剑客 —— JavaScript (第一天)

目录 回顾内容 1.弹性布局 2.网格布局 JavaScript 概述 发展 浏览器 什么是Javascript JavaScript 能干什么 JavaScript需要的环境 JavaScript初体验 基本数据 JS书写方式 行内JS 页面JS 外部JS 1&#xff09;创建外部JS文件 2&#xff09;编写页面 对话框 警…

ubuntu-server部署hive-part2-安装hadoop

参照 https://blog.csdn.net/qq_41946216/article/details/134345137 操作系统版本&#xff1a;ubuntu-server-22.04.3 虚拟机&#xff1a;virtualbox7.0 安装hadoop ​​​​​​下载上传 下载地址 https://archive.apache.org/dist/hadoop/common/hadoop-3.3.4/ 以root用…

simulink的硬件支持下,串口发送的模型,stm32f407的串口程序调试错误

串口调试助手能接收到数据&#xff0c;为何是8个数据&#xff1f;如之奈何&#xff1f; 参考文章&#xff1a; STM32CubeMxMATLAB Simulink串口输出实验_用stm32cubemx生成的串口都是输出-CSDN博客根据 该文章发送字符串 hello&#xff0c;发送数量为5&#xff0c;接收也是he…

【PyQt5篇】多线程

文章目录 &#x1f354;使用QtDesigner进行设计&#x1f6f8;实现多线程&#x1f339;效果&#x1f50e;原因 &#x1f354;使用QtDesigner进行设计 对应的代码btn.ui <?xml version"1.0" encoding"UTF-8"?> <ui version"4.0">&l…