C语言 -- 深入理解指针(二)

C语言 -- 深入理解指针(二)

  • 1. 数组名的理解
  • 2. 使用指针访问数组
  • 3. 一维数组传参的本质
  • 4. 冒泡排序
  • 5. 二级指针
  • 6. 指针数组
  • 7. 指针数组模拟二维数组
  • 8. 字符指针变量
  • 9. 数组指针变量
    • 2.1数组指针变量是什么?
    • 2.2 数组指针变量怎么初始化
  • 10. 二维数组传参的本质
  • 11. 函数指针变量
    • 4.1 函数指针变量的创建​
    • 4.2 函数指针变量的使用
    • 4.3 两段有趣的代码
      • 4.3.1 typedef关键字​
  • 12. 函数指针数组
  • 13. 转移表
  • 14.回调函数是什么?

1. 数组名的理解

使用指针访问数组的内容时,有这样的代码:
在这里插入图片描述

&arr[0] 的方式拿到了数组第一个元素的地址
但是其实数组名arr本来就是地址,而且是数组首元素的地址

下面我们来看个代码:

在这里插入图片描述

我们发现数组名和数组首元素的地址打印出的结果一模一样,数组名就是数组首元素(第一个元素)的地址。

  • 这时候有同学会有疑问?数组名如果是数组首元素的地址,那下面的代码怎么理解呢?

在这里插入图片描述

输出的结果是:40,如果arr是数组首元素的地址,那输出应该的应该是4/8才对。​
其实数组名就是数组首元素(第一个元素)的地址是对的,但是有两个例外

  • sizeof(数组名),sizeof中单独放数组名,这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节
  • &数组名,这里的数组名表示整个数组,取出的是整个数组的地址(整个数组的地址和数组首元素的地址是有区别的)
  • 除此之外,任何地方使用数组名,数组名都表示首元素的地址。

这时有好奇的同学,再试一下这个代码:

在这里插入图片描述

三个打印结果一模一样,这时候又纳闷了,那arr和&arr有啥区别呢?
请看下面代码:

在这里插入图片描述
运行结果:

在这里插入图片描述

  • 这里我们发现&arr[0]和&arr[0]+1相差4个字节,arr和arr+1 相差4个字节,是因为&arr[0] 和 arr 都是首元素的地址,+1就是跳过一个元素。
  • 但是&arr 和 &arr+1相差40个字节,这就是因为&arr是数组的地址,+1 操作是跳过整个数组的。​
  • 到这里大家应该搞清楚数组名的意义了吧。
    数组名是数组首元素的地址,但是有2个例外。

2. 使用指针访问数组

1.因为数组在内存中是连续存放的
2.数组名就是首元素的地址(方便找到起始位置)
所以可以用指针来访问数组
代码如下
在这里插入图片描述

这个代码搞明白后,我们再试一下,如果我们再分析一下,数组名arr是数组首元素的地址,可以赋值给p,其实数组名arr和p在这里是等价的
在这里插入图片描述

同理arr[i] 应该等价于 *(arr+i)数组元素的访问在编译器处理的时候,也是转换成首元素的地址+偏移量求出元素的地址,然后解引用来访问的。

3. 一维数组传参的本质

首先从一个问题开始,我们之前都是在函数外部计算数组的元素个数,那我们可以把函数传给一个函数后,函数内部求数组的元素个数吗?
代码如下:

在这里插入图片描述
我们发现在函数内部是没有正确获得数组的元素个数。
这就要学习数组传参的本质了,在上面我们学习了:数组名是数组首元素的地址;那么在数组传参的时候,传递的是数组名,也就是说本质上数组传参本质上传递的是数组首元素的地址。所以函数形参的部分理论上应该使用指针变量来接收首元素的地址。那么在函数内部我们写sizeof(arr) 计算的是一个地址的大小(单位字节)而不是数组的大小(单位字节)。正是因为函数的参数部分是本质是指针,所以在函数内部是没办法求的数组元素个数的。

在这里插入图片描述

再看一组打印数组的代码如下:

在这里插入图片描述

结论:数组传参本质上传递的是数组首元素的地址
一维数组传参,形参的部分可以写成数组的形式,也可以写成指针的形式。

4. 冒泡排序

冒泡排序的核心思想就是:两两相邻的元素进行比较,如果不满足顺序就交换。
练习:写一个函数,对一个整形数组的数据进行排序。
n个元素,n-1趟
第一趟过程中,排n个元素,n-1对比较
第二趟过程中,排n-1个元素,n-2对比较
以此类推…
方法一:

在这里插入图片描述

运行结果:
在这里插入图片描述
方法二:优化上面代码 已经有序或者接近有序的数字就没必要重复比较了。

在这里插入图片描述

运行结果:
在这里插入图片描述

5. 二级指针

指针变量也是变量,是变量就有地址,二级指针变量是用来存放一级指针变量的地址。
在这里插入图片描述
在这里插入图片描述
对于二级指针的运算有:

  • *ppa 通过对ppa中的地址进行解引用,这样找到的是 pa ,*ppa 其实访问的就是 pa .
  • **ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,那找到的是 a .
    在这里插入图片描述

6. 指针数组

指针数组是指针还是数组?
我们类比一下

  • 整型数组 - 存放整型的数组(数组中每个元素是整形类型)
  • 字符数组 - 存放字符的数组(数组中每个元素是字符类型)
  • 指针数组- 存放指针的数组(数组中每个元素是指针类型)

int arr [10] 整形数组
char ch [5] 字符数组
希望有一个数组,数组有4个元素,每个元素是整形指针
int * arr [4];

下面请看图例:

在这里插入图片描述
指针数组的每个元素都是用来存放地址(指针)的。
如下图:
在这里插入图片描述
指针数组的每个元素是地址,又可以指向一块区域。

7. 指针数组模拟二维数组

模拟出二维数组的效果,但不是二维数组。
二维数组的每一行是一个一维数组
看下面代码:

在这里插入图片描述

图示:
在这里插入图片描述

  • parr[i]是访问parr数组的元素,parr[i]找到的数组元素指向了整型一维数组,parr[i][j]就是整型一维数组中的元素。
  • 上述的代码模拟出二维数组的效果,实际上并非完全是二维数组,因为每一行并非是连续的。

8. 字符指针变量

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

在这里插入图片描述

还有一种使用方式如下:

在这里插入图片描述

  1. 你可以把字符串想象为一个字符数组,但是这个数组是不能修改的
  2. 当常量字符串出现在表达式中的时候,他的值是第一个字符的地址
  3. 常量字符串是不能被修改的 ,所以要加const

4.const char* p = “abcdef”;//不是把字符串abcdef\0存放在p中,而是把第一个字符的地址存放在p中

《剑指offer》中收录了一道和字符串相关的笔试题,我们一起来学习一下:

在这里插入图片描述

运行结果:
在这里插入图片描述
这里str3和str4指向的是一个同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当几个指针指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以str1和str2不同,str3和str4相同。

9. 数组指针变量

2.1数组指针变量是什么?

  • 整形指针变量: int * pint; 存放的是整形变量的地址,能够指向整形数据的指针。
  • 浮点型指针变量: float * pf; 存放浮点型变量的地址,能够指向浮点型数据的指针。
  • 数组指针变量应该是:存放的应该是数组的地址,能够指向数组的指针变量。

int *p1[10]; p1是数组,数组10个元素,每个元素的类型是int *,所以p1是指针数组
int (*p2)[10]; p2是指针,指向数组 ,数组有10个元素,每个元素的类型是int,p2是数组指针

数组指针变量

int (*p)[10];

  • p先和*结合,说明p是一个指针变量,然后指向的是一个大小为10个整型的数组。所以p是一个指针,指向一个数组,叫 数组指针。
  • 这里要注意:[]的优先级要高于号的,所以必须加上()来保证p先和结合。​

2.2 数组指针变量怎么初始化

数组指针变量是用来存放数组地址的,那怎么获得数组的地址呢?就是我们之前学习的 &数组名

在这里插入图片描述
如果要存放个数组的地址,就得存放在数组指针变量中,如下:
在这里插入图片描述
例子:

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p1 = arr;
	//int*     int*
	int* p2 = &arr[0];
	//int*     int*
	int (*p3)[10] = &arr;//p3是数组指针 
	//&arr 和 p3的类型是完全一致的
	//int (*)[10]   int (*)[10] 
	//
	return 0;
}

数组指针类型解析:
在这里插入图片描述

10. 二维数组传参的本质

过去我们有一个二维数组的需要传参给一个函数的时候,我们是这样写的:

#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;
}

运行结果:
在这里插入图片描述

  • 这里实参是二维数组,形参也写成二维数组的形式,那还有什么其他的写法吗?
  • 首先我们再次理解一下二维数组,二维数组起始可以看做是每个元素是一维数组的数组,也就是二维数组的每个元素是一个一维数组。那么二维数组的首元素就是第一行,是个一维数组。

如下图:
在这里插入图片描述

  • 二维数组的数组名表示的就是第一行的地址,是一
    维数组的地址。
  • 第一行的一维数组的类型就是 int [5] ,所以第一行的地址的类型就是数组指针类型 int(*)[5]

1.二维数组传参本质上也是传递了地址,传递的是第一行这个一维数组的地址,那么形参也是可以写成指针形式的。
2.二维数组传参,形参的部分可以写成数组,也可以写成指针形式。

代码如下:

#include <stdio.h>
void Print_arr(int(*arr)[5], int r, int c)
{
	int i = 0;
	for (i = 0; i < r; i++)
	{
		int j = 0;
		for (j = 0; j < c; j++)
		{
							//arr[i][j]
			printf("%d ", *(*(arr + 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} };
	Print_arr(arr, 3, 5); //传递的是第一行一维数组的地址
	return 0;
}

运行结果:
在这里插入图片描述

11. 函数指针变量

4.1 函数指针变量的创建​

函数指针变量应该是用来存放函数地址的,未来通过地址能够调用函数的。
那么函数是否有地址呢?我们做个测试:

#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 (*p)(int, int) = &Add;
	return 0;
}

在这里插入图片描述

4.2 函数指针变量的使用

通过函数指针调用指针指向的函数。

#include <stdio.h>
int  Add(int x, int y)
{
	return x + y;
}
int main()
{
	/*printf("%p\n", &Add);
	printf("%p\n", Add);*/
	int (*p)(int, int) = &Add; //<==> Add
	int ret = Add(3, 5);
	printf("%d\n", ret);
	int ret1 = (*p)(4, 5);
	int ret2 = p(5, 5);
	printf("%d\n", ret1);
	printf("%d\n", ret2);
	return 0;
}

运行结果:
在这里插入图片描述

1.把一个函数地址放到一个函数指针变量里面,函数指针变量指向的对象是一个函数,解引用就可以得到函数。
2.函数名= 函数的地址=Add ,就可以写成 函数的地址(3,5)
函数指针变量里面放的就是函数地址 也就可以写成 函数指针变量(3,5),因此Add(3,5) == (*p)(3,5) ==p(3,5)
3. Add(3,5) == (*p)(3,5) ==p(3,5) 叫法:通过函数指针来调用它所对应的函数。

4.3 两段有趣的代码

代码1:

(*(void (*)())0)();  //把0当作一个函数的地址

在这里插入图片描述

代码2​:

void (*signal(int , void(*)(int)))(int);
typedef void(*pf_t)(int); //函数指针类型重命名
pf_t signal(int, pf_t);

上述代码是函数声明
1.signal是一个函数
2.signal函数的参数有2个,第一个是int类型,第二个是函数指针类型,该指针指向的函数参数是int,返回类型是void
3.signal函数的返回类型是这种类型的void(*)(int)函数指针
该指针指向的函数参数是int,返回类型是void

4.3.1 typedef关键字​

typedef 是用来类型重命名的,可以将复杂的类型,简单化。​
比如,你觉得 unsigned int 写起来不方便,如果能写成 uint 就方便多了,那么我们可以使用:
在这里插入图片描述
如果是指针类型,能否重命名呢?其实也是可以的,比如,将 int* 重命名为 ptr_t ,这样写:
在这里插入图片描述
但是对于数组指针和函数指针稍微有点区别:
比如我们有数组指针类型 int(*)[5] ,需要重命名为 parr_t ,那可以这样写:
在这里插入图片描述
函数指针类型的重命名也是⼀样的,比如,将 void( * )(int) 类型重命名为 pf_t ,就可以这样写:
在这里插入图片描述
例子:

typedef unsigned int uint;  

typedef int(*pArr_t)[10] ;  //数组指针类型重命名

typedef int (*pf_t)(int, int) ;  //函数指针类型重命名

int main()
{
	unsigned int num;
	uint num2;
	pArr_t pa;  //数组指针变量
	int(*pb)[10]; //数组指针变量
	pf_t pf;   //函数指针变量
	int (*pf2)(int, int);  //函数指针变量

	return 0;
}

12. 函数指针数组

数组是⼀个存放相同类型数据的存储空间,我们已经学习了指针数组,
比如:
在这里插入图片描述
那要把函数的地址存到一个数组中,那这个数组就叫函数指针数组,那函数指针的数组如何定义呢?
在这里插入图片描述
答案是:parr1
parr1 先和 [] 结合,说明parr1是数组,数组的内容是什么呢?
是 int (*)() 类型的函数指针。

在这里插入图片描述
应用:

#include <stdio.h>
int Add(int x, int y)
{
	return x + y;
}

int Sub(int x, int y)
{
	return x - y;
}

int Mul(int x, int y)
{
	return x * y;
}

int Div(int x, int y)
{
	return x / y;
}

int main()
{
	int (*pf)(int, int) = Add;//pf是函数指针

	int (* pfArr[4])(int, int) = {Add, Sub, Mul, Div};//存放函数指针的数组-函数指针数组
	                             //0    1    2    3
	int i = 0;
	for (i=0; i < 4; i++)
	{
		int ret = pfArr[i](6, 2);
		printf("%d\n", ret);
	}
	return 0;
}

运行结果:
在这里插入图片描述

13. 转移表

函数指针数组的用途:转移表
举例:计算器的一般实现:

#include <stdio.h>
void menu()
{
	printf("******************************\n");
	printf("****  1. add     2. sub   ****\n");
	printf("****  3. mul     4. div   ****\n");
	printf("****  0. exit             ****\n");
	printf("******************************\n");
}

int Add(int x, int y)
{
	return x + y;
}

int Sub(int x, int y)
{
	return x - y;
}

int Mul(int x, int y)
{
	return x * y;
}

int Div(int x, int y)
{
	return x / y;
}


int main()
{
	int input = 0;
	int x = 0;
	int y = 0;
	int ret = 0;
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("请输入两个操作数:");
			scanf("%d %d", &x, &y);
			ret = Add(x, y);
			printf("%d\n", ret);
			break;
		case 2:
			printf("请输入两个操作数:");
			scanf("%d %d", &x, &y);
			ret = Sub(x, y);
			printf("%d\n", ret);
			break;
		case 3:
			printf("请输入两个操作数:");
			scanf("%d %d", &x, &y);
			ret = Mul(x, y);
			printf("%d\n", ret);
			break;
		case 4:
			printf("请输入两个操作数:");
			scanf("%d %d", &x, &y);
			ret = Div(x, y);
			printf("%d\n", ret);
			break;
		case 0:
			printf("退出计算器\n");
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

运行结果:
在这里插入图片描述
使用函数指针数组的实现

#include <stdio.h>
void menu()
{
	printf("******************************\n");
	printf("****  1. add     2. sub   ****\n");
	printf("****  3. mul     4. div   ****\n");
	printf("****  0. exit             ****\n");
	printf("******************************\n");
}

int Add(int x, int y)
{
	return x + y;
}

int Sub(int x, int y)
{
	return x - y;
}

int Mul(int x, int y)
{
	return x * y;
}

int Div(int x, int y)
{
	return x / y;
}


int main()
{
	int input = 0;
	int x = 0;
	int y = 0;
	int ret = 0;
	do
	{
		menu();
		//函数指针数组的方式解决一下
		//这里的函数指针数组,我们称为转移表
		//
		int (*pfArr[])(int, int) = { NULL, Add, Sub, Mul, Div };
		//                           0     1    2    3    4
		printf("请选择:");
		scanf("%d", &input);

		if (input == 0)
		{
			printf("退出计算器\n");
		}
		else if (input >= 1 && input <= 4)
		{
			printf("请输入两个操作数:");
			scanf("%d %d", &x, &y);
			ret = pfArr[input](x, y);
			printf("%d\n", ret);
		}
		else
		{
			printf("选择错误,重新选择\n");
		}
	} while (input);
	return 0;
}

运行结果:
在这里插入图片描述

14.回调函数是什么?

函数指针可以用来实现回调函数。

  • 如果你把函数的指针(地址)作为参数传递给另一个函数,通过这个指针函数去调用对应的函数时,被调用的函数就是回调函数。
  • 回调函数不是由该函数的实现方直接调用,而是在特定的事件或条 件发生时由另外的一方调用的,用于对该事件或条件进行响应。

在这里插入图片描述

  • 这里我们可以把调用的函数的地址以参数的形式传递过去,使用函数指针接收,函数指针指向什么函数就调用什么函数,这里其实使用的就是回调函数的功能。
#include <stdio.h>
void menu()
{
	printf("******************************\n");
	printf("****  1. add     2. sub   ****\n");
	printf("****  3. mul     4. div   ****\n");
	printf("****  0. exit             ****\n");
	printf("******************************\n");
}

int Add(int x, int y)
{
	return x + y;
}

int Sub(int x, int y)
{
	return x - y;
}

int Mul(int x, int y)
{
	return x * y;
}

int Div(int x, int y)
{
	return x / y;
}


//calc功能强大了

void calc(int (*pf)(int,int))
{
	int x = 0;
	int y = 0;
	int ret = 0;
	printf("请输入两个操作数:");
	scanf("%d %d", &x, &y);
	ret = pf(x, y);
	printf("%d\n", ret);
}

int main()
{
	int input = 0;
	
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			calc(Add);//完成计算	
			break;
		case 2:
			calc(Sub);
			break;
		case 3:
			calc(Mul);
			break;
		case 4:
			calc(Div);
			break;
		case 0:
			printf("退出计算器\n");
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}
	} while (input);

	return 0;
}

代码实现过程图解:
在这里插入图片描述

运行结果:
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

选择适合的220V转5V电源芯片,220V转5V非隔离降压电源ic

#### 问题&#xff1a; 在设计一个需要将220V交流电转换为5V直流电的电路时&#xff0c;我应该选择哪种型号的电源芯片&#xff1f;我需要输出电流在200mA以内&#xff0c;有没有推荐的型号&#xff1f; #### 答案&#xff1a; 在220V交流电转换为5V直流电的应用中&#xff0c…

经典的layui框架,还有人用吗?令人惋惜。

自从layui官网宣布关闭之后&#xff0c;layui框架的用户飞速下滑&#xff0c;以至于到现在贝格前端工场承接的项目中&#xff0c;鲜有要求使用layui框架的&#xff0c;那么个框架还有人用吗&#xff1f; 一、layui没落是不是jquery惹的祸 layui的没落与jQuery无关。layui框架…

基于springboot+vue+uniapp的贵工程寝室快修小程序

开发语言&#xff1a;Java框架&#xff1a;springbootuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#…

(二)、python程序--基金看板

一、绪论 获取基金数据并展示。 已实现功能&#xff1a; 1、获取基金名称以列表的方式展示&#xff0c;可按照类型筛选&#xff0c;也可以直接搜索&#xff1b; 2、点击左侧基金名称展示日线&#xff0c;移动鼠标竖线跟着移动&#xff0c;并且显示对应日期的基金数据&#…

[数仓]三、离线数仓(Hive数仓系统)

第1章 数仓分层 1.1 为什么要分层 DIM&#xff1a;dimensionality 维度 1.2 数据集市与数据仓库概念 1.3 数仓命名规范 1.3.1 表命名 ODS层命名为ods_表名DIM层命名为dim_表名DWD层命名为dwd_表名DWS层命名为dws_表名 DWT层命名为dwt_表名ADS层命名为ads_表名临时表命名为…

植物大战僵尸融合嫁接版 MAC 版本下载安装详细教程

继植物大战僵尸杂交版火了之后&#xff0c;PVZ改版可谓是百花齐放&#xff0c;最近又有一个非常好玩的模式被开发出来了&#xff0c;他们称为《植物大战僵尸融合嫁接版》 该版本并没有对植物卡牌做改动&#xff0c;而是可以将任意两种植物叠放到一起进行融合&#xff0c;产生新…

(附源码)springboot共享单车管理系统-计算机毕设 65154

springboot共享单车管理系统 摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于共享单车管理系统当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了共享单车管理系…

ES7210高性能四通道音频ADC转换模拟麦克风为IIS数字咪头

特征 高性能多位 Delta-Σ 音频 ADC 102 dB 信噪比 -85 分贝 THDN 24 位&#xff0c;8 至 100 kHz 采样频率 I2S/PCM 主串行数据端口或从串行数据端口 支持TDM 256/384Fs、USB 12/24 MHz 和其他非标准音频系统时钟 低功耗待机模式 应用 麦克风阵列 智能音箱 远场语音捕获 订购…

桑基气泡图 – 5个维度展示KEGG通路富集结果

2022年发表在《Nature communication》上的文章Kir2.1-mediated membrane potential promotes nutrient acquisition and inflammation through regulation of nutrient transporters fig1i使用微生信平台绘制了一张图&#xff0c;我们将其命名为“桑基气泡图”。从此&#xff…

低代码和制造企业数字化转型成功的关系是什么

针对制造企业特别繁多的应用场景、特别大量的数据以及特别复杂的业务流程等特性&#xff0c;低代码能够更贴合制造企业的应用需求&#xff0c;更符合低代码平台为企业带来的价值&#xff0c;即(低代码平台)即服务。 用低代码与平台的融合力量搭建起企业敏捷的数字底座&#xff…

14-22 剑和远方2 - 深度神经网络中的学习机制

概论 在第一部分中&#xff0c;我们深入探讨了人工智能的兴衰简史以及推动人工智能发展的努力。我们研究了一个简单的感知器&#xff0c;以了解其组件以及简单的 ANN 如何处理数据和权重层。在简单的 ANN 中&#xff0c;不会对数据执行特定操作。ANN 中的激活函数是一个线性函…

Node.js_fs模块

文件删除 文件重命名和移动&#xff08;本质都是修改路径&#xff09; 文件夹操作 创建文件夹(mkdir) 读取文件夹(readdir) &#xff08;打印出来是该文件夹下名称的数组形式&#xff09; 读取当前的文件夹(readdir) 删除文件夹 &#xff08;rmdir&#xff09; 查看资源状态…

一家虚拟电厂繁忙的一天

早晨&#xff1a;准备与监控 7:00 AM - 起床与检查 虚拟电厂&#xff08;VPP&#xff09;团队的成员早起&#xff0c;开始检查电力系统的状态和最新的市场动态。使用专用的监控软件&#xff0c;查看分布式能源资源&#xff08;DERs&#xff09;的实时数据&#xff0c;包括太阳…

【Linux】网络新手村

欢迎来到 破晓的历程的 博客 ⛺️不负时光&#xff0c;不负己✈️ 引言 今天&#xff0c;我们就开始学习Linux网络相关的内容。这篇博客作为Linux网络板块的第一篇博客看&#xff0c;我们首先要带着大家明白Linux网络的一些名词的概念&#xff0c;为之后的学习扫清障碍。然后我…

MMM(Master-Master replication manager for MySQL,MySQL主主复制管理器)

概述 MMM&#xff08;Master-Master replication manager for MySQL&#xff0c;MySQL主主复制管理器&#xff09; MMM是一套支持双主故障切换和双主日常管理的脚本程序。MMM 使用 Perl 语言开发&#xff0c;主要用来监控和管理 MySQL Master-Master &#xff08;双主&#xf…

opencv实现目标检测功能----20240704

早在 2017 年 8 月,OpenCV 3.3 正式发布,带来了高度改进的“深度神经网络”(dnn)模块。 该模块支持多种深度学习框架,包括 Caffe、TensorFlow 和 Torch/PyTorch。这次我们使用Opencv深度学习的功能实现目标检测的功能,模型选用MobileNetSSD_deploy.caffemodel。 模型加载…

GD 32中断系统实现

1.0 中断的概念 中断&#xff1a;简单来说就是打断的意思&#xff0c;在计算机系统中CPU在执行一个操作的时候&#xff0c;有一个比当前任务更为紧急的任务需要执行,cpu暂停当前任务转而去执行更为紧急任务的操作&#xff0c;执行完更为紧急任务之后再返回来执行原来未执行完的…

美股交易相关知识点 持续完善中

美股交易时间 美东时间&#xff1a;除了凌晨 03:50 ~ 04:00 这10分钟时间不可交易以外&#xff0c;其他时间都是可以交易的。 如果是在香港或者北京时间下交易要区分两种: 美东夏令时&#xff1a;除了下午 15:50 ~ 16:00 这10分钟时间不可交易以外&#xff0c;其他时间都是可…

1012-27SF 同轴连接器

型号简介 1012-27SF是Southwest Microwave的2.92 mm连接器。该连接器使用不锈钢合金外壳和镀金接触表面提供了良好的耐腐蚀性和耐磨损性&#xff0c;延长了连接器的使用寿命。适用于高频应用&#xff0c;最高可达 40 GHz&#xff0c;使其适用于微波和射频通信、雷达系统等领域。…

14-31 剑和诗人5 - 使用 AirLLM 和分层推理在单个 4GB GPU 上运行 LLama 3 70B

利用分层推理实现大模型语言(LLM) 大型语言模型 (LLM) 领域最近取得了显著进展&#xff0c;LLaMa 3 70B 等模型突破了之前认为可能实现的极限。然而&#xff0c;这些模型的庞大规模给其部署和实际使用带来了巨大挑战&#xff0c;尤其是在资源受限的设备上&#xff0c;例如内存…