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

指针的进阶——(1)

本次讲解重点:

1、字符指针

2、数组指针

3、指针数组

4、数组传参和指针传参

5、函数指针

关于指针这个知识点的主题,我们在前面已经初级阶段已经对指针有了大致的理解和应用了。我们知道了指针的概念:

1、指针就是地址,但口语中说的指针通常指的是指针变量,指针变量用来存放地址,地址唯一标识一块内存空间。

2、指针的大小是固定的4/8字节(32位平台/64位平台)。

3、指针是有类型的,指针的类型决定了指针的+-整数的步长,指针解引用操作的时候的权限。

4、指针的运算。

5、二级指针:存放一级指针变量的地址的变量。

        理解:指针变量前的第一个*与变量结合表示它是指针,再往前面所有东西表示这个指针所指向对象的类型。

关于初阶指针有什么不太了解,大家可以点击下方链接学习一遍之后,再来学习进阶。

S6---初阶指针_wangjiushun的博客-CSDN博客

接下来,我们继续探讨指针的高级主题。


1.  字符指针

在指针的类型中我们知道有一种指针类型为字符指针:char*

一般我们使用:让一个字符指针指向一个字符变量

int main()
{char ch = 'a';char* pc = &ch;return 0;
}

还有一种使用方式:让一个字符指针指向一个常量字符串的首字符地址

#include<stdio.h>int main()
{const char* pstr = "abcdef";printf("%s\n", pstr);return 0;
}

代码const char *pstr="abcdef";

很容易让我们误以为是把常量字符串存储到字符指针pstr里了,但是想一想一个字符指针怎么可能放得下7个字节的字符串呢?所以其本质是把字符串abcdef首字符的地址放到了pstr中。

图解:

知识点总结:

1.  常量字符串:

        ①常量字符串不能被修改:用const修饰(如果修改,程序崩溃);

        ②常量字符串出现在表达式中时,这个常量字符串的值是首字符的地址。

2.  const修饰的常变量:变量pstr不能被修改,但是pstr本质上还是一个变量,所以叫常变量

3.  %s-打印字符串,直到遇到'\0'才停止。 

有这么一道面试题:

#include<stdio.h>int main()
{char str1[] = "hello bit";char str2[] = "hello bit";const char* str3 = "hello bit";const char* str4 = "hello bit";if (str1 == str2){printf("str1 and str2 are same\n");}else{printf("str1 and str2 are not same\n");}if (str3 == str4){printf("str3 and str4 are same\n");}else{printf("str3 and str4 are not same\n");}return 0;
}

大家猜猜运行的结果。

运行结果:

为什么会这样了?

知识点:

总结:

(常量字符串,不能被修改)C/C++会把常量字符串存储到单独的一个内存区域,当有几个指针,指向同一个常量字符串的时候,它们实际会指向同一块内存。
但是用相同的常量字符串去初始化不同的数组的时候,就会开辟不同的内存块。

一个变量对应着一个唯一的空间。

图解:

所以str1和str2不同,str3和str4相同。

2.  指针数组

在初阶指针里我们已经学习一次指针数组,指针数组是一个存放指针的数组。

这里,我们在回顾一下:

整形数组-存放整形的数组;

字符数组-存放字符的数组

指针数组-存放指针(地址)的数组

指针数组的使用:使用一维数组模拟二维数组

代码1:存放字符指针的数组

#include<stdio.h>int main()
{//存放字符指针的数组const char* arr[4] = { "abcd","hello","hehe","wang" };//打印int i = 0;for (i = 0; i < 4; i++){printf("%s\n", arr[i]);}return 0;
}

 图解:

代码2:存放整形指针的数组

#include<stdio.h>int main()
{int arr1[4] = { 1,2,3,4 };int arr2[4] = { 2,3,4,5 };int arr3[4] = { 3,4,5,6 };//存放整形指针的数组int* arr[3] = { arr1,arr2,arr3 };//打印int i = 0;for (i = 0; i < 3; i++){int j = 0;for (j = 0; j < 4; j++){printf("%d ", *(arr[i] + j));//等价于arr[i][j]}printf("\n");}return 0;
}

图解:

总结:这就是和二维数组一样的,只不过我们是使用指针数组来模拟的。

 3.  数组指针

3.1  数组指针的定义

数组指针是指针?还是数组?

答案是:指针。

我们已经熟悉:

整形指针-存放整形地址的指针-指向整形的指针 int*

字符指针-存放字符(字符串)地址的指针-指向字符(字符串)的指针 char*

那数组指针是:存放数组地址的指针-指向数组的指针

代码实例:

int main()
{//整形指针int a = 10;int* pi = &a;//字符指针char ch = 'w';char* pc = &ch;//数组指针int arr[10] = { 0 };//int* pa[10]是这样的吗,但是这不是指针数组,//pa先与[]结合了就是数组,int(*pa)[10] = &arr;return 0;
}

对数组指针的理解:pa先和*结合,说明pa是一个指针变量,然后指向的是一个大小为10个整形的数组。(即pa是一个指针,指向一个数组的指针,叫做数组指针)

数组指针后面的[]表示所指向的数组有几个元素

知识点:

注意:[]的优先级要高于*的,所以必须加上()来保证pa先和*结合。

指针变量前的第一个*与变量结合表示它是指针,再往前面所有的东西表示这个指针所指向对象的类型。

接下来,我们深入了解数组名和&数组名

3.2  &数组名VS数组名

代码1:打印&数组名和数组名的地址观察

#include<stdio.h>int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };//打印数组名地址printf(" arr-->%p\n", arr);//打印&数组名地址printf("&arr-->%p\n", &arr);return 0;
}

 运行结果:

运行之后我们发现:&数组名和数组名的地址是一样的。

难道两个是一样的吗?

代码2:&数组名和数组名+1

//代码2:
//数组名-数组首元素的地址
// &数组名-是数组的地址
// 数组首元素的地址和数组的地址从值的角度来看是一样的,但是意义不一样
// 指针的类型决定了指针+-整数的步长,指针解引用操作的时候的权限
//#include<stdio.h>int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };printf(" arr---->%p\n", arr);//指针的类型:int*printf(" arr+1-->%p\n", arr + 1);//+1,向后跳4个字节printf("&arr---->%p\n", &arr);//指针的类型:int(*)[10]printf("&arr+1-->%p\n", &arr + 1);//+1,向后跳40个字节return 0;
}

 运行结果:

图解:

根据上面的代码,我们发现:

数组名-数组首元素的地址

&数组名-是数组的地址 

 数组首元素的地址和数组的地址从值的角度来看是一样的,但是意义不一样。

知识点:

1.  指针的类型决定了指针+-整数的步长,指针解引用操作的时候的权限。

2.  存储一个数组所需的内存字节数:

        ①一维数组:总字节数=sizeof(类型)*元素个数

        ②二维数组:总字节数=sizeof(类型)*行数*列数

3、对二维数组数组名的加深理解:数组名就是二维数组首元素的地址

        对于二维数组来说,它的第一行就是它的第一个元素,第二行就是它的第二个元素……即一行是一个元素,二维数组是一个一维数组的数组。

//代码:二维数组的数组名
//二维数组的数组名是首元素地址-->第一行的地址
// 对于二维数组一行是一个元素#include<stdio.h>int main()
{int arr[3][4] = { 0 };printf("%p\n", arr);printf("%p\n", arr + 1);//跳过了16个字节return 0;
}

运行结果:

上机运行实践,也正是如此:arr+1跳40个字节,刚好是一行。

注意区分:二维数组的第一行第一个元素地址是&arr[0][0],

3.3  数组指针的使用

代码1:一维数组数组指针的使用,但是我们很少这样写代码

//代码1:一维数组数组指针的使用,但是我们很少这样写代码#include<stdio.h>int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };//数组指针int(*p)[10] = &arr;//打印数组int i = 0;for (i = 0; i < 10; i++){printf("%d ", (*p)[i]);//*p[i]这种写法的话,p先与[i]结合再解引用}return 0;
}

 代码2:二维数组数组指针的使用

#include<stdio.h>void print1(int arr[3][4], int r, int c)
{int i = 0;for (i = 0; i < r; i++){int j = 0;for (j = 0; j < c; j++){printf("%d ", arr[i][j]);}printf("\n");}
}void print2(int(*p)[4], int r, int c)
{int i = 0;for (i = 0; i < r; i++){int j = 0;for (j = 0; j < c; j++){printf("%d ", *(*(p + i) + j));//等价于(*(p+i))[j],也等价p[i][j]}printf("\n");}
}int main()
{int arr[3][4] = { {1,2,3,4},{2,3,4,5},{3,4,5,6} };//调用函数打印数组print1(arr, 3, 4);print2(arr, 3, 4);return 0;
}

图解:

 学了指针数组和数组指针我们一起回顾并看看下面代码的意思:

int arr[5];

int *parr1[10];

int (*parr2)[10];

int (*parr3[10])[5];

 4.  数组参数、指针参数

我们写代码的时候难免要把数组或者指针传给函数,那么函数的参数该如何设计呢?

4.1  一维数组传参

void test(int arr[])//ok?
{}
void test(int arr[10])//ok?
{}
void test(int* arr)//ok?
{}
void test2(int* arr[20])//ok?
{}

void test2(int* arr[])//ok?

{}
void test2(int** arr)//ok?
{}
int main()
{
    int arr[10] = { 0 };
    int* arr2[20] = { 0 };
    test(arr);
    test2(arr2);
}

 4.2  二维数组传参

void test(int arr[3][5])//ok?
{}
void test(int arr[][])//ok?
{}
void test(int arr[][5])//ok?
{}
void test(int* arr)//ok?
{}
void test(int* arr[5])//ok?
{}
void test(int(*arr)[5])//ok?
{}
void test(int** arr)//ok?
{}
int main()
{
    int arr[3][5] = { 0 };
    test(arr);
}

4.3  一级指针传参

思考:当一个函数的参数部分为一级指针的时候,函数能接收什么参数?

答案是:①一级指针变量;②一维数组数组名;③变量地址。

比如:

void test1(int *p)
{}
//test1函数能接收什么参数?
void test2(char* p)
{}
//test2函数能接收什么参数?

void test1(int* p)
{}void test2(char* p)
{}int main()
{//test1函数能接收什么参数?int a = 10;int* pi = &a;int arr[5] = { 0 };test1(pi);//一级指针变量test1(arr);//一位数组数组名test1(&a);//变量地址//test2函数能接收什么参数?char ch = 'w';char* pc = &ch;char arr1[6] = { '\0' };test2(pc);test2(arr1);test2(&ch);return 0;
}

4.4  二级指针传参

思考:当函数的参数为二级指针的时候,函数能接收什么参数?

答案是:①二级指针变量;②指针数组数组名;③一级指针变量地址。

代码实例:

void test(char** p)
{ }
int main()
{char c = 'b';char* pc = &c;char** ppc = &pc;char* arr[10];test(&pc);//一级指针变量地址test(ppc);//二级指针变量test(arr);//指针数组数组名return 0;
}

5、函数指针

我们先打印一下函数的地址

#include<stdio.h>int Add(int x, int y)
{return x + y;
}int main()
{//打印函数地址printf("%p\n", &Add);printf("%p\n", Add);return 0;
}

运行结果:

从结果我们发现:取函数名和函数名,打印的地址一样。

结论:①取函数名和函数名,都是函数的地址。

那函数的地址是怎么保存的呢?

看下面代码:

#include<stdio.h>int Add(int x, int y)
{return x + y;
}int main()
{//数组指针-指向数组的指针int arr[10] = { 0 };int(*pa)[10] = &arr;//函数指针-指向函数的指针int (*pf)(int, int) = &Add;//pf 是一个存放函数地址的指针变量-函数指针int ret1 = pf(2, 3);//pf是函数地址,Add也是函数地址,所以不用解引用也可以int ret2 = (*pf)(2, 3);//写上*也可以,符合语法,但是需注意带()printf("%d %d\n", ret1, ret2);return 0;
}

类比数组指针,函数指针也是如此要注意带()保证*和变量pf先结合。

使用函数指针找到所指向的函数:

①直接写函数指针:因为函数指针变量存储的就是函数的地址,所以在使用的时候可以不解引用。

②函数指针解引用:解引用其实没必要,这样写就是方便理解。因为pf是指针,指针要找到他所指向的对象(对象函数名就是函数的地址),解引用更容易理解,符合语法的理解。(注意:优先级缘故,如果要解引用,一定要使用()把*和函数指针变量括起来。)

现在我们来看两段有趣的代码:

//代码1
(*(void (*)())0)();
//代码2
void (*signal(int , void(*)(int)))(int);

代码1的解读:

int main()
{( *( void(*)() ) 0 )();//分析:// ①void(*)()-->函数指针类型,这个函数是无参的// ②()里面放类型-->强制类型转换// ③( void(*)() ) 0 -->把0强转成这种函数指针类型,// 就是0被当成了函数的地址// ④(*指针变量)-->解引用操作,找到0地址的函数// ⑤最后的()-->调用函数不用传参(因为强转的0函数类型是无参的)////总结:该代码是一次函数调用,调用0地址处的一个函数//		首先代码中将0强转为类型为( void(*)() )的函数指针//      然后去调用0地址处的函数return 0;
}

破题点:从0出发,再开始分析。

代码2的解读:

//函数返回类型是函数指针int main()
{void (*signal(int, void(*)(int))) (int);//分析:①signal没有与*结合,这不是指针//		②signal后有括号()-->signal是函数名//		③函数名括号()里-->函数参数//		第一个参数是int类型,第二个参数是函数指针类型//		④语句最后有;没有函数体-->函数是声明//		⑤函数的声明-->形式:函数返回类型 函数名 (形参列表);//		那剩下的void(*)(int)就是函数返回类型了//		//总结:该代码是一次函数的声明//		声明的函数名字叫signal//		signal函数的参数有2个,第一个是int类型,第二个是函数指针类型,//		该函数指针能够指向的那个函数的参数是int,返回类型是void。//		signal函数的返回类型是一个函数指针,//		该函数指针能够指向的那个函数的参数是int,返回类型是void。//我们能不能这么写?//void(*)(int) signal(int,void(*)(int));//答案是不能这么写,帮助理解可以这么写,但是语法上是错的//函数的返回类型是函数指针是,只能把函数名 (形参列表)移到*的后面。//优化:类型简化--->typedef//函数指针的重命名typedef void(*pf_t)(int);pf_t signal(int, pf_t);return 0;
}

破题点:从signal出发,再开始分析。

知识点:

1、函数返回类型是指针函数时的写法:当函数的返回类型是函数指针时,只能把函数名 (参数列表)移到返回类型这个函数指针的*的后面。

2、指针类型简化(重命名)--->typedef

        指针类型重命名,别名写在*的后面并且还要注意操作符的优先级(即*先与别名结合)

本次知识点总结:

1.  字符指针的两种使用:

        (1)一般使用:让字符指针指向一个字符变量(字符数组),可通过解引用来访问这个字符变量(字符数组)。

        (2)还有一种使用方式:让字符指针指向一个常量字符串的首字符地址。

加油站:

        (1)常量字符串:①常量字符串不能被修改:用const修饰;②常量字符串出现在表达式中时,这个常量字符串的值是首字符的地址。

        (2)const修饰的常变量:不能被修改。

        (3)(常量字符串,不能被修改)C/C++会把常量字符串存储到单独的一个内存区域,当有几个指针,指向同一个常量字符串的时候,他们实际会指向同一块内存。

        (4)但是用相同的常量字符串去初始化不同的数组的时候,就会开辟不同的内存块。

        (5)一个变量对应着一个唯一的空间。

2.  指针数组

指针数组-存放指针(地址)的数组

回顾数组的创建方式:

        type_t  arr_name  [const_n];

        //type_t:是数组的元素类型

        //arr_name:数组名

        //const_n:常量表达式,用来表示数组中元素个数,即数组的大小(长度)

指针数组的使用:一般是使用一维数组模拟二维数组

3.  数组指针

3.1  数组指针的定义

        数组指针-存放数组地址的指针-指向数组的指针

        如:int arr[10];

               int (*parr)[10]=&arr;//数组指针

对数组指针的理解:

        parr先和*结合,说明是一个指针,前面的int是所指向数组的类型,后面的[]是所指向数组的大小。

        注意:[]的优先级要高于*的,所以必须加上()来保证变量先和*结合。

        指针变量前的第一个*与变量结合表示它是指针,再往前所有的东西表示这个指针所指向对象的类型。

3.2  &数组名和数组名

        数组名-数组首元素的地址

        &数组名-数组的地址

        数组首元素的地址和数组的地址从值的角度来看是一样的,但是意义不一样。

加油站:

        (1)指针的类型决定了指针+-整数的步长,指针解引用操作的时候的权限。

        (2)存储一个数组所需的内存字节数:

                ①一维数组:总字节数=sizeof(类型)*元素个数

                ②二维数组:总字节数=sizeof(类型)*行数*列数

        (3)对二维数组数组名的加深理解:

                数组名是数组首元素的地址,首元素即第一行的地址;

                对于二维数组来说可以看成:一行一个元素(即一维数组),二维数组是一个一维数组的数组

3.3  数组指针的使用-二维数组数组名做实参

4.  数组参数、指针参数

4.1  数组传参

        数组名作函数实参,地址传递

        形参可写为:

        (1)数组形式(注意类型一致,若要标注数组大小:数组大小一致)

                ①一维数组的大小可省略

                ②二维数组的大小:只能省略第一维[]的大小,第二维[]的不可省略。因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素(列),这样才方便计算。

        (2)指针形式

4.2  一级指针传参

        思考:当函数的参数为一级指针的时候,函数能接收什么参数?

        答案是:①一级指针变量;②一维数组数组名;③变量地址

4.3二级指针传参

        思考:当函数的参数为二级指针的时候,函数能接收什么参数?

        答案是:①二级指针变量;②数组指针数组名;③一级指针变量地址

5.函数指针

        结论:取函数名和函数名,都是函数的地址。

(1)函数指针怎么写?

        类比数组指针,函数指针也是要注意操作符的优先级,所以要带()保证*先和变量结合

(2)对函数指针的理解:变量先与*结合,说明变量是一个指针;然后前面的是所指向函数的返回类型,后面的()是所指向函数的参数列表。

(3)使用函数指针找到所指向的函数:

        ①直接写函数指针:因为函数指针变量存储的就是函数的地址(函数名也是函数的地址),所以在使用的时候可以不解引用。

        ②函数指针解引用:解引用其实是没必要的,这样写就是方便理解。因为变量是指针,指针要找到它所指向的对象(对象函数名就是函数的地址),解引用更容易理解,符合语法的理解。(注意:优先级缘故,如果要解引用,一定要使用()把*和指针变量括起来。)

加油站:

        ①函数返回类型是函数指针时的写法:当函数的返回类型是函数指针时,只能把函数名和(参数列表)移到返回类型这个函数指针的*的后面。

        ②指针类型简化--->typedef

        指针类型重命名,别名写在*的后面并且还要注意操作符的优先级(即*先和别名结合)。

指针进阶的主题并未结束,在下一次文章终结。

有什么不足希望大家指出,我会更加努力写出更好的文章。

相关文章:

指针的进阶——(1)

本次讲解重点&#xff1a; 1、字符指针 2、数组指针 3、指针数组 4、数组传参和指针传参 5、函数指针 关于指针这个知识点的主题&#xff0c;我们在前面已经初级阶段已经对指针有了大致的理解和应用了。我们知道了指针的概念&#xff1a; 1、指针就是地址&#xff0c;但口…...

电商平台的促销活动如何抵御大流量的ddos攻击

每一次活动大促带来的迅猛流量&#xff0c;对技术人而言都是一次严峻考验。如果在活动期间遭受黑产恶意 DDoS 攻击&#xff0c;无疑是雪上加霜。电商的特性是业务常态下通常不会遭受大流量 DDoS 攻击&#xff0c;且对延迟敏感&#xff0c;因此只需要在活动期间按需使用 DDoS 防…...

代码随想录-48-104. 二叉树的最大深度

目录前言题目1.层序迭代思路2. 本题思路分析&#xff1a;3. 算法实现4. pop函数的算法复杂度5. 算法坑点前言 在本科毕设结束后&#xff0c;我开始刷卡哥的“代码随想录”&#xff0c;每天一节。自己的总结笔记均会放在“算法刷题-代码随想录”该专栏下。 代码随想录此题链接 …...

【Vue3源码】第六章 computed的实现

【Vue3源码】第六章 computed的实现 上一章节我们实现了 ref 及其它配套的isRef、unRef 和 proxyRefs API。这一章开始实现computed计算属性。 认识computed 接受一个 getter 函数&#xff0c;返回一个只读的响应式 ref 对象。该 ref 通过 .value 暴露 getter 函数的返回值。…...

Java基础之注解

3.注解 3.1概述【理解】 概述 对我们的程序进行标注和解释 注解和注释的区别 注释: 给程序员看的注解: 给编译器看的 使用注解进行配置配置的优势 代码更加简洁,方便 3.2自定义注解【理解】 格式 public interface 注解名称 { ​ public 属性类型 属性名() default 默认值…...

三、线性表

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 自学JAVA数据结构笔记&#xff0c;跟学视频为&#xff1a;黑马程序员Java数据结构与java算法全套教程…...

C++统计方形

统计方形 内存限制&#xff1a;256 MB 时间限制&#xff1a;1 S 题目描述 有一个n*m方格的棋盘&#xff0c;求其方格包含多少正方形、长方形&#xff08;此处长方形不包含正方形&#xff09; 输入格式 输入存在多组测试数据。每组测试数据输入两个整数n,m&#xff0c;数字不超…...

Tina_Linux配网开发指南

OpenRemoved_Tina_Linux_配网_开发指南 1 概述 1.1 编写目的 介绍Allwinner 平台上基于wifimanager-v2.0 的WiFi 配网方式&#xff0c;包括softap(WiFi ap 模式热点配网),soundwave(声波配网),BLE(蓝牙低功耗配网)。 1.2 适用范围 • allwinner 软件平台tina v5.0 版本及以…...

高频面试题|RabbitMQ如何防止消息的重复消费?

一. 前言最近有很多小伙伴开始找工作&#xff0c;在面试时&#xff0c;面试官经常会问我们这样一个题目&#xff1a;RabbitMQ如何防止重复消费?有很多小伙伴这个时候都在想&#xff0c;消息怎么还会重复消费呢???.......所以他们在面试后就跑来问壹哥&#xff0c;针对这个比…...

黑盒测试用例设计方法-边界值分析法

目录 一、边界值定义 二、边界值的考虑 三、边界值的优化 四、边界值的设计用例的步骤 五、案例 六、边界值的类型 一、边界值定义 边界值分析法就是对输入或输出的边界值进行测试的一种黑盒测试方法。通常边界值分析法是作为对等价类划分法的补充&#xff0c;这种情况下…...

项目风险管理中不可忽视的5个关键点

1、风险意识非常重要 项目经理必须要有风险意识&#xff0c;并不是项目计划做好就万事大吉&#xff0c;而是需要对项目风险进行预判&#xff0c;时刻保持风险意识&#xff0c;及时发现和处理项目风险。 项目风险管理关键&#xff1a;风险意识​ 2、建立组织风险资产库 寻…...

Linux->进程地址空间

目录 前言&#xff1a; 1. 程序地址空间回顾 2. 进程空间是什么 3. 进程地址空间与内存 4. 进程地址空间和内存的关联 5. 为什么要有进程地址空间 前言&#xff1a; 我们在平时学习的过程当中总是听到栈、堆、代码段等等储存空间&#xff0c;但是这些东西到底是什么&…...

【奶奶看了也不会】AI绘画 Mac安装stable-diffusion-webui绘制AI妹子保姆级教程

1.作品图 2.准备工作 目前网上能搜到的stable-diffusion-webui的安装教程都是Window和Mac M1芯片的&#xff0c;而对于因特尔芯片的文章少之又少&#xff0c;这就导致我们还在用老Intel 芯片的Mac本&#xff0c;看着别人生成美女图片只能眼馋。所以小卷这周末折腾了一天&#…...

基于stm32电梯管理系统设计

基于stm32电梯管理系统设计这里记录一下以前自己做的嵌入式课程设计&#xff0c;报告中的图片和文字太多了&#xff0c;全部一个一个把搬过来太麻烦了,需要完整文本和代码自行q我963160156&#xff0c;也可在微信公众号 *高级嵌入式软件* 里回复 *电梯* 查看完整版文章摘要关键…...

Spring中的FactoryBean 和 BeanFactory、BeanPostProcessor 和BeanFactoryPostProcessor解析

文章目录FactoryBean 和 BeanFactory后置处理器BeanPostProcessor 和 BeanFactoryPostProcessorBeanPostProcessorBeanFactoryPostProcessorFactoryBean 和 BeanFactory BeanFactory接⼝是容器的顶级接⼝&#xff0c;定义了容器的⼀些基础⾏为&#xff0c;负责⽣产和管理Bean的…...

【C++从入门到放弃】类和对象(上)

&#x1f9d1;‍&#x1f4bb;作者&#xff1a; 情话0.0 &#x1f4dd;专栏&#xff1a;《C从入门到放弃》 &#x1f466;个人简介&#xff1a;一名双非编程菜鸟&#xff0c;在这里分享自己的编程学习笔记&#xff0c;欢迎大家的指正与点赞&#xff0c;谢谢&#xff01; 类和对…...

什么牌子的蓝牙耳机便宜好用?四款高品质蓝牙耳机推荐

随着时代的发展&#xff0c;蓝牙耳机的使用频率越来越高&#xff0c;不少人外出时除了带手机外&#xff0c;蓝牙耳机也成为了外出必备的数码产品之一。现在的蓝牙耳机品牌众多&#xff0c;什么牌子的蓝牙耳机便宜好用&#xff1f;下面&#xff0c;我来给大家推荐四款高品质的蓝…...

eddsa 算法

信息安全课程设计&#xff1a;eddsa 算法 一、项目要求 使用 C 语言开发&#xff1b;可以实现公私钥生成、签名、认证&#xff1b;只需要手动输入明文&#xff0c;代码会自动生成公私钥、签名、认证&#xff1b;记录公私钥生成、签名、认证的时间&#xff1b;在 VS 上运行&am…...

Xcode Developer Document 开发者文档

总目录 iOS开发笔记目录 从一无所知到入门 文章目录IntroDeveloper Documentation 打开方式菜单栏点击 &#xff5c; 快捷键方式另一种打开方式Intro 2016年我在学校学Java的时候&#xff0c;要查某个Java类/方法的用法还得自己手动下载一种.chm格式的开发文档文件&#xff0c…...

IntelliJ插件开发教程之新建项目

JetBrains公司系列产品IDEA、WebStrom、PyCharm、CLion、GoLand等都是基于IntelliJ Platform开发而成&#xff0c;掌握IntelliJ插件开发技能便能拥有提升开发效率的终极武器。本教程Demo源码请微信公众号“开发效率”进行获取。阅读原文如果您是JetBrains产品的用户&#xff0c…...

【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密

在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

基于当前项目通过npm包形式暴露公共组件

1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹&#xff0c;并新增内容 3.创建package文件夹...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...

Python实现简单音频数据压缩与解压算法

Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中&#xff0c;压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言&#xff0c;提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...

【iOS】 Block再学习

iOS Block再学习 文章目录 iOS Block再学习前言Block的三种类型__ NSGlobalBlock____ NSMallocBlock____ NSStackBlock__小结 Block底层分析Block的结构捕获自由变量捕获全局(静态)变量捕获静态变量__block修饰符forwarding指针 Block的copy时机block作为函数返回值将block赋给…...