【C语言】C语言期末突击/考研--指针(一篇就够)

news2024/9/23 11:26:58

目录

一、指针的本质(间接访问原理)

1.1.指针的定义

1.2.取地址操作符与取值操作符,指针本质

二、指针的传递使用场景 

2.1.什么是指针的传递

2.2.指针的传递使用场景

三、指针的偏移使用场景

3.1.指针的偏移

3.2.指针与一维数组

四、指针与malloc动态内存申请,栈与堆的差异

4.1.指针与动态内存申请

4.2.栈空间与堆空间的差异

五、练习题

1.1~1.2

2.1~2.2

3.1~3.2

4.1~4.2


一、指针的本质(间接访问原理)

1.1.指针的定义

    内存区域中的每字节都对应一个编号,这个编号就是“地址”。如果在程序中定义了一个变量,那么在对程序进行编译时,系统就会给这个变量分配内存单元.按变量地址存取变量值的方式称为“直接访问",如printf("%d",i);、scanf("%d",&i);等; 另一种存取变量值的方式称为“间接访问”,即将变量i的地址存放到另一个变量中。在C语言中,指针变量是一种特殊的变量,它用来存放变量地址。
指针变量的定义格式如下:

基类型*指针变量名;

例如:

int *i pointer;

    指针与指针变量是两个概念,一个变量的地址称为该变量的“指针”。例如,地址2000是变量i的指针。如果有一个变量专门用来存放另一变量的地址(即指针),那么称它为“ 指针变量"。例如,下图中的i_ pointer就是-一个指针变量:

    那么i_pointer本身占多大的内存空间呢?本文中编写的程序都是64位应用程序,寻址范围为64位即8字节,所以对于本文来说sizeof(i_ pointer)=8.。如果编写的程序是32位,那么寻址范围图指针变量就是4字节(考研中往往会强调程序是32位的程序)。

1.2.取地址操作符与取值操作符,指针本质

    取地址操作符为&,也称引用,通过该操作符我们可以获取一个变量的地址值;取值操作符为*,也称解引用,通过该操作符我们可以得到一个地址对应的数据。如下例所示,我们通过&i获取整型变量i的地址值,然后对整型指针变量p进行初始化,p中存储的是整型变量i的地址值,所以通*p(printf 函数中的*p)就可以获取整型变量i的值。p中存储的是一个绝对地址值,那为什么取值时会获取4字节大小的空间呢?这是因为p为整型变量指针,每个int型数据占用4字节大小的空间,所以p在解引用时会访问4字节大小的空间,同时以整型值对内存进行解析。
【例】取地址与取值(引用与解引用)

#include <stdio.h>
//&符号是取地址,指针变量的初始化一定 是某个变量取地址
int main(){
    int i= 5;
    int* p=&i;
    printf("i=%d\n",i);//直接访问
    printf("*p=%d\n", *p);//间接访问
    return 0;
}

读者需要注意以下4点:
(1)指针变量前面的“*”表示该变量为指针型变量。例如:

float *pointer_1;

注意指针变量名是pointer_1,而不是*pointer_1。
(2)在定义指针变量时必须指定其类型。需要注意的是,只有整型变量的地址才能放到指向整型变量的指针变量中。例如,下 面的赋值是错误的:

float a;
int *pointer_1;
pointer_1=&a; //毫 无意义而且会出错,有兴趣的读者可以自行尝试

(3)如果已执行了语句

pointer_ 1=&a;

那么&* pointer_1的含义是什么呢?
“&”和“*”两个运算符的优先级别相同,但要按自右向左的方向结合。因此, &* pointer_1与&a相同,都表示变量a的地址,也就是pointer_1。
*&a的含义是什么呢?
首先进行&a运算,得到a的地址,再进行*运算。*&a 和*pointer_1的作用是一样的,它们都等价于变量a,即*&a 与a等价。
(4) C语言本质上是一种自由形式的语言,这很容易诱使我们把“*”写在靠近类型的一侧,如int*a这个声明与前面一个声明具有相同的意思,而看上去更清晰,a被声明成类型为int*的指针。但是,这并不是一个好习惯,因为类似int *a,b,c 的语句会使人们很自然地认为这条语句把所有三个变量声明为指向整型的指针,但事实上并非如此,“*” 实际上是*a的一部分,只对a标识符起作用,但其余两个变量只是普通的整型变量.要声明三个指针变量,正确的语句如下:

int *a,*b,*c;

二、指针的传递使用场景 

2.1.什么是指针的传递

    很多初学者不喜欢使用指针,觉得使用指针容易出错,其实这只是因为没有掌握指针的使用场景.经过多年的实战经验总结,指针的使用场景通常只有两个,即传递与偏移,读者应时刻记住只有在这两种场景下使用指针,才能准确地使用指针。多加练习之后,我们会发现指针其实很简单。

2.2.指针的传递使用场景

    我们首先来看本例的主函数中,定义了整型变量i,其值初始化为10,然后通过子函数修改整型变量i的值。但是,我们发现执行语句printf("after change i=%d\n" ,i);后,打印的i的值仍为10,子函数change并未改变变量i的值.下面我们通过执行程序来查看为什么会出现这种情况.
【例】指针的传递使用场景:

#include <stdio.h>

void change(int j){
    j=5;
}
int main() {
    int i = 10;
    printf("before change i=%d\n", i);//这里打断点
    change(i);//在这一步按下箭头,进入change函数
    printf("after change i=%d\n", i);
    return 0;
}

    上例中代码提示位置打断点,然后调试程序,在内存视图中输人&i,可以看到变量i的地址是 0x61fe1c。按向下键(或 F7)进入change函数,这时变量j的值的确为10,但是&j 的值为0x61fdf0,也就是j和i的地址并不相同。运行j=5后, change函数实际修改的是地址0x61fdf0上的值,从10变成了5,接着change函数执行结束,变量i的值肯定不会发生改变,因为变量i的地址是0x61fe1c而非0x61fdf0(由于程序每次重新编译,因此大家那里的地址和我这里是不一样的,这个没关系,关键是观察i和j的地址不一样)。
上例的原理图如下图所示。程序的执行过程其实就是内存的变化过程,我们需要关注的是栈空间的变化。当main函数开始执行时,系统会为main函数开辟函数栈空间,当程序走到int i时,main 函数的栈空间就会为变量i分配4字节大小的空间。调用change函数时,系统会为change函数重新分配新的函数栈空间,并为形参变量j分配4字节大小的空间。在调用change(i)时,实际上是将i的值赋值给j,我们把这种效果称为值传递(C语言的函数调用均为值传递)。因此,当我们在change函数的函数栈空间内修改变量j的值后,change 函数执行结束,其栈空间就会释放,j 就不再存在,i 的值不会改变。

    有的读者会想,难道就不能在子函数中修改main函数内的某个变量的值?答案是可以的,我们将程序进行了如下例所示的修改。
【例】在子函数中修改main函数中某个变量的值:

#include <stdio.h>
void change(int* j)
{
    *j=5; //间接访问得到变量 i
}
//指针的传递
int main(){
    int i=10;
    printf("before change i=%d\n",i);
    change(&i); //传递变量i的地址
    printf("after change i=%d\n",i);
return 0;
}

    我们可以看到程序执行后,语句printf("after change i=%d\n",i);打印的i的值为5,难道C语言函数调用值传递的原理变了?并非如此,我们将变量i的地址传递给change函数时,实际效果是j=&i,依然是值传递,只是这时我们的j是一个指针变量,内部存储的是变量i的地址,所以通过*j就间接访问到了与变量i相同的区域,通过*j=5就实现了对变量i的值的改变。通过单步调试,我们依然可以看到变量j自身的地址是与变量i的地址依然不相等。

三、指针的偏移使用场景

3.1.指针的偏移

    上面介绍了指针的传递。指针即地址,就像我们找到了一栋楼,这栋楼的楼号是B,那么往前就是A,往后就是C,所以应用指针的另-一个场景就是对其进行加减,但对指针进行乘除是没有意义的,就像家庭地址乘以5没有意义那样.在工作中,我们把对指针的加减称为指针的偏移,加就是向后偏移,减就是向前偏移。下面我们来看下面的例子。
【例】指针的偏移使用场景:

#include <stdio.h>
#define N 5
//指针的偏移
int main() {
    int a[N] = {1, 2, 3, 4, 5};
    int *p;
    int i;
    p = a; //保证等号两边的数值类型一致
    for (i = 0; i < N; i++) //正序输出
    {
        printf("%3d", *(p + i));
    }
    printf("\n---------------\n");
    p = &a[4]; //让 p指向最后一一个元素
    for (i = 0; i < N; i++) //逆序输出
    {
        printf(" %3d", *(p - i));
        printf("\n");
        return 0;
    }
}

     如下图所示,数组名中存储着数组的起始地址0x61fdf0,其类型为整型指针,所以可以将其赋值给整型指针变量p,可以从监视窗口中看到p+1的值为0x61fdf4.那么为什么加1后不是0x61fdf1呢?因为指针变量加1后,偏移的长度是其基类型的长度,也就是偏移sizeof(int),这样通过*(p+1)就可以得到元素a[1]。编译器在编译时,数组取下标的操作正是转换为指针偏移来完成。

3.2.指针与一维数组

    为什么一维数组在函数调用进行传递时,它的长度子函数无法知道呢?这是由于一维数组名中存储的是数组的首地址。如下例所示,数组名c中存储是一个起始地址,所以子函数change中其实传入了一个地址。定义一个指针变量时,指针变量的类型要和数组的数据类型保持一致,通过取值操作,就可将“h”改为“H”, 这种方法称为指针法。获取数组元素时,也可以通过取下标的方式来获取数组元素并进行修改,这种方法称为下标法。
【例】数组传递给子函数的实战练习

#include <stdio.h>
//数组名作为实参传递给子函数时,是弱化为指针的
//练习传递与偏移
void change(char *d){
    *d='H';
    d[1]= 'E';
    *(d +2)='L';
}
int main(){
    char c[10]= "hello";
    change(c);
    puts(c);
    return 0;
}
  

四、指针与malloc动态内存申请,栈与堆的差异

4.1.指针与动态内存申请

    很多读者在学习C语言的数组后都会觉得数组长度固定很不方便,其实C语言的数组长度
固定是因为其定义的整型、浮点型、字符型变量.数组变量都在栈空间中,而栈空间的大小在编
译时是确定的,如果使用的空间大小不确定,那么就要使用堆空间.请看下面例子
【例】动态内存申请:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
    int i;
    char *p;
    scanf("%d",&i); //输入要申请的空间大小
    p=(char*)malloc(i); //使用malloc动态申请堆空间
    strcpy(p,"malloc success");
    puts(p);
    free(p); //free时必须使用malloc申请时返回的指针值,不能进行任何偏移
    printf("free success\n");
    return 0;
}

    首先我们来看malloc函数。在执行#include <stdlib.h>   void *malloc(size_t  size);时,需要给malloc传递的参数是一个整型变量,因为这里的size _t 即为int;返回值为void*类型的指针, void*类型的指针只能用来存储一个地址而不能进行偏移,因为malloc并不知道我们申请的空间用来存放什么类型的数据,所以确定要用来存储什么类型的数据后,都会将void*强制转换为对应的类型。在例1.1中我们用来存储字符,所以将其强制转换为char*类型。同时需要注意指针本身大小,和其指向的空间大小,是两码事,不能和前面的变量类比去理解!
如下图所示,定义的整型变量i。指针变量p均在main函数的栈空间中,通过malloc申请的空间会返回一个堆空间的首地址,我们把首地址存人变量p。知道了首地址,就可以通过strcpy函数往对应的空间存储字符数据。

    既然都是内存空间,为什么还要分栈空间和堆空间呢?栈是计算机系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈操作、出栈操作都有专门的指令执行,这就决定了栈的效率比较高;堆则是C/C++函数库提供的数据结构,它的机制很复杂,例如为了分配一块内存,库函数会按照一定的算法(具体的算法请参考关于数据结构、操作系统的书籍)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能由于内存碎片太多),那么就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后返回.显然,堆的效率要比栈低得多。 (这段了解即可)
栈空间由系统自动管理,而堆空间的申请和释放需要自行管理,所以在具体例子中需要通过free函数释放堆空间. free 函数的头文件及格式为:

#include <stdlib.h>
void free(void *ptr);

    其传入的参数为void类型指针,任何指针均可自动转为void*类型指针,所以我们把p传递给free函数时,不需要强制类型转换. p的地址值必须是malloc当时返回的地址值,不能进行偏移,也就是在malloc和free之间不能进行p=p+1等改变变量p的操作,原因是申请一段堆内存空间时,内核帮我们记录的是起始地址和大小,所以释放时内核用对应的首地址进行匹配,匹配不上时,进程就会崩溃。如果要偏移进而存储数据,那么可以定义两个指针变量来解决。接下来我们来试试先偏移p再执行free,看看程序崩溃的效果。

下面我们来了解栈空间和堆空间在时间有效性上的差异。

4.2.栈空间与堆空间的差异

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//函数栈空间释放后,函数内的所 有局部变量消失
char* print_stack()
{
    char c[17]="I am print_stack";
    puts(c);
    return c;
}
//堆空间不会因函数执行结束而释放
char* print_malloc()
{
    char *p;
    p=(char*)malloc(20);
    strcpy(p,"I am print_malloc");
    puts(p);
    return p;
}

int main()
{
    char *p;
    p=print_stack(); //数据放在栈 空间
    printf("p=%s\n",p);
    p=print_malloc(); //数据放在堆 空间
    puts(p);
    return 0;
}

    如上例中代码的执行结果如下图所示。为什么第二次打印会有异常?原因是print_stack()函数中的字符串存放在栈空间中,函数执行结束后,栈空间会被释放,字符数组c的原有空间。已被分配给其他函数使用,因此在调用print_ stack()函 数后, printf("p=%s\n" ,p);中的p不能获取栈空间的数据。而print_ malloc()函数中的字符串存放在堆空间中,堆空间只有在执行free操作后才会释放,否则在进程执行过程中会一直有效.

五、练习题

1.1~1.2

1、prit("%d",);. scanf("%d" ,&i);是直接访问
A正确B错误
答案: A
解释:直接访问是指我们通过变量名访问变量值,或者直接拿到变量的地址空间进行访问
2、int i= 5;int* p=&i;print("*p= -%dn", *p);这样去访问i的值的方式是间接访问
A正确B错误
答案: A
解释:我们先获取指针变量p的值,*p 相当于通过p内部所存的地址值,对所在地址进行
取值操作,因此*p 是间接访问
3、“&”和“*”两个运算符的优先级别相同,但要按自右向左的方向结合,&是取值,*
是取地址
A正确B错误
答案: B
解释:“&” 和“*”两个运算符的优先级别相同是正确的,但是&是取地址,*代表取值,
这两个的意义一定要记清楚
4、int*a,b,c定义了 3个整型指针变量,分别是a,b,c .
A正确B错误
答案: B
解释: a是指针变量, b和c是整型变量,如果要定义3个指针变量,方法是int *a,*b,*c; .
5、int a;如果我们编写*&a这样的表达式没有意义,因为其与a等价的
A正确B错误
答案: A
解释: *也就是取值运算符,和&也就是取地址运算符,优先级别相同自右向左的方向结合,
因此*&a这样的表达式没有意义,与a等价

2.1~2.2

1、main函数和change函数有各自的函数栈空间
        A正确        B错误
答案: A
解释:不同的函数有自己独有的栈空间


2、函数调用是值传递,将实参的值传递给形参
        A正确        B错误
答案: A
解释:这个非常重要,需要记住、因为理解这个, 才能明白我们视频中的代码实例的原理,同时研究生复试时,导师可能提问函数调用的原理


3、虽然函数调用是值传递,但是我们可以通过指针间接访问的原理,来实现子函数中改变
main函数中某个变量的值
        A正确        B错误
答案: A
解释:我们将变量i的地址传递给change函数时,实际效果是j=&i,依然是值传递,只是这时我们的j是一个指针变量,内部存储的是变量i的地址,所以通过*j就间接访问到了与变量i相同的区域,通过*j=5就实现了对变量i的值的改变

3.1~3.2

1、指针做加碱就是指指针的偏移
        A正确        B错误
答案: A
解释:指针是一个地址,我们会对其做加减运算


2、我们会对指针变量进行乘除,得到一个新地址,来使用
        A正确        B错误
答案: B
解释:指针变量存储的是一个内存地址,我们只会对其做加减操作,访问其后面,或者前面空间的内容,不会对其做乘除操作


3、int a[N]={1,2,3,4,5};int *p;p a;对于这个操作,我们如果进行p: p+1, p的值增大了一个字节
        A正确        B错误
答案: B
解释:对于指针变量做加法运算时,每次加1,增加的长度是其基类型的长度,因为基类型是int,
所以p的值增大了4个字节。

4、数组名传递给子函数时,是弱化为指针的
        A正确        B错误
答案: A
解释:C语言的子函数形参位置,并没有数组变量的设计,我们]把数组名实参传递给子函数时,形参接收到的是数组名内存储的数组的起始地址

4.1~4.2

1、p=(char* )malloc(20);代表在堆空间上,申请20个字节,由于malloc返回的是void*类型指针,我们要往内部存储字符串,所以强转为char*
        A正确        B错误
答案: A
解释: malloc 是盱申请堆内存空间的,非常重要,一定要掌握, 我们给malloc 传递的值为多大,就是申请多少字节


2、malloc 申请的空间,如果我们不使用时,-定要free,否则会一直占用内存空间,直到进程结束
        A正确        B错误
答案: A
解释:这个需要记住,因为在中级阶段,数据结构部分,我们不用的空间一定要free,避免
初试扣分


3、子函数结束后,其栈空间会被释放
        A正确        B错误
答案:A
解释: 函数执行结束后,其函数栈空间会被全部释放

下一期:

【C语言】C语言期末突击/考研--函数

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

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

相关文章

风景视频素材高清无水印的网站有哪些?6个热门素材网站分享

高清无水印风景视频素材网站推荐&#xff0c;让您的视频内容独树一帜&#xff01; 对于视频创作者来说&#xff0c;一段引人入胜的风景视频素材往往能够瞬间抓住观众的注意力&#xff0c;仿佛将他们带入了一个全新的世界。然而&#xff0c;很多创作者在实际拍摄过程中会面临时…

(二)springboot2.7.6集成activit5.23.0之集成设计器

引入官方流程设计器 1. activiti-webapp-explorer2-5.23.0.war项目并解压。 2.将文件夹diagram-viewer和editor-app以及modeler.html拷贝到项目resources/static目录下&#xff1a; 顺便说一下&#xff1a; 在Spring Boot中&#xff0c;静态资源的访问顺序是先找static&#…

QT 安装指南

简介 Qt 是一个跨平台的应用程序开发框架&#xff0c;被广泛应用于桌面、移动设备和嵌入式系统等领域。本文将详细介绍如何在 Windows 操作系统上安装 Qt 5.14.2 版本(这个版本较为稳定适用)。 安装前准备 操作系统: 确保您的计算机运行的是 Windows 10 或更高版本。硬件要求…

【数据结构初阶】二叉树与堆(一)

文章目录 一、树的基础概念1、节点与度数2、树的度与高度3、引入&#xff1a;数组下标为何从0开始4、祖先节点5、树是递归定义的6、树与非树的区别7、代码表示 二、二叉树2.1、满二叉树2.2、完全二叉树2.3、完全二叉树的存储 三、堆 一、树的基础概念 1、节点与度数 节点分为…

app逆向实战之定位关键代码

前言 在保证App能够正常使用的前提下&#xff0c;我们可以通过抓包查看是否存在抓包检测。如果可以进行抓包&#xff0c;我们首先进行登录代码定位&#xff0c;并伪造请求进行登录&#xff0c;然后实现App中的某个功能。本文以某嘟牛app为例&#xff0c;抓包结果如下&#xff…

【投标】运维服务方案(2024Word完整版)

1.项目情况 2.服务简述 2.1服务内容 2.2服务方式 2.3服务要求 2.4服务流程 2.5工作流程 2.6业务关系 2.7培训 3.资源提供 3.1项目组成员 3.2服务保障 软件资料清单列表部分文档&#xff1a; 工作安排任务书&#xff0c;可行性分析报告&#xff0c;立项申请审批表&a…

vue后台管理系统 vue3+vite+pinia+elementui+axios下

这篇文章来完成用户组件 也就是增删改查表格 用户页面信息页面由头部&#xff0c;表格,和弹框组成 <template><div class"user-header"><el-button type"primary" click"handleAdd">新增</el-button><el-form :inl…

(2024,LlamaGen,Llama,自回归下一token预测,模型扩展)自回归模型优于扩散:Llama 用于可扩展图像生成

Autoregressive Model Beats Diffusion: Llama for Scalable Image Generation 目录 0. 摘要 1. 引言 2. 自回归模型在图像生成中的应用 2.1 概述 2.2 图像 tokenizer 2.3 自回归模型生成图像 2.4 规模扩展 2.5 服务 3. 实验 5. 结论 0. 摘要 我们介绍 LlamaGen&…

使用mid360从0开始搭建实物机器人入门级导航系统,基于Fast_Lio,Move_Base

Introduction 本文原本只是自己在拿到mid360后&#xff0c;开始进行开发过程的一些问题和学习的记录。毕竟实物和仿真还是有很多不同&#xff0c;且由于碰到的问题也比较多&#xff0c;READEME也越来越详细&#xff0c;所以就干脆整合起来&#xff0c;做成了一篇使用mid360的搭…

嵌入式初学-C语言-十一

#接嵌入式初学-C语言-十,以及部分例题# 循环结构 break和continue break 功能&#xff1a; 1. 用在switch中&#xff0c;用来跳出switch的case语句&#xff1b;如果case没有break&#xff0c;可能会产生case穿透。 2. 用在循环中&#xff08;while、do..while、for..&#…

Linux压缩/解压缩工具:tar命令详解

目录 一、概述 二、基本概念 三、tar命令的基本语法 1、基本语法 2、常用选项 3、帮助获取 四、用法和示例 1. 创建归档文件 &#xff08;1&#xff09;用法 &#xff08;2&#xff09;示例 2. 解压缩归档文件 &#xff08;1&#xff09;用法 &#xff08;2&#…

经典非比较排序—计数排序的Java实现方式

目录 1.具体思路&#xff1a; 2.代码实现&#xff1a; 3.代码分析 4.示例测试&#xff1a; 测试源码&#xff1a; 测试结果&#xff1a; 计数排序&#xff0c;又被称为鸽巢原理&#xff0c;属于桶排序的一种&#xff0c;其本质是通过哈希映射思想&#xff0c;设定计数数组输入以…

音视频入门基础:WAV专题(5)——FFmpeg源码中解码WAV Header的实现

音视频入门基础&#xff1a;WAV专题系列文章&#xff1a; 音视频入门基础&#xff1a;WAV专题&#xff08;1&#xff09;——使用FFmpeg命令生成WAV音频文件 音视频入门基础&#xff1a;WAV专题&#xff08;2&#xff09;——WAV格式简介 音视频入门基础&#xff1a;WAV专题…

论文翻译:Large Language Models in Education: Vision and Opportunities

Large Language Models in Education: Vision and Opportunities 文章目录 教育中的大型语言模型&#xff1a;愿景与机遇摘要1 引言2. 教育与LLMsA. 教育背景B. LLMs背景C. 智能教育D. 教育中的LLMs 3. EduLLMs的关键技术4. LLM赋能教育A. LLMs在教育中的应用B. LLMs下教育的特…

免费分享:全国传统村落空间分布数据(附下载方法)

数据简介 本数据是在中国传统村落名录的基础上&#xff0c;通过地理编码&#xff0c;制作成具有空间坐标信息的矢量数据。 数据属性 数据名称&#xff1a;全国传统村落空间分布数据数据时间&#xff1a;2012年至今&#xff0c;更新至第五批空间位置&#xff1a;全国数据格式&…

opencascade AIS_TrihedronOwner源码学习对象的实体所有者用于选择管理

opencascade AIS_TrihedronOwner 前言 AIS_Trihedron对象的实体所有者用于选择管理。 在OpenCascade的AIS&#xff08;交互对象框架&#xff09;中&#xff0c;管理类似AIS_Trihedron的对象的选择涉及理解如何处理实体&#xff08;或所有者&#xff09;以进行选择。 方法 1…

【单片机毕业设计选题24095】-基于手机端的电池电压采集系统

系统功能: 系统上电后&#xff0c;OLED显示三组18650锂电池电压。 第一行显示第一组锂电池电压 第二行显示第二组锂电池电压 第三行显示第三组锂电池电压 第四行显示电压设定阈值 短按B4按键增加电压设定阈值 短按B5按键减小电压设定阈值 如果任意一组电池电压小于电压…

红酒与季节:品味四季的风情

四季轮转&#xff0c;岁月更迭&#xff0c;每个季节都有其不同的韵味与风情。当定制红酒洒派红酒&#xff08;Bold & Generous&#xff09;与四季相遇&#xff0c;它们共同编织出一幅幅美丽的味觉画卷&#xff0c;让我们在品味中感受四季的风情。 一、春之序曲&#xff1a…

【ESP01开发实例】-ESP-01驱动DHT11和DH22传感器

ESP-01驱动DHT11和DH22传感器 文章目录 ESP-01驱动DHT11和DH22传感器1、DHT11/DHT22传感器介绍2、LCD1602介绍3、硬件准备与接线4、代码实现本主题介绍如何使用 DHT11 和 DHT22 相对湿度和温度传感器与 ESP8266 ESP-01 Wi-Fi 模块,将相对湿度和温度的测量值显示在 162 LCD 屏幕…

C++回顾——多态

一、定义 ①从广义上说,多态性是指&#xff1a;一段程序能够处理多种类型对象的能力。在C语言中,这种多态性可以通过包含多态4种形式来实现。强制多态、重载多态、类型参数化多态、包含多态。 ②从实现上来说&#xff0c;多态的分类&#xff1a;静态多态、动态多态。 二、 广…