【C语言】深入解开指针(四)
🌈write in front :🔍个人主页 : @啊森要自信的主页
✏️真正相信奇迹的家伙,本身和奇迹一样了不起啊!
欢迎大家关注🔍点赞👍收藏⭐️留言📝>希望看完我的文章对你有小小的帮助,如有错误,可以指出,让我们一起探讨学习交流,一起加油鸭。
文章目录
- 前言
- 一、🚣 字符指针变量
- 二、⛵️ 数组指针变量
- 2.1 数组指针变量是什么?
- 2.2 数组指针变量怎么初始化
- 三、⛵️⼆维数组传参的本质
- 四、🚤函数指针变量
- 4.1 函数指针变量的创建
- 4.2 函数指针变量的使⽤
- 4.3 两段有趣的代码
- 4.3.1 typedef关键字
- 五、🚢函数指针数组
- ⚓️总结
前言
通过对前面指针的学习,你可能对指针有了一些理解,比如,数字名的理解,然后怎么使用指针来访问数组,二级指针,指针数组 …
有了这些的理解,本小节我们继续深入理解指针,啊森将会带你理解字符指针变量,数组指针变量,二维数组传参的本质,函数指针变量和函数指针数组,通过这些学习,我们最后来通过这些知识来实现转移表,话不多说,让我们启航!
一、🚣 字符指针变量
在C语言中,字符指针变量是一种指向字符型数据的指针变量。它可以用来指向一个字符数组的首地址,也可以用来指向一个字符型变量的地址。
指针类型为字符指针 char*
字符指针变量的声明和初始化如下所示:
char str[] = "Hello"; // 声明一个字符数组
char *ptr; // 声明一个字符指针变量
ptr = str; // 将字符数组的首地址赋给字符指针变量
通过字符指针变量可以访问和操作字符数组中的元素,也可以通过指针运算来访问字符串中的字符。例如:
int main()
{char str[] = "Hello";char* ptr;ptr = str;printf("%c\n", *ptr); // 输出字符数组的第一个字符printf("%c\n", *(ptr + 1)); // 输出字符数组的第二个字符return 0;
}
当然,以上是把字符串放在字符数组里面,不过我们可不可以把字符串直接放在指针里面呢?当然可以!
int main()
{const char* pa = "hello,world";//这⾥是把⼀个字符串放到pa指针变量⾥了吗?printf("%s\n", pa);return 0;
}
思考:这⾥是把⼀个字符串放到pa指针变量⾥了吗?
当然不是!
–>代码 const char* pa = "hello,world"; 特别容易让同学以为是把字符串 hello,world 放
到字符指针 pa ⾥了,但是本质是把字符串 hello,world. ⾸字符的地址放到了pa中。

这个是内存布局,"hello,world"是一个字符串常量,它的值存储在内存中,而pa是一个指向这个字符串常量的指针,它的值是字符串常量的地址。所以pa存储的值是104,也就是"hello,world"的第一个字符的ASCII码值,以此我们就可以通过第一个字符串常量的地址遍历后面的字符,顺藤摸瓜的找到字符"\0"才停止。
总结:代码的意思是把⼀个常量字符串的⾸字符 h 的地址存放到指针变量 pa 中。
《剑指Offer》中收录了一道和字符串相关的笔试题,让我们一起来学习一下:
#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");elseprintf("str1 and str2 are not same\n");if (str3 == str4)printf("str3 and str4 are same\n");elseprintf("str3 and str4 are not same\n");return 0;
}

这个代码打印结果不一样的原因是:
-
str1和str2是字符数组,它们分别用"hello bit."初始化了两个不同的数组。虽然内容相同,但它们占用的内存地址是不同的,所以str1 == str2 判断为不相等,打印"str1 and str2 are not same"。 -
str3和str4是字符指针,它们都指向同一个字符串常量"hello bit."。字符串常量存储在只读内存区域,无论如何定义,它们的地址是相同的。所以str3 == str4 判断为相等,打印"str3 and str4 are same"。
换句话说:
- 字符数组比较地址,地址不同就不相等。
- 字符串常量比较内容,内容相同就相等。
所以结果不同的原因是str1、str2是数组,str3、str4是指针,它们的比较规则不同。
如果将str3和str4也定义为字符数组,则它们的比较结果也会是不相等,打印"str3 and str4 are not same"。
二、⛵️ 数组指针变量
2.1 数组指针变量是什么?
之前我们学习了指针数组,指针数组是⼀种数组,数组中存放的是地址(指针)。
数组指针变量是指针变量?还是数组?
答案是:指针变量。
我们已经熟悉:
• 整形指针变量: int * pa; 存放的是整形变量的地址,能够指向整形数据的指针。
• 浮点型指针变量: float * pf; 存放浮点型变量的地址,能够指向浮点型数据的指针。
那数组指针变量应该是:存放的应该是数组的地址,能够指向数组的指针变量。
下⾯代码哪个是数组指针变量?

那数组指针变量应该是:存放的应该是数组的地址,能够指向数组的指针变量。
下⾯代码哪个是数组指针变量?
1. int *p1[10];2. int (*p2)[10];
思考⼀下:p1, p2分别是什么?

数组指针变量
数组指针变量
1 int (*p)[10];
解释:p先和*结合,说明p是⼀个指针变量变量,然后指着指向的是⼀个⼤⼩为10个整型的数组。所以
p是⼀个指针,指向⼀个数组,叫 数组指针。
这⾥要注意:[]的优先级要⾼于 * 号的,所以必须加上 () 来保证p先和 * 结合。
2.2 数组指针变量怎么初始化
数组指针变量是⽤来存放数组地址的,那怎么获得数组的地址呢?就是我们之前学习的 &数组名
int arr[10] = {0};
&arr;//得到的就是数组的地址
如果要存放个数组的地址,就得存放在数组指针变量中,如下:
1 int(*p)[10] = &arr;

我们调试也能看到 &arr 和 p 的类型是完全⼀致的。
数组指针类型解析:
1. int (*p) [10] = &arr;2. | | |3. | | |4. | | p指向数组的元素个数5. | p是数组指针变量名6. p指向的数组的元素类型
三、⛵️⼆维数组传参的本质
有了数组指针的理解,我们就能够讲⼀下⼆维数组传参的本质了。
过去我们有⼀个⼆维数组的需要传参给⼀个函数的时候,我们是这样写的:
#include <stdio.h>
void test(int a[3][5], int r, int c)
{int i = 0;int j = 0;for (i = 0; i < r; i++){for (j = 0; j < c; j++){printf("%d ", a[i][j]);}printf("\n");}
}
int main()
{int arr[3][5] = { {1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7} };test(arr, 3, 5);return 0;
}

C语言二维数组传参的本质是:
二维数组在传参时会自动退化为一维数组指针。
具体来说:
-
二维数组名代表整个二维数组,它其实就是一维数组指针,指向该数组的首行地址。
-
当二维数组作为参数传递给函数时,它会自动退化为一维数组指针。
-
函数内部无法得知传入的参数原本是二维数组,它只能看到一个一维数组指针。
举个例子:
void func(int arr[][3])
{// arr在这里实际类型是int (*arr)[3]
}int main()
{int a[4][3] = {0};func(a); // a传参时自动退化为一维数组指针return 0;
}
这里a是二维数组,但传给func函数时,func内部的arr参数实际上是一个指向int[3]类型一维数组的指针。
所以二维数组传参的本质,就是自动退化为一维数组指针。
而数组指针变量,它也可以指向二维数组首行地址,从而实现对二维数组的操作。
例如:
int (*ptr)[3] = a; // ptr指向a二维数组的首行
所以二维数组传参本质是退化为一维数组指针,而数组指针变量也可以指向二维数组,两者联系在一起,都可以看作是一维数组指针来操作二维数组。
那我们就来试试数组指针变量来遍历数组吧---------->
⾸先我们再次理解⼀下⼆维数组,⼆维数组起始可以看做是每个元素是⼀维数组的数组,也就是⼆维数组的每个元素是⼀个⼀维数组。那么⼆维数组的⾸元素就是第⼀⾏,是个⼀维数组。
如下图:

根据数组名是数组首元素的地址这个规则,二维数组的数组名表示的就是第一行的地址,是一维数组的地址。
根据上面的例子,第一行的一维数组的类型就是 int [5] ,所以第一行的地址的类型就是数组指针类型 int(*)[5] 。那就意味着二维数组传参本质上也是传递了地址,传递的是第一行这个一维数组的地址,那么形参也是可以写成指针形式的。如下:
#include <stdio.h>
void test(int(*p)[5], int r, int c)
{int i = 0;int j = 0;for (i = 0; i < r; i++){for (j = 0; j < c; j++){printf("%d ", *(*(p + i) + j));}printf("\n");}
}
int main()
{int arr[3][5] = { {1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7} };test(arr, 3, 5);return 0;
}

总结:⼆维数组传参,形参的部分可以写成数组,也可以写成指针形式。
四、🚤函数指针变量
4.1 函数指针变量的创建
类比一下:
数组指针变量应该是:存放的应该是数组的地址,能够指向数组的指针变量。
C语言中的函数指针变量是指向函数的指针变量。
函数指针变量的定义格式是:
返回类型 (*变量名)(参数类型列表);
例如:
int (*ptr)(int, char); // ptr是一个指向返回类型为int,参数为int和char的函数的指针
函数指针变量和普通指针变量一样,它也需要指向具体的函数地址才能调用该函数。
例如:
int func(int a, char b)
{return a + b;
}int main()
{int (*ptr)(int, char); // 函数指针变量声明ptr = func; // 指向func函数ptr(10, 'a'); // 通过函数指针调用func函数return 0;
}
函数指针变量的主要特点:
- 可以指向不同类型的函数
- 通过它可以调用被指向的函数
- 可以作为函数参数或返回值进行传递
- 常用在回调函数机制中
函数指针变量是用来存放函数地址的,通过这个地址可以调用函数。函数确实有地址!
#include <stdio.h>void print()
{printf("lalala\n");
}
int main()
{printf("test: %p\n", print);printf("&test: %p\n", &print);return 0;
}
输出:

确实打印出来了地址,所以函数是有地址的,函数名就是函数的地址,当然也可以通过 &函数名 的⽅式获得函数的地址。
如果我们要将函数的地址存放起来,就得创建函数指针变量咯,函数指针变量的写法其实和数组指针⾮常类似。如下:
void print()
{printf("lalala\n");
}
void (*pf1)() = &print;
void (*pf2)() = print;int Add(int x, int y)
{return x + y;
}
int(*pf3)(int, int) = Add;
int(*pf3)(int x, int y) = &Add;//x和y写上或者省略都是可以的
1. int (*pf3) (int x, int y)2. | | ------------3. | | |4. | | pf3指向函数的参数类型和个数的交代5. | 函数指针变量名6. pf3指向函数的返回类型7. 8. int (*) (int x, int y) //pf3函数指针变量的类型
看到这里,你可能会发现数组指针变量和函数指针变量其实好像也是差别不大呀!
4.2 函数指针变量的使⽤
通过函数指针调⽤指针指向的函数。
#include <stdio.h>
int Add(int x, int y)
{return x + y;
}
int main()
{int(*pf3)(int, int) = Add;printf("%d\n", (*pf3)(1, 2));printf("%d\n", pf3(3, 4));return 0;
}

代码输出的结果是一样的,为什么这两种方式都可以呢?
解释:
首先, pf3是一个函数指针变量,它指向Add函数。
在C语言中,函数指针与一般指针运算方式是一致的。
也就是说,对函数指针进行解引用(*pf3)后的结果,就是被指向的函数本身。
所以:
- (*pf3)(1, 2)
- 等价于 解引用pf3,得到Add函数,然后调用Add(1, 2)
- pf3(3, 4)
- 等价于 调用函数指针pf3,它指向的函数Add(3, 4)
两者调用的函数都是Add,参数也一致,所以结果是相同的。
函数指针与一般指针在语法上表现形式不同,但本质上都是指向函数地址的指针。所以对函数指针进行解引用或直接调用效果是一致的。
因此上述代码两种打印方式结果相同,原因就是函数指针与普通指针在语法和语义上是一致的。
4.3 两段有趣的代码
注:两段代码均出⾃:《C陷阱和缺陷》这本书

代码1
1 (*(void (*)())0)();
让我们分析一下:
-
(void (*)())0意思是把0这个整数值,强制类型转换成一个地址,这个函数没有参数,返回类型是void。 -
*操作符对它进行解引用,得到
void ()类型的匿名函数。 -
对这个匿名函数进行调用
(),也就是调用0地址处的地址。
所以整个表达式:
(void (*)())0 - 获取函数指针,指向0地址
-
- 解引用函数指针,得到匿名函数
() - 调用匿名函数
- 解引用函数指针,得到匿名函数
换句话说,这个代码是:
获取一个指向0地址的函数指针,然后解引用它得到一个匿名函数,并对这个匿名函数进行调用。
由于指针指向0地址,实际调用的是内核NULL地址下的代码。这通常会触发异常或者崩溃。
所以这个代码展示了一个通过函数指针调用匿名函数的语法,它实际上是在尝试访问空指针下的代码从而触发错误。
代码2
1 void (*signal(int , void(*)(int)))(int);
精简理解:
- 首先上述代码是函数声明
- signal是一个函数
- signal函数的参数有2个,第一个是int类型
- 第二个是函数指针类型,该指针指向的函数参数是int,返回类型是void
- signal函数的返回类型是这种类型的void(*)(int)函数指针
- 该指针指向的函数参数是int,返回类型是void
细节分析拓展如下:
此时注意signal并没有与前面的*用括号结合 这个代码定义了一个signal函数,它的功能是设置信号处理函数。
-
void(*)(int) 定义了一个函数指针,该函数指针指向一个返回void,接受一个int参数的函数。
-
signal是函数名,它有两个参数:
-
int: 表示信号编号
-
void(*)(int): 函数指针,表示要设置的信号处理函数
-
-
signal函数的返回值是一个函数指针:void (*)(int)
-
这个返回值函数指针也指向一个返回void,接受一个int参数的函数。
所以整个函数声明可以解释为:
signal函数用于设置信号处理函数。它接收两个参数:
- 信号编号
- 要设置的信号处理函数
signal函数返回原来的信号处理函数。
所以这个函数声明定义了一个典型的设置信号处理函数的接口 - signal(),它可以用来设置和获取信号的处理回调函数。
**总结来说:**这个函数声明使用了嵌套的函数指针定义了signal函数的接口格式,目的是为了设置和获取信号处理回调函数。
4.3.1 typedef关键字
当你看到了这里,你可能在想,这么长void (*signal(int , void(*)(int)))(int);的代码,写出来真麻烦,有没有办法可以简化他的长度呢,看起来可观,容易理解呢?可不能自己写着写着把自己转忽悠了哈哈哈。
当然!
typedef 是⽤来类型重命名的,可以将复杂的类型,简单化。
C语言中的typedef主要用于定义类型别名。
typedef语法:
typedef 旧类型名 新类型名;
例如:
typedef int Int;
这行代码定义Int为int类型的别名。
typedef的主要用途:
- 为复杂类型定义简短的名称
比如定义指针、函数指针等:
typedef int (*FuncPtr)(int);
- 隐藏实现细节
比如用结构体指针替换结构体:
typedef struct {int x;int y;
} Point;typedef Point* PointPtr;
- 向下兼容
如果需要修改类型定义,可以使用typedef避免修改大量代码。
- 提高代码可读性
给类型起个有意义的名称,比如用Person替换struct Person。
- 标准库也广泛使用
typedef
如size_t、ptrdiff_t等标准类型都是通过typedef定义的。
所以总体来说,typedef主要用于为类型起别名,简化和隐藏类型,提高代码可读性和兼容性。它广泛应用于C标准库和程序开发中。
本小节由于篇幅有限,我们先讲第一点:
⽐如我们有数组指针类型 int(*)[5] ,需要重命名为 parr_t ,那可以这样写:
1 typedef int(*parr_t)[5]; //新的类型名必须在*的右边
函数指针类型的重命名也是⼀样的,⽐如,将 void(*)(int) 类型重命名为 pf_t ,就可以这样写:
1 typedef void(*pfun_t)(int);//新的类型名必须在*的右边
那么要简化代码2,可以这样写:
typedef void(*pfun_t)(int);
pfun_t signal(int, pfun_t);
五、🚢函数指针数组

数组是⼀个存放相同类型数据的存储空间,我们已经学习了指针数组,
⽐如:
int *arr[10];
//数组的每个元素是int*
那要把函数的地址存到⼀个数组中,那这个数组就叫函数指针数组,那函数指针的数组如何定义呢?
这三个捏个才是正确的呢?int (*parr1[3])();
int *parr2[3]();
int (*)() parr3[3];
答案是:parr1
parr1 先和 [] 结合,说明 parr1是数组,数组的内容是什么呢?
是 int (*)() 类型的函数指针。
这个定义相当于:
- 定义一个函数指针数组parr1
- 数组长度为3
- 每个元素都是一个函数指针
- 指向一个返回int,无参数的函数
这里给出一个C语言函数指针数组的简单实现示例:
// 定义函数原型
int func1(void);
int func2(void);int func1(void)
{printf("func1 called\n");return 0;
}int func2(void)
{printf("func2 called\n");return 0;
}int main()
{// 定义函数指针数组,可以存储2个函数指针int (*funcPtrArr[2])(void);// 初始化函数指针数组元素funcPtrArr[0] = func1;funcPtrArr[1] = func2;// 通过索引调用函数指针数组元素指向的函数funcPtrArr[0]();funcPtrArr[1]();return 0;
}
输出结果为:

主要实现步骤:
- 定义函数原型
- 定义函数指针数组
- 初始化数组元素,使每个元素指向对应的函数
- 通过数组索引,调用函数指针指向的函数
这个示例演示了如何定义和使用函数指针数组来管理和调用多个函数。
实际应用中,可以通过函数指针数组实现回调函数、插件等机制。函数也可以作为参数传递给其他函数。
总之,函数指针数组提供了一种灵活高效的方式来管理和调用多个函数在C语言中。怎么高效?下一届我们做一个计算器,转移表就可以清楚理解他的巧妙之处!
⚓️总结
一、字符指针变量
字符指针变量用来存储字符串,可以通过字符指针访问字符串中的每个字符。
二、数组指针变量
2.1 数组指针变量实际指向数组第一个元素的地址。
2.2 可以通过数组名直接初始化数组指针,也可以通过地址运算符&初始化。
三、二维数组传参的本质
二维数组传参实际上是传一级指针,等同于传数组指针。
四、函数指针变量
4.1 通过函数原型声明函数指针变量类型,并使用地址运算符&初始化。
4.2 通过函数指针调用函数,等同于使用普通函数名调用。
4.3 typedef可以简化函数指针变量类型定义。
五、函数指针数组
函数指针数组可以存储和管理多个函数指针,通过数组索引调用不同函数。
总之,C语言指针变量提供了一种灵活的方式来操作和管理数据,如字符串、数组、函数等。指针变量的概念和使用需要熟练掌握,它是C语言的重要知识点。感谢你的收看,如果文章有错误,可以指出,我不胜感激,让我们一起学习交流,如果文章可以给你一个帮助,可以给博主点一个小小的赞😘
相关文章:
【C语言】深入解开指针(四)
🌈write in front :🔍个人主页 : 啊森要自信的主页 ✏️真正相信奇迹的家伙,本身和奇迹一样了不起啊! 欢迎大家关注🔍点赞👍收藏⭐️留言📝>希望看完我的文章对你有小小的帮助&am…...
AMEYA360:瑞萨面向高端工业传感器系统推出高精度模拟前端的32位RX MCU
全球半导体解决方案供应商瑞萨电子(TSE:6723)宣布面向高端工业传感器系统推出一款全新RX产品——RX23E-B,扩展32位微控制器(MCU)产品线。新产品作为广受欢迎的RX产品家族的一员,具有高精度模拟前…...
切面Aspect + 策略模式实现待办提醒功能
1.背景 产品需要实现一个待办提醒功能,就是核心业务发生变更即提醒业务员去处理相关业务。譬如:订单上传了支付凭证,那么就会提醒相关业务员去待办列表操办。 2.表设计 其实表设计主要是两张表sys_todo、sys_todo_detail 一张是待办核心表…...
SAP 调取http的x-www-form-urlencoded形式的接口
一、了解下x-www-form-urlencoded形式对于SAP来说有啥区别 简单来说, 1.raw格式就是标准的json格式:{“Name”:“John Smith”,“Age”: 23} 2.x-www格式是要转化一下的:NameJohnSmith&Age23 字段与字段相互连接要用 & 符…...
thingsboard3.6的mailConfigTemplateController错误
1、bug内容 使用3.6版本的tb代码进行打包生成boot的jar包,在启动的时候会报错mailConfigTemplateController bean初始化找不到文件路径。 Error creating bean with name mailConfigTemplateController defined in URL [jar:file:/D:/yuxinwei/AE/thingsboard/thingsboard-3…...
Go语言中获取IP
简介 在net包中提供了获取所有网卡的ip,一般不会用127.0.0.1,::1这样的本地回环地址,可以过滤掉,如果想要获取当前真正在使用的地址,得通过net.Dail去连一下才知道 获取ip地址 func main() {fmt.Println(getIpv4())fmt.Println…...
【Computer Vision Foundation】全球计算机视觉基金会论文网
计算机视觉基金会(Computer Vision Foundation,简称CVF)是一个致力于推动计算机视觉领域研究和发展的组织。以下是关于计算机视觉基金会的一些基本信息: 成立目的: CVF成立的目的是促进计算机视觉领域的学术研究、技术…...
计网(复习自用)
计算机网络 1.概述 1.1概念 含义 计算机网络:是一个将分散的。具有独立功能的计算机系统,通过通信设备和线路连接起来,由功能完善的软件实现资源共享和信息传递的系统。 简单点说,计算机网络是互联的,自治的计算机集…...
安徽省广德市选择云轴科技ZStack Cloud云平台建设县级智慧城市
信创是数字中国建设的重要组成部分,也是数字经济发展的关键推动力量。作为云基础软件企业,云轴科技ZStack产品矩阵全面覆盖数据中心云基础设施,ZStack信创云首批通过可信云《一云多芯IaaS平台能力要求》先进级,是其中唯一兼容四种…...
【计算思维】蓝桥杯STEMA 科技素养考试真题及解析 6
1、明明买了一个扫地机器人,可以通过以下指令控制机器人运动: F:向前走 10 个单位长度 L:原地左转 90 度 R:原地右转 90 度 机器人初始方向向右,需要按顺序执行以下那条指令,才能打扫完下图中的道路 A、F-L-F-R-F-F-R-F-L-F B、F-R-F-L-F-F…...
nuxt3项目修改端口号
nuxt的默认端口号是3000 一、修改开发环境端口号 方式一:使用环境变量配置,设置(PORT 或 NUXT_PORT) # .env PORT3001 #http://localhost:3001/ NITRO_PORT3001 #http://localhost:3001/ 方式二:nuxt.config.ts里配置…...
c语言中使用openssl对rsa私钥解密
单次加密数据的最大长度(block_len),由RSA秘钥模长RSA_size()和填充模式有关 填充模式:RSA_PKCS1_PADDING, block_lenRSA_size() - 11填充模式:RSA_PKCS1_OAEP_PADDING,block_lenRSA_size() - 4…...
mysql中数据是如何被用B+树查询到的
innoDB是按照页为单位读写的 那页中有很多行数据,是怎么执行查询的呢,首先我们肯定,是以单向列表形式存储的,提高了增删的效率,但是查询效率低。所以实际上对页中的行数据进行了优化,能以二分的方式进行查…...
Redisson 分布式锁的最佳实践
Redisson 分布式锁的最佳实践 第一、添加依赖第二、添加redisson配置类第三、添加测试类测试结果扩展知识redisson锁中lock方法和tryLock方法有什么区别锁续约 注意事项 引言 在现代分布式系统中,处理并发问题是至关重要的。分布式锁是解决这类问题的关键工具之一。…...
ArkTS声明式开发范式
装饰器 用来装饰类、结构体、方法以及变量,赋予其特殊的含义,如上述示例中 Entry 、 Component 、 State 都是装饰器。 Component 表示这是个自定义组件; Entry 则表示这是个入口组件; State 表示组件中的状态变量,…...
史诗级云故障敲响警钟,应用保障不能没有“连续键”!
近日,知名云服务商出现一次史诗级的云故障:全球所有区域/所有服务同时异常,故障持续长达3小时之多,云上众多应用受到极大影响。 如今,在一个充满不确定性和复杂性的数字化时代,哪怕是顶级云服务商亦不能避…...
SSH连接远程服务器报错:WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED 解决方法
一.错误描述 报错信息里提示了路径信息/root/.ssh/known_hosts:20 二.解决方案 方法一 输入以下指令: ssh-keygen -R XXX(需要连接远程服务器的ip) 按照我的例子ip:10.165.7.136,会返回以下信息: 重新尝试连接: 输…...
数据库——查询连续的月份
一、GP或PGSQL with recursive t(n) as (select date(2023-01-01) union all select n1 from t where n < now()) select to_char(n, yyyy-mm) as ny from t group by ny order by ny 二、Hive select add_months(FROM_UNIXTIME(unix_timestamp(SUBSTR(start_date, 1, 7…...
git代码提交命令(如何提交代码)
# 提交暂存区到仓库区 $ git commit -m [message]# 提交暂存区的指定文件到仓库区 $ git commit [file1] [file2] ... -m [message]# 提交工作区自上次commit之后的变化,直接到仓库区 $ git commit -a# 提交时显示所有diff信息 $ git commit -v# 使用一次新的commit…...
jmeter中调用python代码
1、安装pyinstaller pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyinstaller 2、将py脚本打包 pyinstaller -F venv/get_image/OCR_jmeter_api.py 3、jmeter中添加OS Process Sampler并调用dist下的程序 4、执行jmeter...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...
java高级——高阶函数、如何定义一个函数式接口类似stream流的filter
java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用(Math::max) 2 函数接口…...


