C语言-详解指针

news2025/1/11 20:38:27


目录

一.内存

        1.内存的定义

        2.内存的结构图

二.地址

        1.什么是地址

        2.什么是变量的地址

三.什么是指针

        1.指针的定义

四.如何获取数据存储空间的地址

        1.&运算符

五.指针变量

        1.什么是指针变量(一级指针变量)

        2.指针变量的定义                

       3.指针变量的大小

六.指针变量的大小

七.使用指针变量

        1.*运算符

          2.为什么需要使用地址                

八.指针的运算

        1.指针 +- 整数

        2.指针-指针

        

        3.指针的关系运算                

九.野指针

        1.什么是野指针

        2.野指针的成因

        3.如何避免野指针

十.指针和数组

十一.二级指针

        1.什么是二级指针

        2.二级指针变量的声明

十二.指针数组

        1.什么是指针数组

        2.指针数组的定义

          3.指针数组的使用                

十三.字符指针

        1.什么是字符指针

        2.字符指针的使用

十四.数组指针

        1.什么是数组指针

        2.什么是整个数组的地址

        3.如何保存数组的地址

        4.数组指针变量的定义

        5.数组指针的使用

        6.区别数组,指针数组,数组指针,数组指针数组

        7.指针数组和数组指针数组的使用

十五.数组传参和指针传参

        1.数组传参

        2.指针传参

 十六.函数指针

        1.什么是函数指针

        2.函数指针变量                

        3.函数指针变量的使用

十七.函数指针数组

        1.函数指针数组的定义

        2.函数指针数组的使用

十八.指向函数指针数组的指针

        1.定义                

十九.回调函数

        1.定义

        2.回调函数的使用

二十.指针笔试题


一.内存

        1.内存的定义

                内存(Memory)是计算机的重要部件,也称内存储器和主存储器,它用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据。它是外存与CPU进行沟通的桥梁,计算机中所有程序的运行都在内存中进行,内存性能的强弱影响计算机整体发挥的水平。只要计算机开始运行,操作系统就会把需要运算的数据从内存调到CPU中进行运算,当运算完成,CPU将结果传送出来。

                计算机中常用的内存的大小是 4g/8g/16g

                程序在运行前会先加载到内存中,也会使用内存。

        2.内存的结构图

                C++-内存的结构图-CSDN博客

                一个字节是8个bit位。 

二.地址

        1.什么是地址

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

      

        2.什么是变量的地址

                变量的存储空间的首字节的地址就是整个变量的地址。

                 一个例子:以int类型的变量为例子

                

三.什么是指针

        1.指针的定义

                指针指的是内存中一个最小单元的编号。

                所以我们在提到指针的概念的时候可以认为指针就是地址。

  

四.如何获取数据存储空间的地址

        1.&运算符

                &地址运算符又称取地址运算符,&运算符的运算对象是变量,将变量数据的存储空间的地址叫做表达式的派生值。

                在C语言中我们用%p来作为地址的转换说明。

                那么此时我们获取到的相应类型的地址数据应该保存到什么类型的变量中呢?

五.指针变量

        1.什么是指针变量(一级指针变量)

                指针变量是一个变量,变量中的内容保存的是存储相应类型的存储空间的首字节地址。

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

        2.指针变量的定义                

#include <stdio.h>

int main(void)
{
	int number = 10;

	int* ptr_number = &number;

	printf("number的地址:%p\n", &number);
	printf("ptr_number中保存的数据:%p\n", ptr_number);

	return  0;
}

             

                *ptr_number表明ptr_number这个变量是一个指针变量,该变量中保存的数据是保存int类型数据的存储空间的编号,也就是地址。

                此时就会有疑问,为什么我们通过变量名number也可以得到我们想要的数据,为什么还需要通过地址来访问存储空间,从而得到我们想要的数据。

        

       3.指针变量的大小

        在32位操作系统下                         在64位操作系统下        

        为什么在不同位的操作系统下,同样的代码同样的指针变量却有不同的结果呢?

六.指针变量的大小

        上面我们说到指针变量中保存的是存储空间的地址,那么指针变量在不同的平台下所占的字节数不同,也就说明了在不同的平台下我们的地址这个数据的大小不同。 

        对于32位平台下:

                对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或者0);

                那么32根地址线产生的地址就会是:
                        0000 0000 0000 0000 0000 0000 0000 0000
                        0000 0000 0000 0000 0000 0000 0000 0001
                        ...
                        1111  1111  1111  1111 1111  1111  1111  1111

                所以我们要保存32位bit位的地址数据,那么我们就需要用4个字节来保存。

                所以在32位平台下指针变量的大小都是4字节。无论保存什么样类型的数据。 

        对于64位平台下同理。

七.使用指针变量

        1.*运算符

                *运算符又称解引用运算符(间接运算符),*运算符的运算对象是指针变量或地址,

通过它得到的表达式的派生值是地址中保存的相应类型的数据。

#include <stdio.h>

int main(void)
{
	int number = 10;

	int* ptr_number = &number;

	printf("number=%d\n", number);
	printf("*ptr_number=%d\n", *ptr_number);

	return  0;
}

                       

          2.为什么需要使用地址                

#include <stdio.h>

void Swap(int number_a, int number_b)
{
	int number_tmp = 0;
	number_tmp = number_a; 
	number_a = number_b;
	number_b = number_tmp;
}

int main(void)
{
	int number_a = 10;
	int number_b = 20;

	printf("两数交换前分别为number_a = %d number_b = %d\n", number_a, number_b);

	Swap(number_a, number_b);

	printf("两数交换后分别为number_a = %d number_b = %d\n", number_a, number_b);
	return 0;
}

                 此时我们运行代码发现两数并没有交换:


                        原因就是此时我们传入函数的就是一个值而已,在我们主调函数中的值并没有改变。

        解决办法:

                上面我们提到了地址是存储空间的编号,那么我们将变量的地址传入到函数中,不就可以直接对存储空间中的数据进行更改了。

#include <stdio.h>

void Swap(int* ptr_number_a, int* ptr_number_b)
{
	int number_tmp = 0;
	number_tmp = *ptr_number_a; 
	*ptr_number_a = *ptr_number_b;
	*ptr_number_b = number_tmp;
}

int main(void)
{
	int number_a = 10;
	int number_b = 20;

	printf("两数交换前分别为number_a = %d number_b = %d\n", number_a, number_b);

	Swap(&number_a, &number_b);

	printf("两数交换后分别为number_a = %d number_b = %d\n", number_a, number_b);
	return 0;
}

八.指针的运算

        1.指针 +- 整数

int main(void)
{
	int a = 10;
	int* ptr_a = &a;

	printf("a变量的地址是:%p\n", &a);
	printf("ptr_a:%p\n", ptr_a);
	printf("ptr_a + 1:%p", ptr_a + 1);
	return 0;
}

           

        从上图我们可以看出,指针+-整数并不是单纯的数值上面的累加,而是跳过整数倍个该类型所占的字节数。

        int* ptr:

                *ptr表明ptr变量是指针变量,所以这个变脸中保存的数据是一个地址,该地址所标识的存储空间中的数据是一个int类型的数据。

                所以我们在声明一个变量是指针变量的时候,*表明这个变量是一个指针变量,而指明数据类型,是为了保证我们在处理指针变量的时候,结果的正确。 

        2.指针-指针

                指针-指针的前提条件是两个指针变量指向同一段连续的存储空间上。不同的存储空间上计算出来的结果没有意义。

                指针-指针的结果是两个地址之间的元素个数。                

int main(void)
{
	int numbers[10] = { 0 };

	int* ptr_numbers_start = numbers;
	int* ptr_numbers_end = numbers + 10;

	printf("%d\n", ptr_numbers_end - ptr_numbers_start);
	return 0;
}

               

        

        3.指针的关系运算                

int main(void)
{
	int numbers[3] = { 1,2,3 };

	int* ptr_numbers_start = numbers;
	int* ptr_numbers_end = numbers + 3;

	while (ptr_numbers_start < ptr_numbers_end)
	{
		printf("%d ", *ptr_numbers_start);
		ptr_numbers_start++;
	}
	printf("\n");
	return 0;
}

         注意:

                C语言中只保证了给数组分配空间时,指向数组后面的第一个位置的指针仍然是有效指针。不允许与指向数组第一个元素的前一个位置的指针进行比较。

九.野指针

        1.什么是野指针

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

        

        2.野指针的成因

                  没有对指针变量进行初始化

#include <stdio.h>
int main()
{ 
 int *p;//局部变量指针未初始化,默认为随机值
    *p = 20;
 return 0;
}

                 指针越界访问

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

                对空指针进行解引用

int main(void)
{
	int* ptr = NULL;

	*ptr = 11;
	return 0;
}

        3.如何避免野指针

                a. 指针初始化
                b. 小心指针越界
                c. 指针指向空间释放,及时置NULL
                d. 避免返回局部变量的地址
                e. 指针使用之前检查有效性     
   
#include <stdio.h>
int main()
{
    int *p = NULL;
    //....
    int a = 10;
    p = &a;
    if(p != NULL)
   {
        *p = 20;
   }
    return 0;
}

十.指针和数组

        先看一个例子:                

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

        通过观察上图我们可以得出结论:

                数组名是数组首元素的地址。

十一.二级指针

        1.什么是二级指针

                二级指针是指一级指针变量的地址。

        2.二级指针变量的声明

                int ** pptr;

                        *pptr表明pptr这个变量是指针变量,这个变脸中保存的数据是一个地址数据,这个地址指向的存储空间中保存的数据是一个int*类型的数据。 

十二.指针数组

        1.什么是指针数组

                顾名思义就是一个数组中的每个元素都是指针类型的。

        2.指针数组的定义

                int * ptrs[10];

                ptr[10]表明此处是声明一个数组,该数组有10个元素,int*表明这个10个元素每一个都是int*的指针变量。

        

          3.指针数组的使用                

int* arr1[10]; //整形指针的数组
char *arr2[4]; //一级字符指针的数组
char **arr3[5];//二级字符指针的数组

十三.字符指针

        1.什么是字符指针

               保存char类型数据的存储空间的地址。

        

        2.字符指针的使用

int main()
{
    char ch = 'w';
    char *pc = &ch;
    *pc = 'w';
    return 0;
}
int main()
{
    const char* pstr = "hello bit.";//这里是把一个字符串放到pstr指针变量里了吗?
    printf("%s\n", pstr);
    return 0;
}

                对于代码 const char* pstr = "hello bit.";的解释:

                        ”hello bit“是字符串字面量,这里”hello bit“表示的其实是字符串首元素的地址。这里是将这个字符串首元素的地址放到了pstr中。

        一道笔试题:            

#include <stdio.h>
int main()
{
    char str1[] = "hello bit.";
    char str2[] = "hello bit.";
    const char *str3 = "hello bit.";
    const char *str4 = "hello bit.";
    if(str1 ==str2)
 printf("str1 and str2 are same\n");
    else
 printf("str1 and str2 are not same\n");
       
    if(str3 ==str4)
 printf("str3 and str4 are same\n");
    else
 printf("str3 and str4 are not same\n");
       
    return 0;
}

        这里首先函数声明了str1和str2两个字符数组,然后将字符串“hello bit.”拷贝到数组空间中,数组名表示数组首元素的地址,同时str1和str2又是两个不同的数组,所以str1不等于str2。但是对于str3和str4这两个指针数组来说,因为字符串字面量是保存在内存的常量区的空间是不会改变的,所以str3和str4所获取的地址是相同的。

十四.数组指针

        1.什么是数组指针

                首先数组指针是一个指针,这个指针是整个数组的地址。

       

        2.什么是整个数组的地址

                数组名表示的是数组首元素的地址,那么此时对数组名取地址,得到的就是整个数组的地址。

        3.如何保存数组的地址

                前面我们提到过指针也就是地址,要保存在指针变量中,那么数组指针也不例外,也因该保存在数组指针变量中。

                

        4.数组指针变量的定义

#include <stdio.h>
int main()
{
	int numbers[10] = { 0 };

	int(*ptr_numbers)[10] = &numbers;

	return 0;
}

        首先*ptr_numbers表明ptr_numbers这个变量一个指针变量,该指针变量的类型是一个有10个int元素组成的数组该指针变量中保存的数据是一个10个元素数组的地址

        5.数组指针的使用

#include <stdio.h>

void Print(int (*ptr_numbers)[4], int r, int c)
{
	int i_i = 0;
	int i_j = 0;
	for (i_i = 0; i_i < r; i_i++)
	{
		for (i_j = 0; i_j < c; i_j++)
		{
			printf("%d ", *(*(ptr_numbers + i_i) + i_j));
		}
		printf("\n");
	}
}

int main(void)
{
	int numbers[3][4] = { {1, 2, 3, 4}, {4, 5, 6, 7} ,{7, 8, 9, 10} };

	Print(numbers, 3, 4);
	return 0;
}

        6.区别数组,指针数组,数组指针,数组指针数组

int arr[5];
int *parr1[10];
int (*parr2)[10];
int (*parr3[10])[5];

        7.指针数组和数组指针数组的使用

#include <stdio.h>

int main(void)
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr3[10] = { 1,2,3,4,5,6,7,8,9,10 };

	//整型指针数组
	int* ptr[3] = { arr1, arr2, arr3 };

	//数组指针数组
	int(*ptrs[3])[10] = { &arr1, &arr2, &arr3 };

	//遍历数据
	//整型指针数组的遍历
	int i_i = 0;
	int i_j = 0;
	for (i_i = 0; i_i < 3; i_i++)
	{
		for (i_j = 0; i_j < 10; i_j++)
		{
			printf("%d ", ptr[i_i][i_j]);
		}
		printf("\n");
	}
	printf("\n");
	//数组指针数组的遍历
	int i_z = 0;
	for (i_i = 0; i_i < 3; i_i++)
	{
		for (i_j = 0; i_j < 10; i_j++)
		{
			printf("%d ", (*(ptrs[i_i]))[i_j] );
		}
		printf("\n");
	}
	printf("\n");
	return 0;
}

十五.数组传参和指针传参

        1.数组传参

                一维数组:          

#include <stdio.h>

void test1(int arr[10])
{}
void test1(int arr [])
{}
void test1(int* arr)
{}

void test2(int *arr[20])
{}
void test2(int* arr[])
{}
void test2(int **arr)
{}

int main(void)
{
	int arr1[10] = { 0 };

	int* arr2[20] = { 0 };

	test1(arr1);
	test2(arr2);

	return 0;
}

                二维数组:

#include <stdio.h>

void test(int arr[3][5])
{}
void test(int arr[][5])
{}
void test(int (*arr)[5])
{}


int main(void)
{
	int arr[3][5] = { 0 };

	test(arr);

	return 0;
}

       

        2.指针传参

                一级指针传参:

#include <stdio.h>
void print(int *p, int sz)
{
 int i = 0;
 for(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 *p = arr;
 int sz = sizeof(arr)/sizeof(arr[0]);
 //一级指针p,传给函数
 print(p, sz);
 return 0;
}

                       当一个函数的形数是一个一级指针的时候可以收什么样的实参呢?

                        数组名,变量的地址,一级指针变量。

                二级指针传参:

#include <stdio.h>
void test(int** ptr)
{
 printf("num = %d\n", **ptr); 
}
int main()
{
 int n = 10;
 int*p = &n;
 int **pp = &p;
 test(pp);
 test(&p);
 return 0;
}

                        当一个函数的形数是一个二级指针的时候可以收什么样的实参呢?

                                二级指针变量,一级指针变量的地址,一级指针数组的数组名。

 十六.函数指针

        1.什么是函数指针

#include <stdio.h>
void test()
{
 printf("hehe\n");
}
int main()
{
 printf("%p\n", test);
 printf("%p\n", &test);
 return 0;
}

               

        输出的是两个地址,这两个地址是 test 函数的地址。
        那我们的函数的地址要想保存起来,怎么保存?

        2.函数指针变量                

void test()
{
 printf("hehe\n");
}
//下面pfun1和pfun2哪个有能力存放test函数的地址?
void (*pfun1)();

        分析一下两段代码:

//代码1
(*(void (*)())0)();
//代码2
void (*signal(int , void(*)(int)))(int);

                代码1:

                        (void (*)())0是将0强转类型转换为函数指针,(*0)() 是调用函数。

                代码2:

                        首先(*signal(int , void(*)(int)))是一个函数,该函数的返回值类型是void(int)。

                代码2太复杂,如何简化:

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

       

        3.函数指针变量的使用

#include <stdio.h>
void test()
{
	printf("hehe\n");
}
int main()
{
	void (*ptr_test)() = test;

	ptr_test();
	return 0;
}

十七.函数指针数组

        1.函数指针数组的定义

int (*parr1[10])();

        2.函数指针数组的使用

                函数指针数组的用途:转移表

#include <stdio.h>
int add(int a, int b)
{
           return a + b;
}
int sub(int a, int b)
{
           return a - b;
}
int mul(int a, int b)
{
           return a*b;
}
int div(int a, int b)
{
           return a / b;
}
int main()
{
 int x, y;
     int input = 1;
     int ret = 0;
     int(*p[5])(int x, int y) = { 0, add, sub, mul, div }; //转移表
     while (input)
     {
          printf( "*************************\n" );
          printf( " 1:add           2:sub \n" );
          printf( " 3:mul           4:div \n" );
          printf( "*************************\n" );
          printf( "请选择:" );
      scanf( "%d", &input);
          if ((input <= 4 && input >= 1))
         {
          printf( "输入操作数:" );
              scanf( "%d %d", &x, &y);
              ret = (*p[input])(x, y);
         }
          else
               printf( "输入有误\n" );
          printf( "ret = %d\n", ret);
     }
      return 0;
}

十八.指向函数指针数组的指针

        1.定义                

                指向函数指针数组的指针是一个 指针
                指针指向一个 数组 ,数组的元素都是 函数指针 ;
void test(const char* str)
{
 printf("%s\n", str);
}
int main()
{
 //函数指针pfun
 void (*pfun)(const char*) = test;
 //函数指针的数组pfunArr
 void (*pfunArr[5])(const char* str);
 pfunArr[0] = test;
 //指向函数指针数组pfunArr的指针ppfunArr
 void (*(*ppfunArr)[5])(const char*) = &pfunArr;
 return 0;
}

十九.回调函数

        1.定义

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

        2.回调函数的使用

二十.指针笔试题

                C语言-指针笔试题详解-CSDN博客

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

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

相关文章

Opencv库如何检测图片中鸡蛋数量

Opencv库检测图片中鸡蛋数量 由于需要写一个检测鸡蛋数量的程序&#xff0c;用了几个opencv中的经典方法&#xff0c;实现了图片中鸡蛋的检测。在一步步实现的同时&#xff0c;同时说明每个方法的用途。希望能给学习opencv的小伙伴一些帮助。下图为原始图和实现后的检测边框。…

ubuntu20.04找不到#include<opencv/cv.h>文件

编译ROS包的时候出现错误&#xff1a;fatal error&#xff1a;opencv/cv.h : No such file or directory #include<opencv/cv.h> 查看opencv4版本&#xff1a; pk-config --modversion opencv4: 在opencv4中opencv2的cv.h融合进了imgproc.hpp里: 把源码中的#include …

字节跳动开源基于SD1.5的 MagicAnimate 一张照片秒变真人舞蹈视频

项目地址&#xff1a;https://github.com/magic-research/magic-animate 显卡要求&#xff1a;12G MagicAnimate是一项利用先进的扩散模型实现人体图像动画的创新性项目。其核心优势在于确保生成内容的时间一致性&#xff0c;通过提供预训练的稳定扩散V1.5和MSE微调的VAE基础…

Python-炸弹人【附完整源码】

炸弹人 炸弹人是童年的一款经典电子游戏&#xff0c;玩家控制一个类似"炸弹人"的角色&#xff0c;这个角色可以放置炸弹&#xff0c;并在指定的时间内引爆它们消灭敌人以达到目标&#xff0c;此游戏共设有两节关卡&#xff0c;代码如下&#xff1a; 运行效果&#x…

Qt/C++视频监控拉流显示/各种rtsp/rtmp/http视频流/摄像头采集/视频监控回放/录像存储

一、前言 本视频播放组件陆陆续续写了6年多&#xff0c;一直在持续更新迭代&#xff0c;视频监控行业客户端软件开发首要需求就是拉流显示&#xff0c;比如给定一个rtsp视频流地址&#xff0c;你需要在软件上显示实时画面&#xff0c;其次就是录像保存&#xff0c;再次就是一些…

22、pytest多个参数化的组合

官方实例 # content of test_multi_parametrie.py import pytestpytest.mark.parametrize("x",[0,1]) pytest.mark.parametrize("y",[2,3]) def test_foo(x,y):print("{}-{}".format(x,y))pass解读与实操 要获得多个参数化参数的所有组合&…

vue3里面使用ref和toRef、toRefs

vue3 里面我们经常会使用ref()来接受内部值&#xff0c;返回一个响应式的对象。创建可以使用任何类型的响应式ref。这里对象是响应式的&#xff0c;可以进行更改的&#xff0c;对象有一个value属性&#xff0c;其值就是所传递的原始值。ref() 将传入参数的值包装为一个带 .valu…

【链表Linked List】力扣-83 删除排序链表中的重复元素

目录 题目描述 解题过程 题目描述 给定一个已排序的链表的头 head &#xff0c; 删除所有重复的元素&#xff0c;使每个元素只出现一次 。返回 已排序的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,1,2] 输出&#xff1a;[1,2]示例 2&#xff1a; 输入&#xff1…

【每日OJ —— 94. 二叉树的中序遍历】

每日OJ —— 94. 二叉树的中序遍历 1.题目&#xff1a;94. 二叉树的中序遍历2.解法2.1.算法讲解2.2.代码实现2.3.提交通过展示 1.题目&#xff1a;94. 二叉树的中序遍历 2.解法 2.1.算法讲解 1.首先如果在每次每个节点遍历的时候都去为数组开辟空间&#xff0c;这样的效率太低…

android开发市场被抢占,鸿蒙能入行吗?

根据最新的数据&#xff0c;华为Mate60系列在上市第二周就成功占据了国内手机市场的17%份额&#xff0c;排名第二。而机构预测&#xff0c;华为手机在第37周有望超过20%的市场份额&#xff0c;成为国内手机市场的冠军。 一开始&#xff0c;人们对HarmonyOSNEXT持保留态度&…

国产麒麟操作系统部署记录

前提&#xff1a;部署项目首先要安装各种软件&#xff0c;在内网环境下无法在线下载。 思路&#xff1a;首先部署一台能上网的系统&#xff0c;在此系统下只下载包&#xff0c;然后传到另一台内网系统下进行安装&#xff1b; 1、最开始yum未安装&#xff0c;因此需要先安装yu…

PHP短信接口防刷防轰炸多重解决方案三(可正式使用)

短信接口盗刷轰炸&#xff1a;指的是黑客利用非法手段获取短信接口的访问权限&#xff0c;然后使用该接口发送大量垃圾短信给目标用户 短信验证码轰炸解决方案一(验证码类解决)-CSDN博客 短信验证码轰炸解决方案二(防止海外ip、限制ip、限制手机号次数解决)-CSDN博客 PHP短信…

JavaScript 数组方法 reduce() 的用法

一、概述 在JavaScript中&#xff0c;reduce()方法是一个非常实用的数组方法&#xff0c;它接收一个函数作为累加器&#xff08;accumulator&#xff09;&#xff0c;数组中的每个值&#xff08;从左到右&#xff09;开始缩减&#xff0c;最终为一个值。这个方法在处理数组…

数据结构 | 二叉树的各种遍历

数据结构 | 二叉树的各种遍历 文章目录 数据结构 | 二叉树的各种遍历创建节点 && 创建树二叉树的前中后序遍历二叉树节点个数二叉树叶子节点个数二叉树第k层节点个数二叉树查找值为x的节点二叉树求树的高度二叉树的层序遍历判断二叉树是否是完全二叉树 我们本章来实现二…

【C语言】指针与数组的潜在联系

目录 前言 改变固有数组的平面思维 注意&#xff1a; 数组操作与指针等价 指针数组 数组指针 笔试加深理解&#xff1a; 解析&#xff1a; 前言 《C Traps and Pitfalls》(C语言缺陷与陷阱)中有一句著名的见解&#xff1a; “在C语言中&#xff0c;指针与数组这两个概念…

MUC\GD32低功耗模式简介

 前言 低功耗模式在现在的开发中尤为重要&#xff0c;特别是在使用电池的设备中&#xff0c;今天我们就拿GD32来聊一聊低功耗模式&#xff0c;以及他们使用的状态与唤醒方式以及耗电情况。 GD32支持的低功耗模式&#xff1a;  省电模式 MCU支持三种省电模式&#xff0…

SpringBoot3-创建自定义启动器,使用自定义starter启动器

1、创建自定义启动工程pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.a…

647. Palindromic Substrings 516. Longest Palindromic Subsequence

647. Palindromic Substrings Given a string s, return the number of palindromic substrings 回文子串 in it. A string is a palindrome when it reads the same backward as forward. A substring is a contiguous sequence of characters within the string. nomal: …

Hello World!

一、minist数据集 深度学习编程特有的hello world程序&#xff1a;采用minist数据集完成意向特定深度学习项目 1、minist数据集介绍 MNIST数据集是一个广泛使用的手写数字识别数据集&#xff0c;它包含了许多不同人手写的数字图片。这个数据集被广泛用于研究手写数字识别&…

文件上传漏洞(带实例)

漏洞介绍&#xff1a; 现代互联网的Web应用程序中&#xff0c;上传文件是一种常见的功能&#xff0c;因为它有助于提高业务效率&#xff0c;如企业的OA系统&#xff0c;允许用户上传图片&#xff0c;视频&#xff0c;头像和许多其他类型的文件。然而向用户提供的功能越多&#…