【C语言】指针篇(指针数组,数组指针,函数指针,一级、二级指针)

文章目录

  • 一、指针基础
    • 1.什么是指针
    • 2.指针的定义和初始化
    • 3.指针的解引用
    • 4.野指针和空指针
    • 5.指针的类型
    • 6.指针的大小
    • 7.指针的运算
    • 8.指针和数组
    • 9.指针和字符串
    • 10.二级指针
  • 二、指针数组和数组指针
    • 1.指针数组
    • 2.数组指针
    • 3.练习
  • 三、数组传参和指针传参
    • 1.一维数组传参
    • 2.二维数组传参
    • 3.一级指针传参
    • 4.二级指针传参
  • 四、函数指针
  • 五、函数指针数组
  • 六、指向函数指针数组的指针
  • 七、回调函数

一、指针基础

1.什么是指针

C语言中指针是一种数据类型,指针是存放数据的内存单元地址。

指针是内存中一个最小单元(1个字节)的编号,也就是地址
平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量

我们可以通过&(取地址操作符)取出变量的内存其实地址,把地址可以存放到一个变量中,这个
变量就是指针变量。

后面提到的指针均是指 指针变量。

总结:指针就是地址。

2.指针的定义和初始化

语法格式:数据类型 *指针变量名[=初始地址值]。

int a = 10;
int *pa = &a;

指针变量除了可以存放变量的地址外,还可以存放其他数据的地址,比如可以存放数组和函数的地址,后面都会讲解。

指针变量的初始化,除了可以是已定义变量的地址,也可以是已初始化的同类型的指针变量,也可以是NULL(空指针)。在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个NULL 值是一个良好的编程习惯。

int *p = NULL;

3.指针的解引用

取地址操作符&和解引用操作符*是搭配使用的。

int a = 10;
int* pa = &a;
printf("%d\n", *pa);

将a的地址通过&存放到指针变量pa中,再对pa解引用找到地址中的内容:a中存放的数据10

4.野指针和空指针

空指针:指针赋值为NULL,不指向任何空间。

对指针解引用操作可以获得它所指向的值。但从定义上看,NULL指针并未指向任何东西,因为对一个NULL指针解引用是一个非法的操作,所以在解引用之前,必须确保它不是一个NULL指针。

野指针:

野指针就是指针指向的位置是不可知的。

野指针是学习C语言中比较常犯的一个错误,野指针分为三种:

1.指针未初始化就使用

int *p;//局部变量指针未初始化,默认为随机值
*p = 10;

2.指针越界访问

#include <stdio.h>
int main()
{int arr[10] = { 0 };int* p = arr;for (int i = 0; i <= 11; i++){//当指针指向的范围超出数组arr的范围时,p就是野指针*(p++) = i;}return 0;
}

3.指针指向的空间释放后未置空

指针指向的空间释放后指向的就是无效内存,这时指针应立即置NULL,不然会成为野指针。
具体内容等后面动态内存开辟的时候总结。

规避野指针:

  1. 指针初始化
  2. 小心指针越界
  3. 指针指向空间释放,及时置NULL
  4. 避免返回局部变量的地址 (当被调函数结束后 ,栈区中局部变量的内存空间被释放)
  5. 指针使用之前检查有效性 (是否为NULL)

5.指针的类型

指针的类型与指针指向的类型是不一样的,一定要区分清楚!

从语法的角度看,只要把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。这是指针本身所具有的类型。
把指针声明语句中的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。

例如:

int* ptr; //指针的类型是int*	 指针所指向的类型是int
char* ptr;//指针的类型是char*  指针所指向的类型是char
int** ptr;//指针的类型是int**  指针所指向的类型是int*

指针的类型决定了指针向前或者向后走一步有多大距离

在这里插入图片描述

char* 类型的指针存放 char 类型变量的地址,每走一步跳过一个char类型即1个字节。
short* 类型的指针存放 short 类型变量的地址,每走一步跳过一个short类型即2个字节。
int* 类型的指针存放 int 类型变量的地址,每走一步跳过一个int类型即4个字节。

6.指针的大小

对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平和低电平(1或者0),那么32根地址线产生就会产生2^32 次方个地址,内存中是以字节为单位的,也就是会有 2^32 个字节。2^32 Byte = 2^22 KB = 2^12 MB = 4GB 的空间进行编址;同样64位机器中可以编址8GB空间。

所以32位平台上,一个指针变量的大小就是4字节;64位平台上是8字节。

7.指针的运算

指针 + - 整数: 上面分析指针的类型中提过,指针的类型决定了指针+1或者-1移动的距离就是指针所指向类型的大小。比如:int* 类型的指针+1 则往后走了4个字节,char* 类型指针-2 则往前移动了2个字节。

指针 - 指针:两个指针相减代表指针之间所经历的元素(由参与运算的指针类型决定)个数
例如写一个求字符串长度的函数:

int my_strlen(char *s)
{char *p = s;while(*p != '\0' ){p++;}return p-s;
}

8.指针和数组

前面讲到过,指针的类型决定了指针向前或者向后走一步有多大距离,比如:char* 类型的指针存放 char 类型变量的地址,每走一步跳过一个char类型即1个字节;int* 类型的指针存放 int 类型变量的地址,每走一步跳过一个int类型即1个字节。 所以,我们可以也通过指针来访问数组

#include<stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int* p = arr;//数组首元素的地址存放p中for (int i = 0; i < 10; i++){//printf("%d ", arr[i]);或者printf("%d ", *(arr + i));printf("%d ", *(p + i));//printf("%d ", p[i]);也是正确的}return 0;
}

上述中四种写法都是正确的,在数组篇我们了解到,除了&(数组名)和sizeof(数组名)这两种特殊情况外,其他情况下数组名表示首元素的地址指针变量p也表示数组首元素的地址,所以这四种写法本质上都是一样的。

9.指针和字符串

char* ps = "abcdef";
printf("%s\n", ps);
char s[] = "abcdef";
char* ps = s;
printf("%s\n", ps);

注:并不是将字符串赋予指针变量,而是将存放字符串的连续内存单元的首地址赋予指针变量。

看下面这道例题:

在这里插入图片描述

p1和p2指向的是一个同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当
几个指针指向同一个字符串的时候,他们实际会指向同一块内存。所以p1和p2相等。
但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块(数组存放在栈区),所以s1与s2的地址不同。

可修改性

char* ps = "hello";
p[1] = 'a';//错误char str[] = "hello";
str[0] = 'w';//正确

因为ps指向的是一个字符串常量,字符串字面量通常存储在程序的只读内存区域(如常量区),因此不能修改。而str是一个字符数组,是存储在栈上的,可以被修改。

10.二级指针

指针变量存放其他数据的地址,而指针变量的地址是存放在二级指针中。

#include<stdio.h>
int main()
{int a = 0;int* pa = &a;int** ppa = &pa;**ppa = 25;printf("%d\n", a);printf("%d\n", *pa);printf("%d\n", **ppa);return 0;
}

**ppa = *(*ppa) = *pa = a
:二级指针指向的类型是指针类型,所以二级指针+1等于加上4字节(32位)或者8字节(64位)

二、指针数组和数组指针

1.指针数组

指针数组是数组,数组指针是指针,只需要看末尾名词确定类型。

指针数组的定义

指针数组就是存放指针的数组,本质上是数组。

例如:

int* arr[5];

arr是一个数组,数组中有5个元素,每个元素的类型是int*整型指针。

首先,通过前面操作符篇我们知道[]的优先级比* 高,所以arr先与[]结合,确定是一个数组,数组中每个元素是都是指向int类型的指针,所以是指针数组。

指针数组的使用

#include<stdio.h>
int main()
{int arr[3][5] = { 1,2,3,4,5,6,7,8 };int* p[3] = { arr[0], arr[1], arr[2] };for (int i = 0; i < 3; i++){for (int j = 0; j < 5; j++){printf("%d ", p[i][j]);//printf("%d ", *(*(p + i) + j));}printf("\n");}return 0;
}

p首先是一个数组,数组中的3个元素是int*类型,将二维数组的每一行元素的首地址赋给p中各元素初始化,p的用法相当于一个二维数组。

在这里插入图片描述

2.数组指针

数组指针的定义

数组指针就是指向数组的指针,本质上是指针。

例如:

int (*arr)[5];

由于[]的结合性比*高,所以加上()使arr先与*结合,表示arr是一个指针,这个指针指向的类型是int[5],即指向一个长度为5的整型数组,所以是数组指针。

数组指针的使用

一维数组

#include<stdio.h>
int main()
{int arr[10] = { 1,2,3 };int (*p)[10] = &arr;for(int i = 0; i < 10; i++)printf("%d ", (*p)[i]);return 0;
}

*p相当于*(&arr) = arr 数组首元素的地址 或者由定义可得*p的类型是int[10],即数组

二维数组

#include<stdio.h>
int main()
{int arr[3][5] = { 1,2,3,4,5,6,7,8 };int(*p)[5] = arr;for (int i = 0; i < 3; i++){for (int j = 0; j < 5; j++){printf("%d ", p[i][j]);//printf("%d ", *(*(p + i) + j));}printf("\n");}return 0;
}

p首先是一个指针,指向一个整型数组,这个数组中有5个int类型的数据,所以p+1是跳过这个数组即跳过5个int类型的大小,而通过前面数组篇我们知道二维数组在内存中是连续存储的,也就是说二维数组的下一行首元素的地址是与上一行末尾元素的地址相邻的。所以数组指针p可以用来访问二维数组。
在这里插入图片描述

3.练习

指针数组和数组指针已经了解过了,我们来做几个练习:

指针数组

int* p1[10];

p1是一个数组,数组中有10个元素,每个元素的类型是int*

数组指针

int(*p2)[10];

p2是一个指向数组的指针,指向的数组中有10个元素,每个元素的类型是int

数组指针数组

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

p3先与[10]结合是一个数组,数组中有10个元素,每个元素的类型是int(*)[5]
p3是一个存放数组指针的数组

指针数组指针

int* (*p)[5];

p4先与*结合是一个指针,指向一个数组,数组中有5个元素,每个元素的类型是int*,所以这个数组是指针数组。
p4是一个指向指针数组的指针。

如何判断指针的类型呢?

指针的类型中提到过,现在又多加了指针数组和数组指针的判断

把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型;
把指针声明语句中的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。

int* ptr; //指针的类型是int*	 指针所指向的类型是int
char* ptr;//指针的类型是char*  指针所指向的类型是char
int** ptr;//指针的类型是int**  指针所指向的类型是int*
int(*ptr)[10];//指针的类型是int(*)[10] 指针所指向的的类型是int[10]
int*(*ptr)[5];//指针的类型是int*(*)[5] 指针所指向的的类型是int*[5]

例如:
将arr强制类型转换成与p相同类型

int(*p)[10] = (int(*)[10])arr;

三、数组传参和指针传参

数组篇虽然写过,但在这里再强调一遍加深巩固。
通常情况下,我们所说的数组名都是数组首元素的地址,但有两种特殊情况:

1.sizeof(数组名),计算的是整个数组的大小,此处的数组名表示整个数组。
2.&数组名,取出的是整个数组的地址。

1.一维数组传参

#include <stdio.h>
void test(int a[])//√
{}			//数组传参时可以不写元素个数
void test(int a[10])//√
{}			//正常传参
void test(int* a)//√
{}			//数组传参传的是数组首元素的地址,指针就是地址,接收正常
void test(int (*a)[10])//√
{}		//数组指针,指向有10个int元素的数组,符合arr条件,可以接收
void test2(int* a[20])//√
{}			//正常传参
void test2(int** a)//√
{}//arr2是指针数组,所指数组中的元素类型是指针,数组名又是首元素地址,指针的地址用二级指针接收int main()
{int arr[10] = { 0 };int* arr2[20] = { 0 };test(arr);test2(arr2);return 0;
}

2.二维数组传参

二维数组在定义时行数可以省略,但列数不能省略,因为可以根据列数确定行数,但不能根据行数确定列数。
同样,二维数组传参时,函数形参只能省略第一个[]的数字。
因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素,这样方便运算

void test(int arr[3][5])//√
{}			//正常传参
void test(int arr[][])//×
{}		    //不可以省略列数
void test(int arr[][5])//√
{}			//可以省略行数
void test(int* arr)//×
{}			//二维数组传的是第一行数组的地址,数组的地址不能用一级指针来接收
void test(int* arr[5])//×
{}			//这是存放指针的数组,不是指针,也不是二维数组,完全不搭边
void test(int(*arr)[5])//√
{}			//数组指针,指向的数组有5个int元素,可以接收二维数组第一行数组的地址
void test(int** arr)//×
{}			//二级指针是用来接收一级指针的地址的,不能接收数组的地址
int main()
{int arr[3][5] = { 0 };test(arr);
}

所以,二维数组的传参只有三种方式:行列都不省略,只省略列数,用数组指针。

注:数组地址与数组首元素的地址不一样! 数组地址解引用才能得到数组首元素的地址

3.一级指针传参

#include <stdio.h>
void Print(int *p, int sz)
{for(int i=0; i<sz; i++)printf("%d\n", *(p+i));
}
int main()
{int arr[10] = {1,2,3,4,5,6,7,8,9};int sz = sizeof(arr)/sizeof(arr[0]);int *p = arr;//p指向数组首元素的地址Print(p, sz);//一级指针p,传给函数return 0;
}

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

#include <stdio.h>
void test(int* p)
{}
int main()
{int a = 10;test(&a);//变量的地址int* p = &a;test(p);//一级指针int arr[5];test(arr);//数组首元素的地址return 0;
}

4.二级指针传参

#include <stdio.h>
void test(int** ptr)
{printf("num = %d\n", **ptr);
}
int main()
{int a = 10;int* pa = &a;int** ppa = &pa;test(ppa);//传二级指针test(&pa);//传一级指针的地址return 0;
}

当函数的参数为二级指针的时候,可以接收什么参数?

#include <stdio.h>
void test(int** ptr)
{}
int main()
{int* p;test(&p);//一级指针的地址int** pp;test(pp);//二级指针int* arr[10];//指针数组,指向的数组的元素是int*指针类型test(arr);//传的是数组首元素的地址即int*指针类型的地址,可以用二级指针接收return 0;
}

四、函数指针

函数指针就是指向函数的指针变量。
函数指针可以像一般函数一样,用于调用函数、传递参数。

在这里插入图片描述

函数指针的使用

#include <stdio.h>
int Add(int x, int y)
{return x + y;
}
int main()
{int(*pf)(int, int) = Add;//int(*pf)(int, int) = &Add;int ret = pf(3, 5);//int ret = (*pf)(3, 5);两种写法都可以printf("%d\n", ret);return 0;
}

注:&函数名和函数名都表示函数的地址

嘿嘿,来看两段有趣的代码

第一段代码来自《C陷阱与缺陷》

	(*(void (*)())0)();
分析:void(*)() 表示一个函数指针类型,所指函数的参数为空即没有参数,返回类型是void(void(*)())00进行强制类型转换,转换成一个函数指针类型,0被当成一个函数的地址;(*(void (*)())0)() 调用0地址处的函数,该函数的返回值是void,无参

第二段代码:

	void (* signal(int, void(*)(int)))(int);
分析:这是一次函数的声明,声明的函数名叫signal;signal函数的参数有两个,第一个是int类型,第二个是void(*)(int)函数指针类型该指针指向的函数的参数类型是int,返回类型是void;把signal(int, void(*)(int))去掉再看,signal函数的返回类型是一个void(*)(int)函数指针该指针指向的函数的参数类型是int,返回类型是void

不难发现signal函数的返回类型第二个参数类型相同,都是void(*)(int)类型
所以可以给void(*)(int)类型重命名来简化代码;

typedef void(*)(int) pf_t;//错误写法

这样写符合逻辑,但不符合语法,应当这样写

typedef void(*pf_t)(int);
pf_t signal(int, pf_t);

这样就更好理解了:声明一个叫signal的函数,该函数的第一个参数类型是int,第二个参数类型是pf_t,返回类型也是pf_t;而pf_t是一个void(*)(int)函数指针类型,该指针指向的函数的参数是int类型,返回类型是void

五、函数指针数组

把函数的地址存到一个数组中,那这个数组就叫函数指针数组,函数指针数组中存放的是函数的地址。

比如说写一个加减乘除的计算器:

#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[5])(int, int) = { NULL, Add, Sub, Mul, Div };//函数指针数组 存放函数地址int x = 0, y = 0, ret = 0;while (1){printf("***1.Add  2.Sub***\n");printf("***3.Mul  4.Div***\n");printf("***   0.exit   ***\n");printf("请选择功能:->");int input = 0;scanf("%d", &input);if (input >= 1 && input <= 4){printf("请输入两个操作数:->");scanf("%d %d", &x, &y);ret = pf[input](x, y);printf("%d\n", ret);}else if(input == 0){printf("已退出\n");break;}else{printf("输入错误,请重新选择\n");}}return 0;
}

六、指向函数指针数组的指针

指向函数指针数组的指针是一个指针,这个指针指向一个数组,数组的元素都是函数指针

#include <stdio.h>
void test(const char* str)
{printf("%s\n", str);
}
int main()
{//函数指针pfvoid (*pf)(const char*) = test;//函数指针的数组pfArrvoid (*pfArr[5])(const char* str);pfArr[0] = test;//指向函数指针数组pfArr的指针ppfArrvoid (*(*ppfArr)[5])(const char*) = &pfArr;return 0;
}

七、回调函数

回调函数就是一个通过函数指针调用的函数

如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。

注: 回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

简单回调函数示例:

#include <stdio.h>
void test()
{printf("hehe\n");
}
void print_hehe(void(*pf)())
{if (1)pf();
}
int main()
{//test();print_hehe(test);return 0;
}

练习: 使用回调函数,模拟实现qsort函数(采用冒泡的方式)
库函数qsort的使用方法具体请查阅参考手册,这里简单示范下:

#include <stdio.h>
int int_cmp(const void* e1, const void* e2)
{return *(int*)e1 - *(int*)e2;
}int main()
{int a[] = { 1,2,5,6,9,3,8,4,7,0 };int len = sizeof(a) / sizeof(a[0]);qsort(a, len, sizeof(a[0]), int_cmp);for (int i = 0; i < len; i++)printf("%d ", a[i]);return 0;
}

接下来利用回调函数模拟实现qsort函数(万能通用适用于各种类型排序):

#include<stdio.h>
void Swap(char* buf1, char* buf2, int width)
{for (int i = 0; i < width; i++){char tmp = *buf1;*buf1 = *buf2;*buf2 = tmp;buf1++;buf2++;}
}
//整型排序
int int_cmp(const void* e1, const void* e2)
{return *(int*)e1 - *(int*)e2;//被排序元素什么类型就用什么指针
}//指针数组排序
int pa_cmp(const void* e1, const void* e2)
{return strcmp(*(char**)e1, *(char**)e2);
}//改进qsort 排序任意类型的数组
void bubble_sort(void* base, int len, int width, int (*cmp)(const void* e1, const void* e2))
{for (int i = 0; i < len - 1; i++){for (int j = 0; j < len - 1 - i; j++){if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);}}
}int main()
{char* pa[] = { "abce", "bcde", "abcd"};int len = sizeof(pa) / sizeof(pa[0]);bubble_sort(pa, len, sizeof(pa[0]), pa_cmp);for (int i = 0; i < len; i++)printf("%s ", pa[i]);return 0;
}

注:内存中最小存储单元是字节,char类型是1字节大小,所以可以将各种类型的数据拆分成单个字节,通过单个字节地进行调整,可以满足各种类型的排序,实现qsort功能。

总结完毕,指针的内容就到这里,感谢大家的观看。

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

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

相关文章

Maven POM元素解析

这是对Maven中使用的Maven项目描述符的引用。 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/…

GEE:基于CHIRPS数据集的累积降水量影像下载

作者:CSDN @ _养乐多_ 本文将介绍在 Google Earth Engine(GEE)平台上使用“UCSB-CHG/CHIRPS/DAILY”数据集计算某一段时期(某年/某个季节/某月)的累积降雨量图像,并下载。 结果如下图所示, 文章目录 一、核心函数二、代码链接三、完整代码一、核心函数 .sum() // 对影…

02 Php学习:变量

Php 变量声明 Php 变量赋值 在PHP中&#xff0c;变量赋值是指将一个值赋给一个变量。变量赋值是 PHP 中最基本和常见的操作之一&#xff0c;以下是关于变量赋值的详细说明和示例&#xff1a; 变量赋值语法&#xff1a; $variable value;$variable&#xff1a;要赋值的变量名…

【MATLAB源码-第38期】基于OFDM的块状导频和梳状导频误码率性能对比,以及LS/LMMSE两种信道估计方法以及不同调制方式对比。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 块状导频和梳状导频都是用于无线通信系统中信道估计的方法。 块状导频&#xff1a; 定义&#xff1a; 在频域上&#xff0c;块状导频是连续放置的一组导频符号。这意味着所有的导频符号都集中在一个短的时间段内发送。 优点…

php站长在线工具箱源码优化版

环境要求 PHP > 7.4MySQL > 5.6fileinfo扩展使用Redis缓存需安装Redis扩展 源码下载地址&#xff1a;php站长在线工具箱源码优化版.zip

RISC-V特权架构 - 模式切换与委托

RISC-V特权架构 - 模式切换与委托 1 导致模式切换的常见动作2 异常处理规则3 异常处理时模式切换3.1 在U模式下&#xff0c;发生异常3.2 在S模式下&#xff0c;发生异常3.3 在M模式下&#xff0c;发生异常 4 系统调用时模式切换5 中断处理时模式切换 本文属于《 RISC-V指令集基…

PaddleVideo:onnx模型导出

本文节介绍 PP-TSM 模型如何转化为 ONNX 模型&#xff0c;并基于 ONNX 引擎预测。 1&#xff1a;环境准备 安装 Paddle2ONNX python -m pip install paddle2onnx 安装 ONNXRuntime # 建议安装 1.9.0 版本&#xff0c;可根据环境更换版本号 python -m pip install onnxrunti…

GEE:样本点的样式设置

作者:CSDN @ _养乐多_ 本文将介绍在Google Earth Engine (GEE)平台上为样本点设置样式的方法和代码,样本点可以设置成任何颜色,以及7种形状,以便更直观了解数据的分布和特征。 文章目录 一、统一设置样式1.1 示例代码1.2 示例代码链接二、每一类一个样式2.1 示例代码2.2…

7款公司电脑监控软件

7款公司电脑监控软件 研究证明&#xff0c;人们在家办公的效率比在办公室办公的效率低一半&#xff0c;其中原因是缺少监督&#xff0c;即便在公司办公&#xff0c;还存在员工偷闲的时刻&#xff0c;比如聊天、浏览无关网站、看剧、炒股等&#xff0c;企业想提高员工的工作效率…

【Java】maven传递依赖冲突解决

传递依赖的概念&#xff1a; 传递依赖:&#xff1a; A.jar 依赖 B.jar, B.jar 依赖 C.jar, 这个时候我们就说B是A的直接依赖, C是A传递依赖; 传递依赖可能会产生冲突: 联系着上面, 新导入一个jar包D.jar, D依赖C.jar, 但是B依赖的1.1版本, 而D依赖的是1.2版本, 这时候C这个j…

绝地求生:齐贺PUBG七周年!分享你的游玩感受及反馈赢惊喜道具

PUBG七周年庆典火热进行中&#xff0c;特殊道具、周年主题艾伦格上线&#xff01;七周年期间游玩PUBG&#xff0c;在评论区分享你的游玩感受及反馈&#xff0c;即可参与活动赢取夏日浪潮宝箱奖励。 参与方式 齐贺PUBG七周年&#xff01;在评论区分享分享你的七周年游玩感受及反…

鸿蒙OS实战开发:【多设备自适应服务卡片】

介绍 服务卡片的布局和使用&#xff0c;其中卡片内容显示使用了一次开发&#xff0c;多端部署的能力实现多设备自适应。 用到了卡片扩展模块接口&#xff0c;[ohos.app.form.FormExtensionAbility] 。 卡片信息和状态等相关类型和枚举接口&#xff0c;[ohos.app.form.formInf…

谷歌建站用什么程序比较好?

建网站这回事&#xff0c;说容易也容易&#xff0c;现如今市面上建站的程序多如牛毛&#xff0c;哪怕你不会代码也能建一个漂亮的网站&#xff0c;但网站搭建出来是为了什么&#xff1f;是为了获取流量&#xff0c;拉到业务&#xff0c;那么&#xff0c;建站的时候你就要考虑谷…

如何使用校园网——Win10笔记本,台式机互开热点

当我们使用校园网的时候&#xff0c;往往只能连接一个电脑端&#xff0c;但是又想两个机子同时连接WIFI怎么办呢&#xff1f; 当然&#xff0c;前提条件是你先得其中一台电脑有网络哈 1、打开想开共享热点的电脑的设置 A、点击WIN&#xff0c;再点击设置 2、点击网络和Inte…

JavaScript - 请你说一说对随机数的理解

难度级别:初级及以上 提问概率:40% 在前端开发中,随机数的应用场景非常多,而且也是一个常见的考点。例如网页登录的验证码,看似只有4个随机数字加字母的组合,其实这也是随机数的范畴;例如在抽奖算法中,可以用随机数确定用户中奖的概率…

TCP 三次握手与四次挥手面试题(计算机网络)

TCP 基本认识 TCP 头格式有哪些&#xff1f; 序列号&#xff1a;在建立连接时由计算机生成的随机数作为其初始值&#xff0c;通过 SYN 包传给接收端主机&#xff0c;每发送一次数据&#xff0c;就「累加」一次该「数据字节数」的大小。用来解决网络包乱序问题。 确认应答号&a…

Element Plus 表单校验

原理 为 rules 属性传入约定的验证规则&#xff0c;并将 form-Item 的 prop 属性设置为需要验证的特殊键值:model和:rules中字段的名称需要一致 示例&#xff1a; <template><el-form ref"ruleFormRef" :model"ruleForm" :rules"rules&q…

Spring Security——13,认证成功失败注销成功处理器

认证成功&&失败&&注销成功处理器 说明&#xff1a;一、认证成功处理器1.1 自定义成功处理器1.2 配置自定义成功处理器 二、认证失败处理器2.1 自定义失败处理器2.2 配置自定义失败处理器 三、登出成功处理器3.1 自定义登出处理器3.2 配置登出处理器 四、完结撒…

Excel全套213集教程

Excel全套213集教程 包含技术入门93集 图表17集 数据透视35集 公式函数68 基础入门 93节 https://www.alipan.com/s/cMxuPstkS1x 提取码: 77dd 点击链接保存&#xff0c;或者复制本段内容&#xff0c;打开「阿里云盘」APP &#xff0c;无需下载极速在线查看&#xff0c;视…

【C语言】if语句选择题

前言 题目一&#xff1a; 题目二&#xff1a; 题目三&#xff1a; 题目四&#xff1a; 题目五&#xff1a; 题目六&#xff1a; 题目七&#xff1a; 题目八&#xff1a; 前言 关于if语句相关的选择题 题目一&#xff1a; 关于if语句说法正确是&#xff1a;( ) A .if语…