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

news2024/12/24 11:20:11

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语言指针篇正在持续更新~~在这里插入图片描述

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

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

相关文章

基于供需算法优化概率神经网络PNN的分类预测 - 附代码

基于供需算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于供需算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于供需优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神经网络的光滑…

redis实战篇03

附近的商户 我们利用Redis的GEOHash来完成对于地理坐标的操作 UV统计 主要是使用Redis来完成统计功能 用户签到 使用Redis的BitMap数据统计功能 好友关注 基于Set集合的关注、取消关注&#xff0c;共同关注等等功能&#xff0c;这一块知识咱们之前就讲过&#xff0c;这次…

数据库迁移(DBeaver版本)

最近需要做一个数据库迁移&#xff0c; 测试环境开发的差不多了&#xff0c;需要将脚本迁移到生产。 中间了试了一些工具&#xff0c;比如Jetbrain出品的datagrip&#xff0c;这个数据库工具平时还是很好用的&#xff0c;但是数据迁移感觉不是那么好用&#xff0c;所以还是用到…

string类的总结

目录 1.为什么要学习string类 2.string的标准库 3.string类的常用接口说明 1.string类对象的常见构造 2.string类对象的容量操作 3.string类对象的3种遍历方法 3.1 [ ] 下标 3.2 基于范围的for循环 3.3 迭代器 4 string类对象的元素访问 4.1 operator[]&#xff1a; 4.…

ubuntu20.04.1网络图标突然消失,无法上网

故障&#xff1a;打开虚拟机进入Ubuntu系统后&#xff0c;打开火狐浏览器&#xff0c;发现无法连接网络。 解决办法&#xff1a;因为刚接触Linux系统&#xff0c;就在网上找各种资料&#xff0c;试了各种办法无果&#xff0c;最后发现有可能网络配置文件被更改。 打开控制台输…

深信服AC设备用户认证

拓扑图 目录 拓扑图 一. 无需认证 思路&#xff1a;创建用户和组&#xff0c;将无需认证策略和用户绑定 1.创建组&#xff0c;组里添加用户 2. 新建不需要认证策略&#xff0c;将不需要认证策略和用户关联 3.验证 二.密码认证 思路&#xff1a;创建用户和组&#xff0c;并…

windows快捷方式图标变成空白

今天突然有客户说应用程序快捷方式图标变成了空白&#xff0c;就研究了一下&#xff0c;网上找了一下很多都说是什么图标缓存有问题&#xff0c;试过之后发现并不能解决问题。 然后发现用户的文件上都一把黄色的小锁的标志&#xff0c;查了一下说是文件属性里面设置加密之后就会…

深度学习二维码识别 计算机竞赛

文章目录 0 前言2 二维码基础概念2.1 二维码介绍2.2 QRCode2.3 QRCode 特点 3 机器视觉二维码识别技术3.1 二维码的识别流程3.2 二维码定位3.3 常用的扫描方法 4 深度学习二维码识别4.1 部分关键代码 5 测试结果6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天…

Java(一)(引用类型的参数在传递,方法重载,面向对象编程基础)

基本类型和引用类型的参数在传递的时候有什么不同? 基本类型的值传递:参数传输存储的数据值 引用类型的值传递:参数传输存储的地址值 传递数组名字的时候,传递的是数组的地址,change方法可以通过地址直接访问我们在堆内存中开辟的数组,然后改变数组,数组中的元素发生变化 方…

HP惠普光影精灵7笔记本Victus by HP 16.1英寸游戏本16-d0000原装出厂Windows11.21H2预装OEM系统

下载链接&#xff1a;https://pan.baidu.com/s/1LGNeQR1AF1XBJb5kfZca5w?pwdhwk6 提取码&#xff1a;hwk6 可适用的型号&#xff1a; 16-d0111tx&#xff0c;16-d0112tx&#xff0c;16-d0125tx&#xff0c;16-d0127tx&#xff0c;16-d0128tx&#xff0c;16-d0129tx&#…

“升级图片管理,优化工作流程——轻松将JPG转为PNG“

在图片时代&#xff0c;无论是工作还是生活&#xff0c;图片管理都显得尤为重要。批量处理图片&#xff0c;将JPG格式轻松转换为PNG格式&#xff0c;能够使您的图片管理更优化&#xff0c;提高工作效率。 首先&#xff0c;我们进入首助编辑高手主页面&#xff0c;会看到有多种…

键盘方向键移动当前选中的table单元格,并可以输入内容

有类似于这样的表格&#xff0c;用的<table>标签。原本要在单元格的文本框里面输入内容&#xff0c;需要用鼠标一个一个去点以获取焦点&#xff0c;现在需要不用鼠标选中&#xff0c;直接用键盘的上下左右来移动当前正在输入的单元格文本框。 const currentCell React.u…

简单算法——回溯、贪心、动态规划

回溯法 回溯法深度优先剪枝&#xff0c;实质就是用递归代替for循环。 仍然是一种暴力遍历的手段&#xff0c;通常与递归配合使用&#xff0c;用于解决单纯for循环无法处理的问题&#xff0c;比如组合、切割、子集、排列等问题——比如求n个数里的长度为k的组合&#xff0c;需要…

docker 安装mongodb 实现 数据,日志,配置文件外挂

docker 安装mongodb 实现数据&#xff0c;日志&#xff0c;配置文件外挂 1 背景 最近开发了一个评论系统之前用mysql来存储数据&#xff0c;但是考虑到后期业务增大访问量也会增大&#xff0c;为了兼容这种高并发的场景&#xff0c;因此经过多方面的考虑&#xff0c;我们最终…

调试/抓包工具

一、Fiddler【推荐window使用】 介绍&#xff1a;个人认为是 Windows 平台最好用的抓包工具&#xff1b; 下载&#xff1a;Fiddler | Web Debugging Proxy and Troubleshooting Solutions 使用方式&#xff1a;这一篇文章写的很全&#xff0c;认真看完就够用了 Fiddler 抓包工…

FISCO BCOS 3.0【02】配置和使用系统自带的控制台

官方技术文档&#xff1a;https://fisco-bcos-doc.readthedocs.io/zh-cn/latest/index.html 我们在官方技术文档的基础上&#xff0c;进行&#xff0c;对文档中一些不清楚的地方进行修正 控制台提供了向FISCO BCOS节点部署合约、发起合约调用、查询链状态等功能。 第一步. 安…

Linux本地docker一键部署traefik+内网穿透工具实现远程访问Web UI管理界面

文章目录 前言1. Docker 部署 Trfɪk2. 本地访问traefik测试3. Linux 安装cpolar4. 配置Traefik公网访问地址5. 公网远程访问Traefik6. 固定Traefik公网地址 前言 Trfɪk 是一个云原生的新型的 HTTP 反向代理、负载均衡软件&#xff0c;能轻易的部署微服务。它支持多种后端 (D…

Git详解及 github使用

1.1 关于版本控制 开始之前先看一个没有版本控制的例子 1.1.1 本地版本控制 本地版本控制系统 许多人习惯用复制整个项目目录的方式来保存不同的版本&#xff0c;或许还会改名加上备份时间以示区别。这么做唯一的 好处就是简单&#xff0c;但是特别容易犯错。有时候会混淆所在…

市级奖项+1,持安获「创业北京」创业创新大赛优秀奖!

2274个创业项目参赛 历经五个多月的激烈角逐 第六届“创业北京”创业创新大赛 终于圆满落下帷幕 持安科技在北京市总决赛中再创佳绩&#xff01; 荣获制造业赛道优秀奖 本次大赛由北京市人力资源和社会保障局、北京市发展和改革委员会等11家单位联合主办&#xff0c;以“创…

C语言--从键盘输入10个数字放在数组中,并输出

用scanf读取数字的时候要注意&#xff0c;可以输入一个数字&#xff0c;按一下回车&#xff0c;输入一个数字&#xff0c;按一下回车&#xff0c;也可以一次性输入完10个数据。&#xff08;中间可以用空格隔开&#xff0c;系统会自动识别&#xff09; 输出一:每按下一个数字&am…