【C语言期末不挂科——指针篇1】

C语言指针初阶

文章目录

  • C语言指针初阶
      • **什么是指针?**
          •    **1)初识指针**
          •   **2)地址的大小**
          •   **3)指针变量**
      • **指针的类型**
          •    **1)指针对整数加减运算**
          •   **2)指针的解引用**
      • **野指针**
          •   **1)为什么会有野指针**
          •   **2)如何避免野指针**
      • **指针运算**
          •   **1)指针 + - 整数**
          •   **2)指针-指针**
          •   **3)指针的关系运算**
      • **数组和指针**
      • **二级指针**
      • **指针数组**

前言:

  对于许多正在学习C语言的小伙伴来说,指针可能会让你非常的头疼,很多人不知道如何控制指针变量,甚至都不敢用指针来写代码。但是在实际的开发中还是经常会和指针打交道的,今天我们开启C语言指针系列的章节学习~
在这里插入图片描述


什么是指针?

   1)初识指针

  指针是什么?这个我们先不着急,我们先来模拟一个场景:

  [事件1] 现在,假设你今天要去西藏旅游,到了地方总得有住的地方,于是你去希望旅馆定了一个房间号为302的房间。你是第一次来这个旅馆并不熟悉房间的排列,所以你得一个一个的去找到你的房间。你按着顺序找到了302的房间,并将行李放了进去… [结束]

在这里插入图片描述

  现在就可以回答前面的问题了,指针其实就是地址,事件1的房间号就可看作地址,有了房间号,我们就可以找到对应的房间,将行李都放进房间了。指针也是如此:指针通过地址进而找到对应的内存空间从而进行访问。

  对于指针:

指针是内存中一个最小单元的编号,也就是地址。

  注意 我们平常所说的指针,其实是指 指针变量,是用来存放地址的 变量。

我们也可以这样来理解指针:在这里插入图片描述
  通过指针的地址来找到对应的内存空间。


  2)地址的大小

  我们已经了解了指针就是地址,那么地址又是什么?实际上:

  在计算机运行时,数据会存放在内存中,内存会以 字节 为单位划分为多个存储空间,并且为每个字节默认设置一个对应的编号,这个编号就是地址。

  可能你还会有疑问:“为什么内存会以字节为单位划分呢?”

  其实经过前人的计算与考量,发现一个字节给一个对应的地址是比较合适的。在32的机器上,假设有32根地址线,每根地址线在寻址的时候产生的高低电平就是0和1。

  那么32根地址线产生的地址就会是:

00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
00000000 00000000 00000000 00000002

111111111 111111111 111111111 111111111

  这里就会产生2^32 次方个地址。如果每个地址来标识一个字节,那么我们就能给大约4GB(2^32 Byte = = 2^32 /1024KB = = 2^32/1024/1024MB= =2^32/1024/1024/1024GB = = 4GB)的的空间进行编址了。同样的方式,64位机器能编址多大空间?可以自己算算。

  这里我们就知道了:

1、在32位机器上,地址是32个0或1组成的二进制序列,地址有 4个字节 的空间的大小来存储,所以在32位机器下,一个指针变量的大小就是4字节
2、在64位的机器上,有64个地址线,一个指针变量的大小就是8个字节了


  3)指针变量

  还记不记得我们在学C语言中用到的 ‘&’ 符号?是不是很眼熟?没错,我们经常在scanf函数里面用到这个符号,其实这个符号叫做: 取地址操作符 。顾名思义,就是用来提取变量的地址。

  我们可以通过& 来取出变量的内存地址,把地址可以存放到一个变量中,这个变量就是指针变量

#include<stdio.h>

int main()
{
	int a = 10;//整形大小为4个字节
	int *p = &a;//取变量a的地址赋给指针变量p,虽然整形大小为4个字节
	//但是指针存储的仅仅是四个字节中的第一个起始字节
	 
	return 0;
}

  总结

1、 指针变量是用来存放地址的
2、 在32位平台下,指针大小为4字节,在64位平台下,指针大小为8字节


指针的类型

  看到标题你可能会有些疑问:既然我们的指针只能保存一个字节的内容,我们为什么还要给指针分为不同的类型呢?

  实际上,我们规定指针这样定义:

int a = 0;
int *p = &a;

float b = 0;
float *pb = &b;

double c = 0;
doublr *pc = &c;
//...

  我们可以看到,指针变量的 定义方式为:类型 + * 而指针前面的类型表示指针的类型,我们可以看到,指针的类型有,int,double,float…我们常用的类型都有对应的指针类型。

  那这些指针类型究竟有什么用呢?代表什么意思呢?


   1)指针对整数加减运算

  我们来看这样一段代码:

#include<stdio.h>

int main()
{
	int a = 1;
	char *pa1 = (char *)a;//既然指针只保存一个字节的值,那我们不妨直接把int强转成char
//只取int的首个字节的地址进行操作看看会发生什么? 
	int *pa2 = &a;//将未强转的类型也用指针保存,用来做对照 
	
	printf("%p\n", &a);//地址打印用%p 
	printf("%p\n", pa1); 
	printf("%p\n", pa1 + 1);
	
	printf("%p\n", pa2);
	printf("%p\n", pa2 + 1);
	
	return 0;
}

  那么结果会是多少呢?

在这里插入图片描述

  我们发现第一个与第二个和第四个的打印结果是相同的,也就是说他们的起始地址是相同的,第一个和第四个就不用多说,两个是同一个变量取地址打印。

  第二个结果也刚好能验证我们指针取的地址是元素的首个字节的地址。

  可以看到,pa1 + 1的地址要比pa1的地址大了1(16进制),也就是说pa1向后加一就是往后走一个字节的距离。

  再来看pa2与pa2 + 1,这里的差值却为4(十六进制10 - 0C),也就是说pa2加一是跳过了4个字节。我们发现,他们跳过的字节数刚好和指针对应的类型大小相同!这里我们就可以得出结论

指针类型决定了指针向前或向后走一步的步长(距离)


  2)指针的解引用

  我们已经知道了指针如何在内存中工作的,那么我们该如何将指针给用起来呢?其实啊,我们有了变量的地址,保存在指针变量里,接下来就是放行李的过程,也就是对内存空间进行访问。

  [事件2] 你打开了302房间的房门,刚走进去,不禁皱起了眉头,里面的杯子还是乱的,垃圾桶还没清理,甚至地下还有垃圾,你直接去找了酒店前台,前台十分抱歉,于是叫来了保洁阿姨,很快的,你的房间就焕然一新了,上个房客剩下的东西统统清理干净,随后将你的东西放进角落…[结束]

  指针的意义就是为了来管理我们的内存,在C语言中用指针来访问内存有一个专门的运算符:*解引用运算符 ,这里的解引用,就可以对指针指向的内存空间随意访问啦。

用法为:

int a = 0;
int *p = &a;//正常取变量地址

*a = 1;//这就是对指针所指向的内存空间进行访问
//也就是说,指针可以通过解引用来更改变量a的内容

  这里将原来的0通过指针解引用改变为了1,酒店里你发现订的房间居然很乱?现在是你要住进来,你可不管之前住的是谁。这就是通过对指针解引用,来访问内存,可以对于原来的值进行修改。

  注意:初学者总是会搞错指针类型的大小与指针所指向变量的大小关系,指针的 大小永远为4/8个字节。我们来看下面例子:

#include<stdio.h>

int main()
{
	printf("%d\n",sizeof(int *));//sizeof对不同的指针类型求大小
	printf("%d\n",sizeof(char *));
	printf("%d\n",sizeof(short *));
	printf("%d\n",sizeof(long *));
	printf("%d\n",sizeof(float *));
	printf("%d",sizeof(double *));
	//... 
	return 0;
 } 

  得出的结果为:

在这里插入图片描述

  其实说白了指针就是地址,指针可不管你是int、还是double还是什么类型,到我这里都是地址,指针的类型大小是跟指针所指向的类型无关,我的机器为64位机器,所以我的指针大小就一定是8个字节。


  我相信你还有一些疑问:“还是那个问题,既然指针只需要一个字节的地址,那为什么还要分什么类型,我全都是char *不就完了吗?”。

  其实上面我已经解释了为什么指针需要类型,这里在从解引用的角度来分析一下,我们来看下面的例子:

#include<stdio.h>

int main()
{
	int a = 0x44332211;//这里不是地址,而是16进制的数字进行赋值
	int *p = &a;//整形指针取地址
	printf("%x\n",*p);//以十六进制形式打印
	
	char *pa = (char *)&a;//字符指针取地址
	printf("%x\n", *pa);//十六进制打印
	printf("%x\n", *(pa+1));//指针向下一个位置访问
	return 0;
 } 

在这里插入图片描述

  由打印结果我们可以看到:不同类型的指针使用解引用而访问到不同的字节数,这里char*指针只访问了变量a的一个字节,而int*指针访问了变量a的4个字节。

总结:

指针的类型 决定了指针解引用时候有多大权限(访问几个字节数


野指针

  1)为什么会有野指针

  哎呀,指针真好用!我有了谁的地址,我就可以随便来玩了,有一天,你写了这样一段代码:

#include<stdio.h>

int main()
{
	int *p;
	*p = 20;
	
	printf("%d\n", *p);
	return 0;
}

  这个时候在打印:在这里插入图片描述

  哎呀,这里程序怎么挂了?其实,这里没有对指针p进行初始化,他没有保存任何变量的地址。这个指针也是一个局部变量,当局部变量不初始化的时候,内容是随机值。

  既然是随机值,也就是说这里的指针是随机的地址,你说万一这地址里面存的是什么重要数据,你在这里把他改了?是不是就太危险了?!

  这种有越界访问的指针我们统称:野指针

野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)


  除此之外,还有其他导致野指针的原因,我们来看下面代码:

#include <stdio.h>
int main()
{
	int arr[10] = {0};
	int *p = arr;//相当于int *p = &a[0];
 	int i = 0;
	for(i=0; i<=11; i++)
    {
		//当指针指向的范围超出数组arr的范围时,p就是野指针
		*(p++) = i;//先解引用赋值,再后置++使指针指向下一个位置
	}
	return 0;
}

在这里插入图片描述

  在C语言中,数组名表示数组首元素地址,我们将数组的首元素地址给了指针p,我们通过for循环用指针对数组进行访问,这里我们只有10个元素,我们却要访问12次,那么就会发生越界访问问题。

  这里也就会造成指针越界访问的问题,同样,当出了数组之后,指针也会变成随机值,造成越界访问。


  [事件3] 这几天在西藏你玩的很爽,玩够了,也该回家族打理产业了,然后你就想在过了今天晚上,明天就回去,可是当你走到302的房门前,发现你的行李整齐地摆放在地下,这个时候你才想到,原来房间今天早上就到期了…身上的钱也只够回家了,看来今天只能露宿街头了…[结束]

  除了上面的情况之外,我们还有一种常见的导致野指针的问题:

#include<stdio.h>

int *Test()
{
	int a = 1;
	int *p = &a;
	return p;
}

int main()
{
	int *ret = Test();
	*ret = 2;
	printf("%d\n", *ret);
	return 0;
}

  我们来仔细分析一下:从main函数开始,第一个语句直接进入到Test函数里,那么Test函数会在函数栈帧上开辟一块空间,变量a也开了一块空间,指针变变量p也开辟一块空间用来记录a的地址。

  在函数调用结束的时候,会创建一个临时变量记录返回值,函数栈帧销毁,变量a和指针变量p都销毁了,临时变量被返回值传到main函数的ret。

  那么ret就记录下了这个地址,我们对ret解引用赋值,但是这个时候Test函数已经销毁了,里面的变量的值已经回收了,这个时候再去访问这个已经回收的地址,那么肯定会发生越界访问的。也就是说,你的房间已经被退房了,这个时候你还想去302,就是非法的了。

  总结:

1、野指针会造成越界访问的问题,因此对于指针控制范围非常重要。
2、已经回收资源的地址,再次访问这个地址就是非法访问。


  2)如何避免野指针

  由上面的学习我们知道指针玩不好代价是很大的,那么有没有什么办法防止指针越界等问题呢?要想玩好指针,你必须要记住这五个点:

1、指针一定要初始化
2、小心指针越界
3、指针指向的空间释放,及时将这个指针置为NULL
4、避免返回局部变量的地址
5、指针使用之前要检查有效性

  指针在使用之前一定要初始化,如果没有需要引用的对象,就将指针置为NULL,如下:

#include<stdio.h>

int main()
{
	int a = 10;
	int *p = &a;
	
	int *ptr = NULL;
	 
	return 0;
}

  这里的NULL我们可以转到定义来看一下:

  我们可以看到,在c++中的NULL就是0,在C语言中NULL的类型就是(void *)空指针类型,严格来说C语言的NULL是更加正确的。

  牢记这5点,妈妈就再也不用担心我的指针老是出错了。


指针运算

  我们已经理解指针的基本功能了,除了上面的基本功能,指针还有一个很重要的东西———指针运算。

  1)指针 + - 整数

  我们前面已经学过,指针加上整数就是跳过整数倍指针类型个字节,就像:

#include<stdio.h>

int main()
{
	int a = 0x44332211; 
	char *p = (char *)&a;
	
	printf("%x\n", *p);
	printf("%x\n", *(p + 1));
	printf("%x\n", *(p + 2));
	printf("%x", *(p + 3));
	return 0;
 } 

在这里插入图片描述

  指针加上整数除了可以进行读取数据以外,还可以连续的存储数据,我们看下面代码:

#include<stdio.h>

#define N 5//数组元素个数

int main()
{
	int arr[N] = { 0 };
	int *parr = NULL;//指针用来保存数组首元素地址

	for(parr = &arr[0] ; parr < &arr[N] ; )//将数组首元素地址赋值、小于判断条件就一直执行
	{
		*parr++ = 1;//指针解引用对内存空间进行赋值,随后+1指向下一个位置
	}
	
	int i = 0;
	for(i = 0 ; i < N ; i++)//打印出来数组里的值看看是否改变
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

在这里插入图片描述

  我们用指针解引用访问对应的内存空间从而完成了赋值操作。这种是指针parr的位置一直在变化,如果不想要指针的位置,我们可以这样写:

#include<stdio.h>

#define N 5

int main()
{
	int arr[N];
	int *parr = &arr[0];

	int sz = sizeof(arr) / sizeof(arr[0]);//sizeof(数组名)求出整个数组的字节大小
//然后再除上一个元素的大小,就是数组元素的个数。sizeof(arr) == N
	int i = 0;
	for(i = 0 ; i < sz ; i++)
	{
		*(parr + i) = 1;
	}

	for(i = 0 ; i < N ; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

在这里插入图片描述

  这样就能控制指针的地址不变,而完成数组元素的赋值了。

  总结:

  指针加减整数的意义就是指针跳过了 指针类型大小*整数 个字节,进而访问对应的内存空间。


  2)指针-指针

  我们来看下面的代码:

#include<stdio.h>

int main()
{
	int arr[10] = { 0 };
	printf("%d\n", &arr[9] - &arr[0]);
	return 0;
}

  这里两个指针相减,你来思考一下,得出的结果是多少?相信聪明的你能很快的得出正确的答案。我们直接来看结果:

在这里插入图片描述

  答案是9,不知道你想对了没有,我们取了数组元素的第10个元素地址,与第一个元素地址作差,得出来的结果是9,正好就是两个数组元素的距离。

  但是如果是这两种情况:

#include<stdio.h>

int main()
{
	int arr[10];
	double a = 1;
	int *ptr1 = &arr[0];
	double *ptr2 = &a;
	printf("%d", ptr1 - ptr2);
}

在这里插入图片描述

  如果采用了不用类型的参数进行相减,就会报错,而且最好是像数组这种连续的内存空间使用指针相减,否则相减出来的值是几乎没有什么意义的。

  总结:

  1、指针-指针得到的就是指针和指针之间元素的个数。
  2、两个指针相减的前提是他们的类型必须相同。
  3、指针相减的到时元素的个数,所以在连续的内存空间下相减是比较有意义的,不推荐两个毫不相关的指针相减,因为几乎没什么意义。


  3)指针的关系运算

  我们的地址是有大小的,有高低地址之分,而指针的关系运算就是比较指针的大小。我们来看下面的代码:

#include<stdio.h>

#define N 5

int main()
{
	int arr[N] = { 1 };
	int *parr = NULL;

	for(parr = &arr[5] ; parr > &arr[0] ; )
	{
		*--parr = 0;
	}
	
	int i = 0;
	for(i = 0 ; i < N ; i++)
	{
		printf("%d ", arr[i]);
	}
	
	return 0;
}

  数组一共有5个元素,将数组元素全部初始化为1,随后我们将数组的最后一个元素的地址放进指针变量parr里面,我们准备使数组中的元素从后往前进行赋值,将数组中的元素全部赋值为0。

  详细的工作原理如下:
在这里插入图片描述
  当然你的for循环里也可以这样写:

for(parr = &arr[5] ; parr >= &arr[0] ; parr--)//这两种方式都是相同的
{
	*parr = 0;
}

  得到的结果同样是:

在这里插入图片描述

  指针的比较还有一个要点:就是只能向后比较,但是不能向前比较,如下图:

在这里插入图片描述

  C语言规定了:允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。


数组和指针

  指针和数组是什么关系呢?我们前面也使用了数组名作为首元素地址,那么数组与指针究竟有着什么样的渊源呢?大型纪录片之《指针与数组的故事》持续为您播出…

  指针变量就是指针变量,不是数组指针变量的大小为4/8个字节,专门用来存放地址的。数组也就是数组,不是指针,数组有一块连续的内存空间,可以存放1个或多个类型相同的数据

  我们来看下面的代码:

#include<stdio.h>

int main()
{
	int arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	int len = sizeof(arr)/sizeof(arr[0]);
	
	int *p = arr;//指向数组首元素地址
	int i = 0;
	for(i = 0 ; i < len ; i++)
	{
		printf("%p == %p\n",p + i, &arr[i]);
	}
	return 0;
}

在这里插入图片描述
  我们可以看到,数组与指针的地址全部都是对应的,一模一样,所以说,数组名就是首元素地址,那么以后你就可以不使用[]来访问数组的内容了,可以使用指针 + 偏移量 的方式来访问数组元素:

int a[1000];
int *p = arr;
for(int i = 0 ; i < sizeof(arr)/sizeof(arr[0]) ; i++)
{
	*(p + i) = 1;//i就为偏移量
}

  数组与指针的联系

  前面我们也用到了,数组名就是首元素地址,数组名 == 地址 == 指针 ,当我们知道数组首元素的地址的时候,又因为数组是连续存放的,所以通过指针就可以遍历访问数组,前面也演示过了,数组可以通过指针来访问

  数组名就是数组的首元素地址,但是在这两个情况下是例外的

//sizeof(数组名)  sizeof数组名是直接得到整个数组的字节大小
//& 数组名		&数组名 如果进行+1操作是直接跳过一整个数组

  其余的情况数组名就是首元素地址。


二级指针

  指针的基本用法我们大概了解了,但是我们了解的是 “一级指针” 的用法,其实还存在着二级指针、三级指针…多级指针,因为二级指针用的最多,所以我们在这里主要阐述二级指针,其他指针的情况类比就行了。

  那么究竟什么是二级指针呢?我们先来看我们日常所说的一级指针:

int a = 0;
int *pa = &a;//这里的指针pa就是一级指针

  我们再来看看二级指针:

int a = 0;
int *pa = &a;//这里的指针pa就是一级指针

int **ppa = &pa;//这里为二级指针

  我们要理解一个东西,指针变量也是变量 啊,既然是变量,那么就一定有内存空间来存储指针变量,而二级指针就是取一级指针变量的地址 的指针。如下图:

在这里插入图片描述

  这里二级指针的两个*可以这么来理解:int **是种类型,而我们可以把int ** 看成int* * 前面的int*是指向变量的类型,也就是一级指针(一级指针的类型为int *),而你本身是二级指针,指针的类型必须是int *,加上一级指针的类型int* 就是int ** 。

  同样,三级整形指针的返回类型就为int ***,多级指针以此类推…我们来看下面代码:

int a = 0;
int *p = &a;//一级指针
int **pp = &p;//二级指针

  现在我们想通过二级指针来修改变量a的值,我们该如何做?我们是如何由一级指针访问变量内存的?使用解引用来访问:

*p = 1;//以上面代码为续接

  那我们二级指针解引用就找到了一级指针的地址,然后我们在解引用一次,不就可以访问变量a了吗?

* *pp = 100;//两次解引用,第一次解引用找一级指针内存,第二次解引用就访问到变量a了

  以上就是二级指针的具体用法了,多级指针以此类推。


指针数组

  在我们C语言中存在着这样一个东西————指针数组 ,那么请你思考一下,指针数组究竟是指针呢还是数组呢?

  答:是一个数组,用来存放指针的数组。

  我们知道,数组有不同的类型,有int型数组,double型数组、char型数组…

在这里插入图片描述
  那么我们的指针数组呢?刚才我们也回答了,指针数组里面存放的都是指针变量,那这里的数组名其实就是二级指针了。

在这里插入图片描述

  我们来看下面代码:

#include<stdio.h>

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "talk is cheap";
	char arr3[] = "show me code";
	
	char *parr[] = { arr1, arr2, arr3 };
	char **p = parr;
	return 0;
 } 

  我们可以通过指针p来访问数组中的元素的指向。
在这里插入图片描述
  字符指针数组的每个值的类型都是char*,而数组名就为数组的首元素地址,首元素为指针,所以数组名就是二级指针。

 ; 这里我们用二维数组的方式打印出各个数组里的字符串,我们只需要:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main()
{
	char arr1[] = "abcdef       ";
	char arr2[] = "talk is cheap";
	char arr3[] = "show me code ";
	
	char *parr[] = { arr1, arr2, arr3 };
	char **p = parr;
	
	int len = strlen(arr1);
	int i = 0;
	for(i = 0 ; i < 3 ; i++)
	{
		int j = 0;
		for(j = 0 ; j < len ; j++)
		{
			printf("%c",parr[i][j]);//通过[]来访问下标
		}
		printf("\n");
	}
	return 0;
 } 

在这里插入图片描述

  我们可以看到,完全可以用二级指针来模拟二维数组。其实在第二层的for循环里面我们可以这样改:

for(j = 0 ; j < len ; j++)
{
	printf("%c",*(parr[i] + j));
}
printf("\n");

  先由数组名可以访问每个元素,而每个元素的类型都是char*所以我们可以使用偏移量来对每个指针变量所指向的数组进行访问。当然,这里还有其他的写法可以支持访问,大家可以自由的探索。


  感谢你能看到这,这期就到这里啦,如果还想看后续内容就给博主点点关注!C语言指针篇正在持续更新~~在这里插入图片描述

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

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

相关文章

河北大学选择ZStack Cube超融合一体机打造实训云平台

河北大学通过云轴科技ZStack Cube超融合一体机构建校园实训云平台&#xff0c;部署测试仅耗时1天&#xff0c;该平台能够更快地为学生提供高性能、高可用的云主机、云存储和云网络服务&#xff1b;同时也能满足日常运维管理要求&#xff0c;为学生提供更好的实训环境。 河北省…

什么是NoSQL?什么是redis?redis是做什么的?

redis官网 NoSQL泛指非关系型数据库&#xff0c;redis是其中的一种&#xff0c;Redis是发展最快的。 什么是NoSQL&#xff1f; NoSQL是一个广义的术语&#xff0c;指的是非关系型数据库&#xff0c;不同于传统的关系型数据库&#xff08;如MySQL、Oracle等&#xff09;。它没有…

(二)Pytorch快速搭建神经网络模型实现气温预测回归(代码+详细注解)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、数据集二、导入数据以及展示部分1.导入数据集以及对数据集进行处理2.展示数据&#xff08;看看就好&#xff09; 三&#xff08;1&#xff09;、搭建网络进…

Diagrams——制作短小精悍的流程图

今天为大家分享的是一款轻量级的流程图绘制软件——Diagrams。 以特定的图形符号加上说明&#xff0c;表示算法的图&#xff0c;称为流程图或框图。流程图是流经一个系统的信息流、观点流或部件流的图形代表。我们常用流程图来说明某一过程。 流程图使用一些标准符号代表某些类…

计算数组中每个元素的立方根numpy.cbrt()

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 计算数组中每个元素的立方根 numpy.cbrt() [太阳]选择题 请问以下代码中执行语句输出结果是&#xff1f; import numpy as np a np.array([1, 8, 27]) print("【显示】a ",a) pr…

二维码智慧门牌管理系统升级,异常门牌聚合解决方案助力高效管理

文章目录 前言一、异常门牌聚合解决方案 前言 在今天的数字化时代&#xff0c;智慧城市已成为发展趋势&#xff0c;其中二维码智慧门牌管理系统扮演着至关重要的角色。通过对门牌信息进行数字化管理&#xff0c;该系统极大提升了城市管理的效率和便捷性。然而&#xff0c;随着…

QMenuBar和QToolBar使用同一个QAction

文章目录 前言一、编辑QMenuBar二、将QMenuBar中的Action添加到toolbar总结 前言 qmenubar中的action添加到toolbar&#xff0c;不是在toolbar中再添加action&#xff0c;效果图如下 一、编辑QMenuBar 正常编辑QMenuBar&#xff0c;以下图为例 二、将QMenuBar中的Action添…

logistic回归后快速绘制亚组森林图!SCI发表级高清图片分分钟生成!

本周为大家重点介绍一下风暴统计平台的最新板块——亚组森林图&#xff01; 现在亚组分析好像越来越流行&#xff0c;无论是观察性研究还是RCT研究&#xff0c;亚组分析一般配备森林图。 比如这张图&#xff1a; 还有这个&#xff1a; 森林图不仅是画图的画法&#xff0c;背后还…

算法 LeetCode 题解 | 有效的括号

大家好&#xff0c;我是木川 一、题目描述 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。…

Java源码分析:Guava之不可变集合ImmutableMap的源码分析

原创/朱季谦 一、案例场景 遇到过这样的场景&#xff0c;在定义一个static修饰的Map时&#xff0c;使用了大量的put()方法赋值&#xff0c;就类似这样—— public static final Map<String,String> dayMap new HashMap<>(); static {dayMap.put("Monday&q…

Apache Airflow (十) :SSHOperator及调度远程Shell脚本

&#x1f3e1; 个人主页&#xff1a;IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 &#x1f6a9; 私聊博主&#xff1a;加入大数据技术讨论群聊&#xff0c;获取更多大数据资料。 &#x1f514; 博主个人B栈地址&#xff1a;豹哥教你大数据的个人空间-豹…

【计算机网络笔记】ICMP(互联网控制报文协议)

系列文章目录 什么是计算机网络&#xff1f; 什么是网络协议&#xff1f; 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能&#xff08;1&#xff09;——速率、带宽、延迟 计算机网络性能&#xff08;2&#xff09;…

农户建档管理系统的设计与实现-计算机毕业设计源码20835

摘 要 随着互联网趋势的到来&#xff0c;各行各业都在考虑利用互联网将自己推广出去&#xff0c;最好方式就是建立自己的互联网系统&#xff0c;并对其进行维护和管理。在现实运用中&#xff0c;应用软件的工作规则和开发步骤&#xff0c;采用Java技术建设农户建档管理系统。 本…

项目技术复盘

背景 该项目接手时已是8月中下旬&#xff0c;并且客户要求九月中旬输出第一版本。这么紧急的节奏&#xff0c;不知道商务是如何答应的。临危受命&#xff0c;让我承担开发经理岗位&#xff0c;主导该项目。 开发团队 岗位 人员 base 架构师兼高级软件工程师 季工 上海 高…

Java中利用OpenCV进行人脸识别

OpenCV 概述 ​ OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源计算机视觉库&#xff0c;它提供了丰富的工具和算法&#xff0c;用于处理图像和视频数据。该库由一系列高效的计算机视觉算法组成&#xff0c;涵盖了许多领域&#xff0c;包括目…

C++单调向量算法:132 模式解法三枚举1

本题不同解法 包括题目及代码C二分查找算法&#xff1a;132 模式解法一枚举3C二分查找算法&#xff1a;132 模式解法二枚举2代码最简洁C二分查找算法&#xff1a;132 模式解法三枚举1性能最佳C单调向量算法&#xff1a;132 模式解法三枚举1 分析 时间复杂度 2轮循环时间复杂…

「引流工具」火炬多平台多功能引流高效推广脚本,抖音+快手+小红书多平台自动引流软件

全自动多平台多功能引流脚本&#xff1a; 脚本支持斗音&#xff0c;快手&#xff0c;小红薯&#xff0c;扣扣。默默&#xff0c;弹弹&#xff0c;金日头条&#xff0c;微博&#xff0c;知乎&#xff0c;bibi&#xff0c;易车&#xff0c;最右&#xff0c;美团&#xff0c;汽车…

微软正式宣布其首款人工智能芯片 Maia 100 及基于 Arm 的通用计算芯片 Cobalt 100

微软确认了此前的传闻&#xff1a;该公司已自主开发了 AI 芯片&#xff0c;旨在训练大型语言模型&#xff0c;减少对 Nvidia 的依赖。此外&#xff0c;微软还研制了自家的基于 Arm 架构的 CPU&#xff0c;专为云计算工作负载设计。这两款定制硅芯片旨在为其 Azure 数据中心提供…

Axure基础详解二十:中继器随机抽奖效果

效果演示 组件 一、中继器 建立一个“中继器”内部插入一个“正方形”&#xff0c;给“正方形”添加一个【样式效果】>>【选中状态】填充背景为红色&#xff0c;字体白色。在中继器表格中插入两列数据函数&#xff1a;【xuhao】(序号列&#xff0c;按12345……填写&…

【DevOps】Git 图文详解(二):Git 安装及配置

Git 图文详解&#xff08;二&#xff09;&#xff1a;Git 安装及配置 1.Git 的配置文件2.配置 - 初始化用户3.配置 - 忽略.gitignore Git 官网&#xff1a;https://www.git-scm.com/ 下载安装包进行安装。Git 的使用有两种方式&#xff1a; 命令行&#xff1a;Git 的命令通过系…