C++ 指针详解

news2024/11/16 12:56:29

目录

一、指针概述

指针的定义

指针的大小

指针的解引用

野指针

指针未初始化

指针越界访问

指针运算

二级指针

指针与数组

二、字符指针

三、指针数组

四、数组指针

函数指针

函数指针数组

指向函数指针数组的指针

回调函数

指针与数组

一维数组

字符数组

二维数组


一、指针概述

指针的定义

数据是存放在内存中的,每一个内存空间都会有一个像房间号一样的编号,比如某某五星级酒店3109号房间,只有获得了这个编号才能找到这个房间,这个编号就是地址。而指针就是用来存放这个地址的变量。总结来说:指针是一个变量,是用来存放内存地址的变量,我们通常称谓指针变量。

指针的大小

是由计算机的物理性质决定的,一般的计算机分为32位机和64位机,32位机就是由32根地址线组成,每一根地址线都会传递高电平(1)或者低电平(0)。那么32根地址线就会产生2^32次方个地址,所以64位机的地址以此类推。8bite = 1字节——32位机的地址就由4个字节存储,62位机的地址就由8个字节的地址存储。

指针类型:数据的存储方式有 char、short、int、long、long long、float、double、struct、void
因此对应反指针类型也就有:char*、short*、int*、long*、long long*、float*、double*、struct*、void*

int main()
{
 
    //什么类型数据的地址就得放到对应类型的指针变量中
    
    char ch = 'w';
    char* pc = &ch;
 
    int num = 10;
    int* p = #
 
    return 0;
}

指针的解引用

指针的类型决定了,对指针解引用的时候有多大的权限(能取到多大的字节数)。比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。

野指针

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

指针未初始化

int main()
{ 
    //局部变量指针未初始化,默认为随机值
    int *p;//没有指向对应的地址空间,无法查找地址
    *p = 20;
 
    return 0;
}

指针越界访问

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

指针指向的空间释放,在堆里开辟内存的空间,如果被回收就不能在使用,因此指针就不能再指向那块空间的地址。

指针运算

指针的类型决定 + - 整数,指针变量所偏移的空间大小

int main()
{
 
    float arr[5];
    //指针+-整数;指针的关系运算
    for (float *p = &arr[0]; vp < &arr[5];)
    {
         //后置++,先给数组赋值在偏移四个字节
         *p++ = 0;
    }
    return 0;
 
}

指针 - 指针

//模拟实现strlen
int my_strlen(char *s)
{
       char *p = s;
 
       while(*p != '\0' )
              p++;
        
       return p-s;//两个指针之间的空间个数
}

指针的关系运算,允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。

#define N_VALUES 5
int main()
{
    
    float values[N_VALUES];
    float *vp;
    
    //不能让数组第一个元素的地址与数组第一个元素之前的地址进行比较
    for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--)
    {
        *vp = 0;
    }
 
    return 0;
}

二级指针

指针变量也是一个变量,每一个变量都会存放到内存中,也就会有地址。二级指针,就是用来存放一级指针变量地址的变量。因此,存放一级指针变量地址的指针为二级指针,存放二级指针变量地址的指针为三级指针,以此类推。

 

指针与数组

可见数组名和数组首元素的地址是相同的。 因为数组是一块连续的空间,所以可以用指针指向数组首元素的地址,通过指针的加减来访问数组的每一个空间。

arr可以理解为一个变量,即一个内存空间。

二、字符指针

将字符变量的地址放到字符指针中称为字符指针。一种比较特殊的字符指针指向的是常量池中字符串首字符的地址,常量池当中的字符串是不能修改的。而将字符串放到数组当中进行存储的值是可以修改的。

char a = ‘w’;

char* pa = &a;

char* p = "abcdef";

备注:const加在*前表示不能修改指针所指向空间的值,const加在*后表示不能修改指针的指向

字符串数组和常量字符串的区别:

int main()
{
	//用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块
	//str1,str2字符串数组存放的是对应字符的asc码值
	//值虽然相同但是他们是两个不同数组,开辟的地址也是不同的
	char str1[] = "hello bit.";
	char str2[] = "hello bit.";
	
	//字符指针str3,str4存放的是字符串常量池的字符,存放的都是字符'h'的地址
	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;
}

三、指针数组

整型数组 - 存放整型的数组
字符数组 - 存放字符的数组
指针数组 - 存放指针(地址)的数组
指针数组是存放指针的数组,每种类型的数据都可以创建数组,但是数组也可以是由指针组成。

存放字符指针的数组

参数pc是是一个二级指针,存储的是abcdef字符串的地址,每次挪1字节

存放数组首地址的指针数组

四、数组指针

字符指针——存放字符地址的指针——指向字符的指针 char*
整型指针——存放整型地址的指针——指向整型的指针 int*
浮点型的指针——存放浮点型地址的指针——指向浮点型的指针 float*  double*
数组指针——存放数组地址的指针——指向数组的指针

数组名和&数组名的区别:

数组指针的使用,使用一:两种打印数组的方式

数组指针的使用,使用二:二维数组的使用

//正常的接受二维数组的参数
void print1(int arr[3][4], int r, int c)
{
	int i = 0;
	for (i = 0; i < r; i++)
	{
		int j = 0;
		for (j = 0; j < c; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
}
 
//用数组指针来接受二维数组,表示的是数组的第几行
void print2(int(*p)[4], int r, int c)
{
	int i = 0;
	for (i = 0; i < r; i++)
	{
		int j = 0;
		for (j = 0; j < c; j++)
		{			
			//printf("%d ", (*(p + i))[j]);
			printf("%d ", p[i][j]);
		}
		printf("\n");
	}
}
 
int main()
{
	int arr[3][4] = { {1,2,3,4}, {2,3,4,5} , {3,4,5,6} };
	print1(arr, 3, 4);
    printf("\n");
    
    //数组名arr,表示首元素的地址
    //但是二维数组的首元素是二维数组的第一行
    //所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
    //可以数组指针来接收
	print2(arr, 3, 4);
 
	return 0;
}

 

函数指针

函数指针的定义与使用

类型名  (*指针变量名)(函数参数)  = &函数名(或者直接写函数名)
//函数指针
int Add(int x, int y)
{
	return x + y;
}
 
int main()
{
	
	//pf 是一个存放函数地址的指针变量 -  函数指针
 
	int (*pf)(int, int) = &Add;//可以理解为&Add给pf
 
	int ret = (*pf)(2,3);
 
	//&函数名和函数名都是函数的地址
	int (*pf)(int, int) = Add;

	//int ret = Add(2, 3);
	int ret = pf(2, 3);
 
	printf("%d\n", ret);
 
	return 0;
}

函数名也可以理解为一个指针变量,指针变量就是一块内存,内存中记录一个地址;变量也是一块内存直接记录值。*a取a的值,&a取a的低地址,a标识一块内存。

函数指针数组

函数指针数组的定义

数组是一个存放相同类型数据的存储空间,前面有讲到指针数组,那要把函数的地址存到一个数组中,那这个数组就叫函数指针数组。

                    数据类型 ( * 数组名[数值] ) (函数参数);
如:

int ( * parr1 [ 10 ])();
int * parr2 [ 10 ]();

函数指针数组的使用(转移表)

void menu()
{
	printf("*******************************\n");
	printf("****** 1. add   2. sub    *****\n");
	printf("****** 3. mul   4. div    *****\n");
	printf("****** 0. exit            *****\n");
	printf("*******************************\n");
}
 
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 (*pf[5])(int, int) = { NULL, Add, Sub, Mul, Div };
 
int main()
{
	int input = 0;
	int x = 0;
	int y = 0;
	int ret = 0;
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		if (input == 0)
		{
			printf("退出计算器\n");
			break;
		}
		else if (input>=1 &&input<=4)
		{
			printf("请输入两个操作数:>");
			scanf("%d %d", &x, &y);
			ret = pf[input](x, y);
			printf("%d\n", ret);
		}
		else
		{
			printf("选择错误\n");
		}
	} while (input);
 
	return 0;
}

指向函数指针数组的指针

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

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

回调函数

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

void menu()
{
	printf("*******************************\n");
	printf("****** 1. add   2. sub    *****\n");
	printf("****** 3. mul   4. div    *****\n");
	printf("****** 0. exit            *****\n");
	printf("*******************************\n");
}
 
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;
}
 
void calc(int (*pf)(int, int))
{
	int x = 0;
	int y = 0;
	int ret = 0;
	printf("请输入两个操作数:>");
	scanf("%d %d", &x, &y);
	ret = pf(x, y);
	printf("%d\n", ret);
}
 
int main()
{
	int input = 0;
	
	do 
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			calc(Add);
			break;
		case 2:
			calc(Sub);
			break;
		case 3:
			calc(Mul);
			break;
		case 4:
			calc(Div);
			break;
		case 0:
			printf("退出计算器\n");
			break;
		default:
			printf("选择错误\n");
			break;
		}
	} while (input);
 
	return 0;
}

指针与数组

一维数组

int main()
{
	//一维数组
	int a[] = { 1,2,3,4 };//4*4=16
	printf("%d\n", sizeof(a));//16
	printf("%d\n", sizeof(a + 0));//a+0 其实是数组第一个元素的地址,是地址就是4/8字节
	printf("%d\n", sizeof(*a));//*a是数组首元素,计算的是数组首元素的大小,单位是字节,4
	printf("%d\n", sizeof(a + 1));//a+1是第二个元素的地址,是地址大小就是4/8
	printf("%d\n", sizeof(a[1]));//a[1]是第二个元素,计算的是第二个元素的大小-4-单位是字节
	printf("%d\n", sizeof(&a));//&a是整个数组的地址,整个数组的地址也是地址,地址的大小就是4/8字节
	//&a---> 类型:int(*)[4]
 
	printf("%d\n", sizeof(*&a));//&a是数组的地址,*&a就是拿到了数组,*&a--> a,a就是数组名,sizeof(*&a)-->sizeof(a)
	//计算的是整个数组的大小,单位是字节-16
 
	printf("%d\n", sizeof(&a + 1));//&a是整个数组的地址,&a+1,跳过整个数组,指向数组后边的空间,是一个地址,大小是4/8字节
	printf("%d\n", sizeof(&a[0]));//&a[0]是首元素的地址,计算的是首元素地址的大小,4/8字节
	printf("%d\n", sizeof(&a[0] + 1));//&a[0] + 1是第二个元素的地址,地址的大小就是4/8字节
	return 0;
}

字符数组

int main()
{
	//字符数组
	char arr[] = { 'a','b','c','d','e','f' };
	//char*
	//char [6]
	printf("%d\n", strlen(arr));//随机值
	printf("%d\n", strlen(arr + 0));//随机值
	//printf("%d\n", strlen(*arr));//strlen('a')->strlen(97),非法访问-err
	//printf("%d\n", strlen(arr[1]));//'b'-98,和上面的代码类似,是非法访问 - err
	printf("%d\n", strlen(&arr));//&arr虽然是数组的地址,但是也是从数组起始位置开始的,计算的还是随机值
	//char(*)[6]
	printf("%d\n", strlen(&arr + 1));
	//&arr是数组的地址,&arr+1是跳过整个数组的地址,求字符串长度也是随机值
	printf("%d\n", strlen(&arr[0] + 1));//&arr[0] + 1是第二个元素的地址,是'b'的地址,求字符串长度也是随机值
 
	printf("%d\n", sizeof(arr));//arr单独放在sizeof内部,计算的是整个数组的大小,单位是字节,6
	printf("%d\n", sizeof(arr + 0));//arr + 0是数组首元素的地址,4/8
	printf("%d\n", sizeof(*arr));//*arr是数组的首元素,计算的是首元素的大小-1字节
	printf("%d\n", sizeof(arr[1]));//arr[1]是第二个元素,大小1字节
	printf("%d\n", sizeof(&arr));//取出的数组的地址,数组的地址也是地址,是地址大小就是4/8
	printf("%d\n", sizeof(&arr + 1));//&arr+1是跳过整个,指向数组后边空间的地址,4/8
	printf("%d\n", sizeof(&arr[0] + 1));//&arr[0] + 1是数组第二个元素的地址,是地址4/8字节
 
	return 0;
}

int main()
{
	char arr[] = "abcdef";//数组是7个元素
	//[a b c d e f \0]
	printf("%d\n", strlen(arr));//6,arr是数组首元素的地址,strlen从首元素的地址开始统计\0之前出现的字符个数,是6
	printf("%d\n", strlen(arr + 0));//arr + 0是数组首元素的地址,同第一个,结果是6
	printf("%d\n", strlen(*arr));//*arr是'a',是97,传给strlen是一个非法的地址,造成非法访问
	printf("%d\n", strlen(arr[1]));//err
	printf("%d\n", strlen(&arr));//6
	printf("%d\n", strlen(&arr + 1));//&arr + 1是跳过数组后的地址,统计字符串的长度是随机值
	printf("%d\n", strlen(&arr[0] + 1));//&arr[0]+1是b的地址,从第二个字符往后统计字符串的长度,大小是5
 
	printf("%d\n", sizeof(arr));//7 - 数组名单独放在sizeof内部,计算的是数组的总大小,单位是字节
	printf("%d\n", sizeof(arr + 0));//arr+0是首元素的地址,大小是4/8
	printf("%d\n", sizeof(*arr));//*arr是数组首元素,大小是1字节
	printf("%d\n", sizeof(arr[1]));//arr[1]是数组的第二个元素,大小是1字节
	printf("%d\n", sizeof(&arr));//&arr是数组的地址,数组的地址也是地址,是4/8字节
	printf("%d\n", sizeof(&arr + 1));//&arr + 1是跳过整个数组的地址,是4/8字节
	printf("%d\n", sizeof(&arr[0] + 1));//&arr[0] + 1是第二个元素的地址,是4/8字节
 
	return 0;
}

int main()
{
	const char* p = "abcdef";
	
	printf("%d\n", strlen(p));//6- 求字符串长度
	printf("%d\n", strlen(p + 1));//p + 1是b的地址,求字符串长度就是5
	printf("%d\n", strlen(*p));//err,*p是'a'
	printf("%d\n", strlen(p[0]));//err - 同上一个
	printf("%d\n", strlen(&p));//&p拿到的是p这个指针变量的起始地址,从这里开始求字符串长度完全是随机值
	printf("%d\n", strlen(&p + 1));//&p+1是跳过p变量的地址,从这里开始求字符串长度也是随机值
	printf("%d\n", strlen(&p[0] + 1));//&p[0] + 1是b的地址,从b的地址向后数字符串的长度是5
 
	printf("%d\n", sizeof(p));//p是指针变量,大小就是4/8字节
	printf("%d\n", sizeof(p + 1));//p + 1是b的地址,是地址,就是4/8个字节
	printf("%d\n", sizeof(*p));//*p是'a',sizeof(*p)计算的是字符的大小,是1字节
	printf("%d\n", sizeof(p[0]));//p[0]-->*(p+0) --> *p  就同上一个,1字节
	printf("%d\n", sizeof(&p));//&p是二级指针,是指针大小就是4/8
	printf("%d\n", sizeof(&p + 1)); //&p + 1是跳过p变量后的地址,4/8字节
	printf("%d\n", sizeof(&p[0] + 1));//p[0]就是‘a’,&p[0]就是a的地址,+1,就是b的地址,是地址就是4/8
 
	return 0;
}

 

二维数组

int main()
{
	//二维数组
	int a[3][4] = { 0 };
	//printf("%p\n", &a[0][0]);
	//printf("%p\n", a[0]+1);
 
 
	printf("%d\n", sizeof(a));//48 = 3*4*4
	printf("%d\n", sizeof(a[0][0]));//4
	printf("%d\n", sizeof(a[0]));//a[0]是第一行的数组名,数组名单独放在sizeof内部,计算的就是数组(第一行)的大小,16个字节
	printf("%d\n", sizeof(a[0] + 1));//a[0]作为第一行的数组名,没有单独放在sizeof内部,没有取地址,表示的就是数组首元素的地址
	//那就是a[0][0]的地址,a[0]+1就是第一行第二个元素的地址,是地址就是4/8个字节
	printf("%d\n", sizeof(*(a[0] + 1)));//*(a[0] + 1)是第一行第2个元素,计算的是元素的大小-4个字节
	printf("%d\n", sizeof(a + 1));//a是二维数组的数组名,数组名表示首元素的地址,就是第一行的地址,a+1就是第二行的地址
	//第二行的地址也是地址,是地址就是4/8   
	//a - int (*)[4]
	//a+1--> int(*)[4]
	printf("%d\n", sizeof(*(a + 1)));//a+1是第二行的地址,*(a+1)表示的就是第二行,*(a+1)--a[1]  //16
	printf("%d\n", sizeof(&a[0] + 1));//&a[0]是第一行的地址,&a[0]+1是第二行的地址,地址的大小就是4/8
	printf("%d\n", sizeof(*(&a[0] + 1)));//*(&a[0] + 1) 是对第二行的地址解引用,得到的就是第二行,计算的就是第二行的大小
	printf("%d\n", sizeof(*a));//a表示首元素的地址,就是第一行的地址,*a就是第一行,计算的就是第一行的大小
	//*a -- *(a+0)--a[0]
	printf("%d\n", sizeof(a[3]));//16字节 int[4]
	//如果数组存在第四行,a[3]就是第四行的数组名,数组名单独放在sizeof内部,计算的是第四行的大小
 
	int a = 10;
	printf("%d\n", sizeof(int));
 
	return 0;
}

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

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

相关文章

FreeRTOS调度器启动过程分析

目录 引出思考 vTaskStartScheduler()启动任务调度器 xPortStartScheduler()函数 FreeRTOS启动第一个任务 vPortSVCHandler()函数 总结 引出思考 首先想象一下如何启动第一个任务&#xff1f; 假设我们要启动的第一个任务是任务A&#xff0c;那么就需要将任务A的寄存器值…

腾讯云手动下发指令到设备-用于设备调试

打开腾讯云API Explorer&#xff0c;Publish Msg https://console.cloud.tencent.com/api/explorer?Productiotcloud&Version2021-04-08&ActionPublishMessagehttps://console.cloud.tencent.com/api/explorer?Productiotcloud&Version2021-04-08&ActionPub…

【模电】设置静态工作点的必要性

设置静态工作点的必要性 静态工作点为什么要设置静态工作点 静态工作点 在放大电路中&#xff0c;当有信号输入时&#xff0c;交流量与直流量共存。将输入信号为零、即直流电源单独作用时晶体管的基极电流 I B I\tiny B IB、集电极电流 I C I\tiny C IC、b - e间电压 U B E U\t…

语义分割网络FCN

语义分割是一种像素级的分类&#xff0c;输出是与输入图像大小相同的分割图&#xff0c;输出图像的每个像素对应输入图像每个像素的类别&#xff0c;每一个像素点的灰度值都是代表当前像素点属于该类的概率。 语义分割任务需要解决的是如何把定位和分类这两个问题一起解决&…

佛罗里达大学利用神经网络,解密 GPCR-G 蛋白偶联选择性

内容一览&#xff1a;G 蛋白偶联受体 (GPCRs) 是一种将细胞膜外的刺激&#xff0c;传递到细胞膜内的跨膜蛋白&#xff0c;广泛参与到人体生理活动当中。近日&#xff0c;佛罗里达大学的研究者测定了 GPCRs 和 G 蛋白的结合选择性&#xff0c;并开发了预测二者选择性的算法&…

kubernetes监控GPA安装部署

本文在于指导如何对k8s的监控GPA(Grafana&#xff0c;prometheus以及alertmanager)进行安装部署。 1. 介绍 Prometheus 在真正部署Prometheus之前&#xff0c;应了解一下Prometheus的各个组件之间的关系及作用&#xff1a; 1&#xff09;MertricServer&#xff1a;是k8s集群…

朋友圈7大黄金发圈时间

众所周知&#xff0c;朋友圈运营是私域运营必不可少的重要环节。 因为做好朋友圈运营&#xff0c;能够打造形成高质量、高价值的私域流量&#xff0c;加快实现用户成交。 那么如何形成一个吸粉又吸金的人设&#xff0c;做出高质量的朋友圈发圈内容呢&#xff1f; 那么如何确保能…

SSM整合(注解版)

SSM 整合是指将学习的 Spring&#xff0c;SpringMVC&#xff0c;MyBatis 进行整合&#xff0c;来进行项目的开发。 1 项目基本的配置类 1.1 Spring 配置类 这个配置类主要是管理 Service 中的 bean&#xff0c;controller 层的 bean 对象是 SpringMVC 管理的 package cn.ed…

二极管:二极管的基本原理

一、认识导体、绝缘体、半导体 什么是导体&#xff1f; 导体 conductor &#xff0c;是指电阻率很小&#xff0c;且容易传导电流的物质。导体中存在大量可自由移动的带电粒子&#xff0c;也称为载流子。在外电场的作用下&#xff0c;载流子作定向运动&#xff0c;形成电流。 …

安装配置JDK1.8

JDK1.8的下载及配置 1.进入甲骨文官网甲骨文官网往下翻找到java8并且点击windows. 2.下载Java8必须登录账号 3下载完后点击进入安装&#xff0c;直接下一步就可以&#xff0c;记住这个路径。 4.右击我的电脑进入环境配置&#xff0c;新增变量。 CLASSPATH .;%JAVAHOME%\lib;…

3.C程序编译步骤

目录 1 预处理 2 编译 3 汇编 4 链接 5 文件大小情况 依次执行下面4个步骤 预处理 将所有头文件展开&#xff0c;比如stdio.h等&#xff0c;展开就相当于把stdio.h中的所有代码粘贴到你的代码里。将所有的宏文件展开&#xff0c;像stdio.h是官方定义的头文件&#x…

C# - Opencv应用(3) 之矩阵Mat使用[图像截取粘贴、ROI操作、位运算、数学计算]

C# - Opencv应用&#xff08;3&#xff09; 之矩阵Mat使用[图像截取粘贴、ROI操作、位运算、数学计算] 图像读取&#xff0c;大小、截取、位运算图像ROI操作&#xff1a;粘贴赋值、滤波图像数学计算部分结果如下&#xff1a; 1.图像读取&#xff0c;大小、截取、位运算 //图…

计算机辅助药物设计AIDD-小分子-蛋白质|分子生成|蛋白质配体相互作用预测

文章目录 计算机辅助药物设计AIDD【小分子专题】AIDD概述及药物综合数据库学习机器学习辅助药物设计图神经网络辅助药物设计自然语言处理辅助药物设计药物设计与分子生成 计算机辅助药物设计【蛋白质专题】蛋白质数据结构激酶-Kinase相似性学习基于序列的蛋白质属性预测基于结构…

解决xshell连接诶树莓派中文乱码的问题

系统版本 解决办法 在根目录下找到 /etc/profile 修改profile文件,添加以下两行.以便重启之后也能生效: export LANGzh_CN.utf8 export LC_ALLzh_CN.utf8注意: /etc/profile的修改需要root权限才能修改! 在xshell的编码格式改为UTF-8

一次性客户的笔记总结

创建一次性客户&#xff0c;系统会给出一个客户编码&#xff1b; 每次记账的时候&#xff0c;在录入过账码及客户编码后&#xff0c;点击回车&#xff0c;都需要录入这个客户的详细信息&#xff08;比如 客户名称等&#xff09; 一次性客户的信息存储在BSEC表中&#xff0c;这种…

飞致云1panel + 雷池WAF

可能有许多人都有这个需求&#xff1a;为自己的个人站点套上WAF&#xff0c;增加安全性&#xff0c;本文将介绍如何将1panel面板深度结合长亭雷池防火墙&#xff0c;实现为个人站点套上WAF并且自动续签ssl证书。 前提条件&#xff1a; 服务器IP已绑定域名 完整的1panel环境 …

springboot简单集成上传和下载(带页面)

来学习一下文件上传和下载 一、页面开发 整体思路 登录页 主页 二、库表设计 SET FOREIGN_KEY_CHECKS0;-- ---------------------------- -- Table structure for t_files -- ---------------------------- DROP TABLE IF EXISTS t_files; CREATE TABLE t_files (id int(11) N…

【五分钟】熟练使用numpy.cumsum()函数(干货!!!)

引言 numpy.cumsum()函数用于计算输入数组的累积和。当输入是多维数组时&#xff0c;numpy.cumsum()函数可以沿着指定轴计算累积和。 计算一维数组的累计和 代码如下&#xff1a; # 计算一维数组的累计和 tmp_array np.ones((4,), dtypenp.uint8) # [1, 1, 1, 1] print(&…

java--接口概述

1.认识接口 ①java提供了一个关键字interface&#xff0c;用这个关键字我们可以定义出一个特殊的结构&#xff1a;接口。 ②注意&#xff1a;接口不能创建对象&#xff1b;接口是用来被类实现(implements)的&#xff0c;实现接口的类称为实现类。 ③一个类可以实现多个接口(接…

1、Spring基础概念总结

Spring概述&#xff1a; Spring体系结构 IOC的概念和作用 耦合指的是对象之间的依赖关系&#xff0c;耦合越小越好 以jdbc为例 通过反射来注册驱动&#xff0c;那么会造成驱动名称写死在程序当中&#xff0c;这种结果显然是不太合理的通过配置文件的形式可以解决这种耦合问…