C语言初阶(6) - 指针

目录

1.指针是什么?

2. 指针和指针类型

2.1 指针 +- 整数

2.2 指针的解引用

3. 野指针

3.1 野指针成因

3.2 如何规避野指针

4. 常量指针和指针常量 (const)

4.1.常量指针

4.2.指针常量

5. 指针运算

5.1 指针+-整数

5.2 指针-指针

5.3指针的关系运算

6. 指针和数组

7.二级指针

8.指针数组


1.指针是什么?

理解指针的两个要点:
1. 指针是内存中一个最小单元的编号,也就是地址。
2. 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量。
总结:指针就是地址,口语中说的指针通常指的是指针变量

我们可以理解:

内存单元 -> 编号 -> 地址 -> 指针

int a = 10;

如果VS2019中的地址存储的内容如下:

地址: 0x032FFB24 -> 地址里面存放的数据(0a 00 00 00)

说明此VS2019是按照小端字节序存储的

//00000000 00000000 00000000 00000101

//     00              00             00             0a

也可以这样理解地址的产生:

32位CPU - 32根地址线 - 物理的电线 - 通电 - 1/0  (产生32个数)

64位CPU - 64根地址线 - 物理的电线 - 通电 - 1/0  (产生64个数)

      对CPU来说,他执行到某个特定的编码数值,就会执行特定的操作。比如2+3,其实就是通过总线把数据2和3从内存里读入,然后放到寄存器上,再用加法器相加这两个数值并将结果放入到寄存器里,最后将这个数值回写到内存中,以此循环往复,一行行执行机器码直到退出。

指针变量
我们可以通过&(取地址操作符)取出变量的内存起始地址,把地址可以存放到一个变量中,这个变量就是 指针变量.
#include <stdio.h>
int main()
{
	int a = 10;//在内存中开辟一块空间
	int* p = &a;//这里我们对变量a,取出它的地址,可以使用&操作符。
	//a变量占用4个字节的空间,这里是将a的4个字节的第一个字节的地址
	//存放在p变量中,p就是一个之指针变量。

    *p = 1;
    printf("%d\n", a);
    return 0;
}
原来a的值是10,通过指针变量pa,解引用也可以改变a的值。
总结:
指针变量,用来存放地址的变量。(存放在指针中的值都被当成地址处理)。
那这里的问题是:
  • 一个小的单元到底是多大?(1个字节)
  • 如何编址?
经过仔细的计算和权衡我们发现一个字节给一个对应的地址是比较合适的。
对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或者0);
那么32根地址线产生的地址就会是:
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
.......
11111111   11111111   11111111   11111111
这里就有 2 32 次方个地址。
每个地址标识一个字节,那我们就可以给
2^32Byte == 2^32/1024KB == 2^32/1024/1024MB==2^32/1024/1024/1024GB == 4GB)
4G 的空闲进行编址。
同样的方法,那 64 位机器,如果给 64 根地址线,那能编址多大空间,自己计算。
这里我们就明白:
在32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储,所以
一个指针变量的大小就应该是4个字节。
那如果在64位机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地
址。
总结:
指针是用来存放地址的,地址是唯一标示一块地址空间的。
指针的大小在 32 位平台是 4 个字节,在 64 位平台是 8 个字节

2. 指针和指针类型

指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址。要搞清一个指针需要搞清指针的四方面的内容:指针的类型、指针所指向的类型、指针的值或者叫指针所指向的内存区、指针本身所占据的内存区。让我们分别说明。

先声明几个指针放着做例子:
例一:

  1. (1)int*ptr;
  2. (2)char*ptr;
  3. (3)int**ptr;
  4. (4)int(*ptr)[3];
  5. (5)int*(*ptr)[4];
2.1.指针的类型

从语法的角度看,你只要把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。这是指针本身所具有的类型。让我们看看例一中各个指针的类型:
(1)int*ptr;          //指针的类型是int*
(2)char*ptr;      //指针的类型是char*
(3)int**ptr;        //指针的类型是int**
(4)int(*ptr)[3];   //指针的类型是int(*)[3]
(5)int*(*ptr)[4];  //指针的类型是int*(*)[4]
怎么样?找出指针的类型的方法是不是很简单?

2.2.指针所指向的类型
当你通过指针来访问指针所指向的内存区时,指针所指向的类型决定了编译器将把那片内存区里的内容当做什么来看待。
从语法上看,你只须把指针声明语句中的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。例如:
(1)int*ptr;         //指针所指向的类型是int
(2)char*ptr;      //指针所指向的的类型是char
(3)int**ptr;        //指针所指向的的类型是int*
(4)int(*ptr)[3];   //指针所指向的的类型是int()[3]
(5)int*(*ptr)[4];  //指针所指向的的类型是int*()[4]
这里可以看到,指针的定义方式是: type + * 。
其实:
char* 类型的指针是为了存放 char 类型变量的地址。
short* 类型的指针是为了存放 short 类型变量的地址。
int* 类型的指针是为了存放 int 类型变量的地址。
在指针的算术运算中,指针所指向的类型有很大的作用。
指针的类型(即指针本身的类型)和指针所指向的类型是两个概念。当你对C越来越熟悉时,你会发现,把与指针搅和在一起的"类型"这个概念分成"指针的类型"和"指针所指向的类型"两个概念,是精通指针的关键点之一。
2.3.指针的值----或者叫指针所指向的内存区或地址

指针的值是指针本身存储的数值,这个值将被编译器当作一个地址,而不是一个一般的数值。在32 位程序里,所有类型的指针的值都是一个32 位整数,因为32 位程序里内存地址全都是32 位长。

指针所指向的内存区就是从指针的值所代表的那个内存地址开始,长度为sizeof(指针所指向的类型)的一片内存区。

以后,我们说一个指针的值是XX,就相当于说该指针指向了以XX为首地址的一片内存区域;我们说一个指针指向了某块内存区域,就相当于说该指针的值是这块内存区域的首地址。

指针所指向的内存区和指针所指向的类型是两个完全不同的概念。在例一中,指针所指向的类型已经有了,但由于指针还未初始化,所以它所指向的内存区是不存在的,或者说是无意义的。
以后,每遇到一个指针,都应该问问:这个指针的类型是什么?指针指的类型是什么?该指针指向了哪里?(重点注意)

那指针类型的意义是什么?
         指针类型决定了指针向前或向后走一步,走多大距离(单位是字节)。
2.4 指针本身所占据的内存区

指针本身占了多大的内存?你只要用函数sizeof(指针的类型)测一下就知道了。在32 位平台里,指针本身占据了4 个字节的长度。指针本身占据的内存这个概念在判断一个指针表达式(后面会解释)是否是左值时很有用。

2.5 指针 +- 整数
#include <stdio.h>
//演示实例
int main()
{
	int n = 10;
	char* pc = (char*)&n;
	int* pi = &n;
	printf("%p\n", &n);
	printf("%p\n", pc);
	printf("%p\n", pc + 1);//增加了1个字节
	printf("%p\n", pi);
	printf("%p\n", pi + 1);//增加了4个字节
	return 0;
}
总结:指针的类型决定了指针向前或者向后走一步有多大(距离)。

举例说明:创建一个数组,存入10个数,利用指针倒着打印出来。

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

	//倒着打印
	int* q = &arr[9];
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *q);
		q--;
	}

	return 0;
}

int* 类型的指针+1 就等于指针向前4个字节。

2.6 指针的解引用

1.指针类型决定了在解引用的是一次能访问几个字节(指针的权限);

字符指针解引用会访问1个字节

char* p  ->  1个字节

整形指针解引用会访问4个字节

//演示实例
#include <stdio.h>
int main()
{
	int n = 0x11223344;
	char* pc = (char*)&n;
	printf("%x\n", *pc);
	int* pi = &n;
	printf("%x\n", *pi);
	*pc = 0;  //重点在调试的过程中观察内存的变化。
	*pi = 0;  //重点在调试的过程中观察内存的变化。
	return 0;
}
总结:
指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。
比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。

3. 野指针

概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
3.1 野指针成因
(1)  指针未初始化
这种问题很常见,如下实例:
#include <stdio.h>
int main()
{ 
 int *p;//局部变量指针未初始化,默认为随机值
    *p = 20;
 return 0;
}

代码int* p没有初始化,所以p变量中存的地址并没有指向我们当前程序的空间,而是指向内存中随机的空间,因此要*p要访问这块内存空间肯定是出错的!

这就是p的野指针。

(2) 指针越界访问

越界访问也很常见,我们平常在遍历数组中,不注意就会遇到这样的问题:

#include <stdio.h>
int main()
{
    int arr[5] = {0};
    int *p = arr;
    int i = 0;
    for(i=0; i<6; i++)
   {
        //当指针指向的范围超出数组arr的范围时,p就是野指针
        *(p++) = i;
   }
    return 0;
}
初始化数组arr,让指针变量p等于数组首元素的地址,数组本身有 5个元素,但是在for循环中确 循环6次,i分别是0 1 2 3 4 5 ,本身i是0~4的,但是循环6次就会导致 非法访问内存,因此第6个数打印出来是随机数,这也是野指针的问题。
(3). 指针指向的空间释放
这个问题也是经常会遇到的问题,具体看下面的例子:
#include<stdio.h>
int* test()
{
	int x = 20;
	return &x;
}
int main()
{
	int* p = test();
	*p = 30;
	return 0;
}

test函数返回值是x的地址,main函数中用指针变量p接收x的地址,但是x变量进入test函数创建,而出了test函数会销毁,这时在改变*p的值,即使用x的地址,则是非法访问了,也会造成野指针的问题。

3.2 如何规避野指针
1. 指针初始化
比如上方的例子中,不能直接int* p, 必须要初始化,int a = 10; int* p = &a;从而规避野指针问题。
2. 小心指针越界问题
在我们使用数组时,一定要注意数组的 元素个数 以及我们所 循环的次数 ,避免粗心而导致的越界访问。
3. 指针指向空间释放及时置 NULL
在我们 不使用指针变量p时 ,int* p = NULL; 置为空,在接下来想要使用p时,用if语句:if(p!=NULL) .........能够很好的避免野指针。
4. 避免返回局部变量的地址
就像上面也指针成因的第三条所举的例子,避免返回局部变量的地址。
5. 指针使用之前检查有效性
像if(p!=NULL) .........就是在检查指针的有效性。
#include <stdio.h>
int main()
{
    int *p = NULL;
    //....
    int a = 10;
    p = &a;
    if(p != NULL)
   {
        *p = 20;
   }
    return 0;
}

4. 常量指针和指针常量 (const)

常量指针和指针常量,ta们都与  const 这个关键字有关,下面举几个例子,看看大家能不能分清其中的区别:
const int* pa = &a;
int const* pa = &a;
int* const pa = &a;
const int* const pa = &a;
4.1.常量指针
常量指针的概念:指针 所指空间的值不能发生改变,不能通过指针解引用修改指针所指向空间的值,但是 指针的指向是可以改的
4.2.指针常量
指针常量的概念:指针本身就是一个常量,即 指针的指向不能发生改变,但是 指针所指向空间的值是可以改变的,可以通过解引用改变指针所指向空间的值。
具体可以理解为:
常量指针这个名字,以指针结尾,所以是具有指针性质的,因此可以改变指向,又因为是常量指针,所以指向的值是常量的,即是不能改变的。
再看指针常量这个名字,以常量结尾,应该具有常量的一些性质,所以自然不能改变指针的指向,只能修改指针所指向的值。
所以怎么区分 const 加到那个位置才叫常量指针,加到哪个位置叫指针常量?
const 如果在*的左边,那就是常量指针;
const 如果在*的右边,那就是指针常量;
为什么要这样记呢,可以思考一下,*在指针中有解引用的作用
//const 放在*的左边(可以理解为const修饰*)
//const 修饰的指针指向的内容,表示指针指向的内容不能通过指针来改变;
//但是指针变量本身是可以改变的。
(不能修改指针所指向空间的值, 但是指针的指向确是没有限制的)
//cosnt 放在*的右边(可以理解为const修饰的是pa)
//const修饰的指针变量本身,指针变量的内容不能被修改;
//但是指针指向的内容是可以通过指针来改变的。
(指针变量不能改变他的指向,但是指针所指向空间的值是不受限制的)
那么上面的几个例子已经有答案了,只需要看cosnt修饰的是*还是指针变量。
常量指针:const int* pa = pa; int const *pa = &a;
指针常量:int* const pa = &a;
如果*左右两边都加上cosnt , 说明这个指针指向和内容都不可改变。

5. 指针运算

5.1 指针+-整数

举例说明指针加减整数的情况:

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

指针变量p是数组第一个元素的地址,用for循环打印数组各个元素,*的优先级高于++,所以每次执行*p打印完数组中元素后,p++在指向数组下一个元素,从而循环5次打印出数组中5个元素。

5.2 指针-指针

指针-指针的操作得到的是指针和指针之间元素个数,当然前提是两个指针必须指向同一块空间;举个栗子说明:

#include<stdio.h>
int main()
{
	int arr[8] = { 1,2,3,4,5,6,7,8 };
	int* p1 = &arr[0];
	int* p2 = &arr[7];
	printf("%d\n", p2 - p1);
	return 0;
}

如图所示表示数组中8个元素在内存中的存储,其中p1指向数组的第一个元素的地址,p2指向数组的第八个元素的地址,p2-p1,表示两个指针之间的元素个数,可以看到间隔7个元素,所以打印结果为7。

5.3指针的关系运算

指针的运算关系就是指针之间进行大小的比较,从而实现某些功能,例如:

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

如图所示即为指针的关系运算,下方所画的图可以清楚的解释: 

p刚开始是数组首元素的地址,接着通过p<&arr[8]的比较,满足则打印该地址的下的元素,接着p++,进行下一轮的比较,直到不满足p<&arr[8]为止。

这里可能有人会疑惑,上文说到不能越界吗,数组只有8个元素,下标最大为7,怎么可以使用arr[8]呢,其实这里并没有越界,上文是使用了越界的地址,已经非法访问内存了,而这里只是将这个地址写出来,和指针变量p进行关系运算,并没有使用这个地址,所以并不存在野指针的问题。

规定:允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较(如上方例子),但是不允许与指向第一个元素之前的内存位置的指针相比较。

6. 指针和数组

看一个例子:

#include <stdio.h>
int main()
{
 int arr[10] = {1,2,3,4,5,6,7,8,9,0};
    printf("%p\n", arr);
    printf("%p\n", &arr[0]);
    return 0;
}

运行结果:

可以看见数组名和数组首元素的地址是一样的。

结论: 数组名表示数组首元素的地址。(2种情况除外,数组章节讲解了)

这样写代码是可以的:

int arr[10] = { 1,2,3,4,5,6,7,8,9,10};

int* p = arr; //p存放的是数组首元素的地址 

既然可以把数组名当成地址存放到一个指针中,那我们使用指针来访问一个元素就成为可能。

例如:

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

运行结果:

所以p+i其实计算的是数组arr下标为i的地址。

那我们就可以直接通过指针来访问数组。

如下:

int main()
{
    int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
    int *p = arr; //指针存放数组首元素的地址
    int sz = sizeof(arr) / sizeof(arr[0]);
    int i = 0;
    for (i = 0; i<sz; i++)
    {
        printf("%d ", *(p + i));
    }
    return 0;
}

7.二级指针

指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?
这就是 二级指针

对于二级指针的运算有:

  • *ppa通过对ppa中的地址进行解引用,这样找到的是pa,*ppa其实访问的就是pa.

int b = 20;

*ppa  = &b; //等价于 pa = &b;

  • **ppa先通过*ppa 找到pa ,然后对pa 进行解引用操作:*pa, 那找到的是a。

**ppa = 30;

//等价于 *pa = 30

//等价于 a = 30

8.指针数组

指针数组是指针还是数组?

答案:是数组。是存放指针的数组。

数组我们已经知道整形数组,字符数组。

int arr1[5];                //整形数组 - 存放整形的数组

char arr2[6];             //字符数组 - 存放字符的数组

指针数组 - 存放指针的数组

int a = 10;

int b = 20;

int c = 30;

int* arr[5] = { &a, &b, &c};  //存放整形指针的数组

int i = 0;

for(i=0;  i<3;  i++)

{
        printf("%d ", *(arr[i]));

那指针数组是怎样的?

int* arr3[5]; //是什么?

arr3是一个数组,有五个元素,每个元素是一个整形是指针。

指针就介绍到这里。


补充:

CPU位数的含义
        上面这个流程里,最重要的几个关键词,分别是CPU寄存器,总线,内存。

        CPU的寄存器,说白了就是个存放数值的小盒子,盒子的大小,叫位宽。32位CPU能放入最大2^32的数值。64位就是最大2^64的值。这里的32位位宽的CPU就是我们常说的32位CPU,同理64位CPU也是一样。

        而CPU跟内存之间,是用总线来进行信号传输的,总线可以分为数据总线,控制总线,地址总线。功能如其名,举个例子说明下他们的作用吧。在一个进程的运行过程中,CPU会根据进程的机器码一行行执行操作。

        比如现在有一行是将A地址的数据与B地址的数据相加,那么CPU就会通过控制总线,发送信号给内存这个设备,告诉它,现在CPU要通过地址总线在内存中找到A数据的地址,然后取得A数据的值,假设是100,那么这个100,就会通过数据总线回传到CPU的某个寄存器中。B也一样,假设B=200,放到另一个寄存器中,此时A和B相加后,结果是300,然后控制CPU通过地址总线找到返回的参数地址,再把数据结果通过数据总线传回内存中。这一存一取,CPU都是通过控制总线对内存发出指令的。

总线,也可以理解为有个宽度,比如宽度是32位,那么一次可以传32个0或1的信号,那么这个宽度能表达的数值范围就是0到2^32这么多。

32位CPU的总线宽度一般是32位,因为刚刚上面提到了,CPU可以利用地址总线在内存中进行寻址操作,那么现在这根地址总线,最大能寻址的范围,也就到2^32,其实就是4G

64位CPU,按理说总线宽度是64位,但实际上是48位(也有看到说是40位或46位的,没关系,你知道它很大就行了),所以寻址范围能到2^48次方,也就是256T

本小节到这里就结束了。

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

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

相关文章

Vitis HLS 学习笔记--理解串流Stream(2)

目录 1. 简介 2. 极简的对比 3. 硬件模块的多次触发 4. 进一步探讨 do-while 5. 总结 1. 简介 在这篇博文中《Vitis HLS 学习笔记--AXI_STREAM_TO_MASTER-CSDN博客》&#xff0c;我分享了关于 AXI Stream 接口的实际应用案例。然而&#xff0c;尽管文章中提供了代码示例&…

如何向Linux内核提交开源补丁?

2021年&#xff0c;我曾经在openEuler社区上看到一项改进Linux内核工具的需求&#xff0c;因此参与过Linux内核社区的开源贡献。贡献开源社区的流程都可以在内核社区文档中找到&#xff0c;但是&#xff0c;单独学习需要一个较长的过程&#xff0c;新手难以入门&#xff0c;因此…

分享四种免费获取SSL的方式

SSL证书目前需要部署安装的网站很多&#xff0c;主要还是基于国内目前对证书的需求度在不断的升高&#xff0c;网站多了、服务器多了之后。网络安全问题就成为了大家不得不面对的一个重要的问题了。SSL证书的作用有很多&#xff0c;这里就不一一详述了&#xff0c;本期作品主要…

如何在线阅读Linux内核源码?

开源社区有一句名言&#xff1a;Talk is cheap, show me your code。阅读源代码是学习Linux操作系统的必经之路。但是&#xff0c;Linux内核的代码量超过3000万行&#xff0c;工程包非常大&#xff0c;直接下载耗时较长&#xff0c;这就需要使用一些在线阅读的技巧。 方式1&am…

【深度学习】【Lora训练0】StabelDiffusion,Lora训练,kohya_ss训练

文章目录 环境数据自动标注kohya_ss BLIP2kohya_ss WD14 后续 资源&#xff1a; &#xff08;1&#xff09;训练ui kohya_ss&#xff1a; https://github.com/bmaltais/kohya_ss &#xff08;2&#xff09;kohya_ss 的docker 其他docker https://github.com/ashleykleynhans…

韩顺平0基础学Java——第7天

p110-p154 控制结构&#xff08;第四章&#xff09; 多分支 if-elseif-else import java.util.Scanner; public class day7{public static void main(String[] args) {Scanner myscanner new Scanner(System.in);System.out.println("input your score?");int s…

Word表格标题间距大修改环绕为无仍无法解决

1.选中表格&#xff0c;右键选择【表格属性】 2.选择【环绕】&#xff0c;此时【定位】可以被启用&#xff08;如下&#xff09;&#xff0c;点击进入窗口 3.修改参数和下面一模一样 注意&#xff1a;【垂直】那里的修改方式是先选段落&#xff0c;后在位置输入0

【linux】主分区,扩展分区,逻辑分区,动态分区,引导分区,标准分区

目录 主分区&#xff0c;扩展分区&#xff0c;逻辑分区 主分区和引导分区 主分区&#xff0c;扩展分区&#xff0c;逻辑分区&#xff08;标准分区&#xff09; 硬盘一般划分为一个“主分区”和“扩展分区”&#xff0c;然后在扩展分区上再分成数个逻辑分区。 磁盘主分区扩展…

html+css-Day1(盒子模型)

一、常用属性 1、字体设置font "line-height" 是 CSS 中的一个属性&#xff0c;用于设置文本行之间的距离&#xff0c;也就是行间距。它影响着段落、行内元素或者任何包含文本的元素的可读性。"line-height" 可以设置为数字、长度单位&#xff08;如 px、e…

现货黄金流程到何种程度?现货黄金在金融产品中的占比是多少?

踏入2024年以来&#xff0c;受美联储降息以及地缘局势紧张的影响&#xff0c;美元受压&#xff0c;避险情绪高涨&#xff0c;众多因素影响下黄金价格出现了强势的上涨&#xff0c;屡创历史新高。在上涨如此强劲的背景下&#xff0c;投资者希望通过黄金投资来实现资产增值。市场…

力扣爆刷第135天之数组五连刷(双指针快慢指针滑动窗口)

力扣爆刷第135天之数组五连刷&#xff08;双指针快慢指针滑动窗口&#xff09; 文章目录 力扣爆刷第135天之数组五连刷&#xff08;双指针快慢指针滑动窗口&#xff09;一、704. 二分查找二、27. 移除元素三、977. 有序数组的平方四、209. 长度最小的子数组五、59. 螺旋矩阵 II…

Adversarial Synthesis of Human Pose From Text # 论文阅读

URL https://arxiv.org/pdf/2005.00340 TD;DR 20 年 5 月来自高校的一篇论文&#xff0c;任务是用 GAN 生成 pose&#xff0c;目前 7 引用。 Model & Method 输入的是描述动作的 text&#xff0c;通过 text encoder&#xff08;本文用的是叫做 fastText 的方法&#…

Kafka应用Demo:指派分区订阅消息消费

环境准备 Kafka环境搭建和生产者样例代码与《Kafka应用Demo&#xff1a;按主题订阅消费消息》相同。 消费者代码样例 public class KafkaConsumerService {private static final Logger LOGGER LoggerFactory.getLogger(KafkaConsumerService.class);private static final S…

word图片水印

一、word中旧水印如何删除 打开word模板&#xff0c;想要删除旧水印&#xff0c;如下图所示操作&#xff0c;但是旧水印删除不掉。 以为上传新水印图片会替换掉旧水印&#xff0c;结果显示了2个水印&#xff0c;要怎么删除呢&#xff1f; 如下截图所示&#xff0c;双击打开页…

vue+element的表格(el-table)排班情况表(2024-05-09)

vueelement的表格&#xff08;el-table&#xff09;排班情况&#xff0c;增删查改等简单功能 代码&#xff1a; <template><!-- 表格 --><div class"sedules"><el-header><el-date-pickerv-model"monthValue2"type"month…

YOLOv8网络结构介绍

将按照YOLOv8目标检测任务、实例分割任务、关键点检测任务以及旋转目标检测任务的顺序来介绍&#xff0c;主要内容也是在目标检测任务中介绍&#xff0c;其他任务也只是Head层不相同。 1.YOLOv8_det网络结构 首先&#xff0c;YOLOv8网络分成了三部分&#xff0c;分别是主干网络…

制鞋5G智能工厂数字孪生可视化平台,推进行业数字化转型

制鞋5G智能工厂数字孪生可视化平台&#xff0c;推进行业数字化转型。随着科技的飞速发展&#xff0c;5G技术与智能制造的结合正成为推动制鞋行业数字化转型的重要力量。制鞋5G智能工厂数字孪生可视化平台&#xff0c;不仅提高了生产效率&#xff0c;还优化了资源配置&#xff0…

【Linux系统编程】31.pthread_detach、线程属性

目录 pthread_detach 参数pthread 返回值 测试代码1 测试结果 pthread_attr_init 参数attr 返回值 pthread_attr_destroy 参数attr 返回值 pthread_attr_setdetachstate 参数attr 参数detachstate 返回值 测试代码2 测试结果 线程使用注意事项 pthread_deta…

SpringCloud:认识微服务

程序员老茶 &#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;程序员老茶 &#x1f64a; P   S : 点赞是免费的&#xff0c;却可以让写博客的作者开心好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#…

NSSCTF | [SWPUCTF 2021 新生赛]easy_sql

打开题目&#xff0c;提示输入一些东西&#xff0c;很显眼的可以看到网站标题为“参数是wllm” 首先单引号判断闭合方式 ?wllm1 报错了&#xff0c;可以判断为单引号闭合。 然后判断字节数&#xff08;注意‘--’后面的空格&#xff09; ?wllm1 order by 3-- 接着输入4就…
最新文章