C/C++:指针用法详解
C/C++:指针
指针概念
指针变量也是一个变量
指针存放的内容是一个地址,该地址指向一块内存空间
指针是一种数据类型
指针变量定义
内存最小单位:BYTE字节(比特)
对于内存,每个BYTE都有一个唯一不同的编号,这个编号就是内存的地址
一个地址编号对应的是一个BYTE的空间大小
一个地址编号在32位系统下,是一个4个字节的无符号整数;在64位系统下是一个8个字节的无符号整数
//描 述:指针的定义
#include <stdio.h>int main()
{int *p;//定义int型指针变量,名字为p,int型(可以执行int型地址)int a; //定义int型变量aa = 1;p = &a;//把a的内存地址赋值给pprintf("%p\n",p);//00B7FB24 实际上a占了4个字节(地址编号),但是只输出第一个地址编号//64位系统下a占8个字节,这也是为什么32位系统下内存用的少,64位内存用的多return 0;
}
int *p;
//p:指针变量,存放地址
//*p:指针所指内存的实际数据
*p = 10//p指向的地址存放的值是10
//指针变量只能存放地址,不能将一个int型变量直接赋值给一个指针
取地址符号&(found/address)
&可以获取一个变量在内存中的地址
register int a;//register限定符,a变成寄存器变量,存放在cpu里而不是内存中,所以是没有地址的,不能用&进行取地址操作
void指针
void代表无类型,可以指向任何类型的地址
//描 述:void指针
#include <stdio.h>int main01()
{int *p;int a;a = 1;p = &a;//把a的内存地址赋值给p*p = 10; //通过指针变量间接访问a的值,把a的值改为10printf("a = %d\n",a);printf("*p = %d\n",*p);a = 100; //修改a的值时*p的值也会变化printf("a = %d\n",a);printf("*p = %d\n",*p);int b = 2; p = &b; //现在指针变量p指向了b(指来指去)*p = 50;printf("b = %d\n",b);printf("*p = %d\n",*p);a = 123456;//char *p1 = &a;//p1为char型指针变量,a为int型变量//char *p1 = (char*)&a;//强制转换会导致错误的结果void *p2 = &a;//void代表无类型,可以指向任何类型的地址 return 0;
}
指针占用内存
在同一个系统下,不管指向什么类型的变量,地址编号的大小总是一样的(32位系统占4个BYTE,64位系统占8个BYTE),但是不同类型变量占用的内存是不同的,见下方的代码
就像在一个酒店里,不管是单人间,双人间还是标准间,门牌号的大小都是一样的(4位数/8位数)
//描 述:指针占用内存说明
#include <stdio.h>int main02()
{char *p;int *p1;long long *p2;printf("%lu,%lu,%lu", sizeof(p),sizeof(p1),sizeof(p2));//结果:4,4,4return 0;
}
上述的代码与下面的代码进行比较
//描 述:不同类型变量占用的内存大小#include<stdio.h>int main05()
{int a[10];printf("%p,%p,%p\n",a,&a[0],&a[1]);//输出结果:0135FCA0,0135FCA0,0135FCA4//a与&a[0]是一样的,&a[0]与&a[1]中间有0135FCA0、1、2、3,因为一个int型变量占4个内存(4个地址编号)char b[10];printf("%p,%p,%p\n",b,&b[0],&b[1]);//输出结果:0076FB24,0076FB24,0076FB25//一个char类型变量占一个内存(地址编号)long long c[10];printf("%p,%p,%p\n",c,&c[0],&c[1]);//输出结果:008FFC84,008FFC84,008FFC8Creturn 0;
}
空指针与野指针
空指针:如果一个指针变量没有明确得指向一块内存,那么就把这个指针变量指向NULL,空指针是合法的
野指针:没有初始化过值的指针(没有指定内存),野指针是非法的
程序中避免野指针,可以使用空指针
//描 述:空指针与野指针#include<stdio.h>int main03()
{/*野指针int *p;*p = 100;//没有指定内存*///空指针int *p1;p1 = NULL;return 0;
}
指针的兼容性
指针类型之间一定要匹配,指针之间的赋值比普通数据类型之间的赋值要更严格
int a;
double b = 3.45;
a = b;//正确,a = 3
int *p = &b;//错误,类型不一致
大白话:不要把指针想的太神秘,指针变量只是个变量而已,它里面放的就是一些地址编号,这些地址编号就是无符号的整数,在32位系统下是4个字节,在64位系统下是8个字节,但是这些整数不能直接赋值,来源于另外一个变量的取地址操作
指向常量的指针与指针常量
指向常量的指针
int a = 1;
const int *p = &a;//p可以指向一个int类型的地址,但不可以用*p的方式修改这个内存的值
*p = 10;//会报错:不能给常量赋值
printf("a = %d\n",a);
对于常量来说,值不能改变
const int b = 0;
b = 10;//报错,b为常量,值不能改变
但是可以创建一个指针指向它,修改
const int b = 0;
int *p = &b;
*p = 0;//不会报错,但是会warning,实际上这是不合理的,c语言的漏洞
c语言中的const是有问题的,可以通过指针变量间接修改const常量的值(c++中是无法修改的),所以在c语言中用#define常量的时候更多
指针常量
int *const p2 = &a;//p2只能指向a的地址
p2 = &b;//错误,p2是一个常量指针,只能指向固定的一个变量a的地址
//但是可以通过*p2来读写这个变量的值
*p2 = 10;
注意区分常量指针与指针常量
指针与数组的关系
p=a;数组的名字就代表数组第一个元素的地址,等同于 p = &a[0]
p1 = &a[5];//把a5的地址给指针p1
*p1 = 1000;//改变a[5]的值
p1[2] = 666;//p1指向a[5],则p1[2]顺延指向a[7],改变的是a[7]的值,把数组想象成一个队列
p[3] = 100;//当指针变量指向一个数组的时候,c语言语法规定指针变量名可以当数组名用,区别在哪里?
//区别:
printf("%lu,%lu\n", sizeof(a),sizeof(p));//对数组来讲返回数组的大小40,对指针来讲返回指针的大小4
//描 述:指针与数组的关系#include<stdio.h>int main()
{int a[10] = {1,2,3,4,5,6,7,8,9,10};int *p;p = a;//可以这样指向,数组的名字就代表数组第一个元素的地址,等同于 p = &a[0]int *p1;p1 = &a[5];//把a5的地址给指针p1*p1 = 1000;p1[2] = 666;//p1指向a[5],则p1[2]顺延指向a[7],改变的是a[7]的值,把数组想象成一个队列p[3] = 100;//当指针变量指向一个数组的时候,c语言语法规定指针变量名可以当数组名用,区别在哪里?//区别:printf("%lu,%lu\n", sizeof(a),sizeof(p));//对数组来讲返回数组的大小40,对指针来讲返回指针的大小4int i;for(i=0;i<10;i++){printf("a[%d]=%d\n",i,a[i]);printf("a[%d]=%d\n",i,p[i]);//像数组一样使用指针}return 0;
}
/*
运算结果:
40,4
a[0]=1
a[0]=1
a[1]=2
a[1]=2
a[2]=3
a[2]=3
a[3]=100
a[3]=100
a[4]=5
a[4]=5
a[5]=1000
a[5]=1000
a[6]=7
a[6]=7
a[7]=666
a[7]=666
a[8]=9
a[8]=9
a[9]=10
a[9]=10
*/
指针运算
指针变量可以计算,int* 类型加一,变化4个整数(增加4个字节),char* 类型加一,变化1个整数
//描 述:指针运算-加一#include<stdio.h>int main07()
{int a = 0;int *p = &a;printf("%p,%p,%p\n",p,p+1,p+2);//结果:0118FCA4,0118FCA8,0118FCAC(加1操作加4个字节)char c = 0;char *p1 = &c;printf("%p,%p,%p\n",p1,p1+1,p1+2);//结果:0075F937,0075F938,0075F939return 0;
}
//描 述:指针运算2#include<stdio.h>int main()
{int a[10] = { 0 };int *p1 = a;p1 += 5;*p1 = 1;p1 -= 2;*p1 = 3;//p1 *= 2;//混淆int i;for(i=0;i<10;i++){printf("a[%d]=%d; ",i,a[i]);//结果:a[0]=0; a[1]=0; a[2]=0; a[3]=3; a[4]=0; a[5]=1; a[6]=0; a[7]=0; a[8]=0; a[9]=0;}return 0;
}
增加/减少指针值:p++;p–
求差值:pa-pb,通常用于同一个数组内求两个元素之间的距离
比较:pa == pb,通常用来比较两个指针是否指向同一个位置
通过指针使用数组元素
//描 述:指针与数组#include<stdio.h>int main00()
{int a[10] = {1,2,3,4,5,6,7,8,9};int *p = a;p[3] = 100;//等同于下面一句,一般习惯这样写,简洁//*[p+3] = 100;int i;for(i=0;i<10;i++){printf("a[%d] = %d\n",i,a[i]);}return 0;
}int main()
{//c语言中所有数据类型都可以理解为一个char的数组int a = 0x12345678;//0x开头,16进制,int是4个字节,可以视作4个char(12,34,56,78)的数组char *p = (char *)&a;//为了防止出现warning,使用强制转换printf("%x,%x\n", *p,p[1]);//结果:78,56,倒着放,小端对齐的概念*p = 0;//相当于p[0],a[0]printf("%x,%x\n", *p,p[1]);p[2] = 0;printf("%x\n",a);//结果:12005678printf("--------------------\n");char b[20] = {0};int *p1 = (int *)&b;//防止warning强转p1[3] = 0x12345678;//int占4个字符,3*4=12,从第13个位置也就是b[12]开始放(倒着放,小端对齐概念)int i;for(i=0;i<20;i++){printf("b[%d] = %x\n",i,b[i]);}
/*输出
--------------------
b[0] = 0
b[1] = 0
b[2] = 0
b[3] = 0
b[4] = 0
b[5] = 0
b[6] = 0
b[7] = 0
b[8] = 0
b[9] = 0
b[10] = 0
b[11] = 0
b[12] = 78
b[13] = 56
b[14] = 34
b[15] = 12
b[16] = 0
b[17] = 0
b[18] = 0
b[19] = 0
*/return 0;
}
c语言中所有数据类型都可以理解为一个char的数组
练习:把ip地址转化为整数
输入ip地址
char a[100]=“192.168.2.5”
把这个ip转化为unsigned int类型的整数
//描 述:把ip地址转化为整数#include<stdio.h>int main003()
{char a[] = "192.168.2.5";unsigned int ip = 0;unsigned char *p = (unsigned char *)&ip;int a1,a2,a3,a4;sscanf(a,"%d.%d.%d.%d",&a1,&a2,&a3,&a4);printf("%d,%d,%d,%d\n",a1,a2,a3,a4);p[0] = a4;p[1] = a3;p[2] = a2;p[3] = a1;printf("%u\n",ip);//运行结果:192,168,2,5 3232236037return 0;
}
练习:利用指针进行多维数组排序
//描 述:指针的灵活性——利用指针对多维数组进行排序#include<stdio.h>int main()
{char a[2][5] = {{3,4,1,2,9},{3,44,98,0,5}};//把二维数组"拉直"当成一维数组char *p =(char *)a;int i,j;for(i=0;i<10;i++){for(j=0;j<10-i;j++){if(p[j]<p[j-1]){char tmp = p[j];p[j] = p[j-1];p[j-1] = tmp;}}}for(i=0;i<2;i++){for(j=0;j<5;j++){printf("%d\n",a[i][j]);}}return 0;
}
指针数组
指针数组的定义:
char *a[10];//定义指针数组a,每个成员是char*类型的,一共10个成员
int *b[10];//定义指针数组b,每个成员是int*类型的,一共10个成员
printf("%lu,%lu\n",sizeof(a),sizeof(b));//结果:40,40
给数组成员赋值:
char i = 0;
//a = &i;//a和b为数组名,数组名不能作为左值
//b = &i;
a[0] = &i;//合法
printf("%lu,%lu\n",sizeof(a[0]),sizeof(*a[0]));//输出结果4,1
//描 述:指针数组#include<stdio.h>int main0000()
{char *a[10];//定义指针数组a,每个成员是char*类型的,一共10个成员int *b[10];//定义指针数组b,每个成员是int*类型的,一共10个成员printf("%lu,%lu\n",sizeof(a),sizeof(b));//结果:40,40char i = 0;//a = &i;//a和b为数组名,数组名不能作为左值//b = &i;a[0] = &i;//合法printf("%lu,%lu\n",sizeof(a[0]),sizeof(*a[0]));//输出结果4,1return 0;
}int main0001()
{int *b[10] = { NULL };int a,b1,c;b[0] = &a;b[1] = &b1;b[2] = &c;*b[0] = 10;printf("%d\n",a);return 0;
}
二级指针——指向指针的指针
int a = 0; 地址是0x123456
int *p = &a; p为0x123456,*p为0,指针p的存放地址是0x100
int **pp = &p; pp为0x100(p的地址), *pp为0x123456,**pp为0
//描 述:二级指针#include<stdio.h>//二级指针
int main0002()
{int a = 0;int *p = &a;int **pp;//二级指针,二级指针pp存放指针p的地址,pp = &p;//int **pp = &p;//前两句的结合体return 0;
}//二级指针与数组
int main0003()
{int a[10];int *p = a;//p是指向数组a的指针p[0] = 0;p[1] = 2;int *b[10];//定义指针数组bint **p1 = b;//定义指向指针数组b的二级指针p1(不能用一级指针指向b)p1[0] = NULL;printf("%lu\n",sizeof(p1[0]));//运行结果:4return 0;
}
对于一个指针变量b,想指向它需要定义一个二级指针a
多级指针
能用低级指针的尽量不要用高级指针,一级指针二级指针最常用,三级指针很少
//描 述:二级指针#include<stdio.h>//二级指针
int main0002()
{int a = 0;int *p = &a;int **pp;//二级指针,二级指针pp存放指针p的地址,pp = &p;//int **pp = &p;//前两句的结合体return 0;
}//二级指针与数组
int main0003()
{int a[10];int *p = a;//p是指向数组a的指针p[0] = 0;p[1] = 2;int *b[10];//定义指针数组bint **p1 = b;//定义指向指针数组b的二级指针p1(不能用一级指针指向b)p1[0] = NULL;printf("%lu\n",sizeof(p1[0]));//运行结果:4return 0;
}
int a = 0;
int *p = &a;
int **pp = &p;//pp代表p的地址,*pp代表a的地址,**pp代表a的值
int ***ppp = &pp;//ppp代表pp的地址,*ppp代表p的地址,**ppp代表a的地址,***ppp代表a的值
函数的参数作为指针变量
c语言想通过函数内部修改实参的值,只能给函数实参传递实参的地址来间接修改实参的值
//描 述:函数的参数作为指针变量#include<stdio.h>void swap(int *a,int *b)
{int tmp = *a;*a = *b;*b = tmp;
}int main0006()
{int a = 1;int b = 2;swap(&a,&b);//c语言想通过函数内部修改实参的值,只能给函数实参传递实参的地址来间接修改实参的值printf("a=%d,b=%d\n",a,b);return 0;
}
思考代码为什么输出为4和40?
//描 述:当数组名作为函数形参时,c语言将数组名解析为指针#include<stdio.h>//void test(int a[10])
void test(int *a)//最常用最简单
//void test(int a[])
{printf("%lu\n",sizeof(a));//输出结果:4a[5] = 100;
}
int main()
{int a[10] = {1,2,3,4,5,6,7,8,9,10};printf("%lu\n",sizeof(a));//输出结果:40printf("----------------\n");test(a);int i;for(i=0;i<10;i++){printf("a[%d]=%d\n",i,a[i]);/*结果:a[0]=1a[1]=2a[2]=3a[3]=4a[4]=5a[5]=100a[6]=7a[7]=8a[8]=9a[9]=10*/}return 0;
}
以下三条语句是一样的:
void test(int a[10])//当数组名作为函数形参时,c语言将数组名解析为指针
void test(int *a)//最常用最简单
void test(int a[])
函数指针参数使用const保护:
void test(const int *a)//为了不让函数内部修改数组成员的值
在c语言中,可以转个弯(强转)在函数内部修改成员的值(限制菜鸟),但是在c++中是改不了的
函数的返回类型可以是指针类型
int *test()
{return NULL;
}
memset与memcpy与memmove
memset:将指定区域的内存置空(参数1:指定要置空内存的首地址;参数2:0;参数3:这块内存的大小,单位,字节)
memset(a,0,sizeof(a));
//描 述:memset:将指定区域的内存置空(参数1:指定要置空内存的首地址;参数2:0;参数3:这块内存的大小,单位,字节)#include<stdio.h>
#include<string.h>
int main0008()
{int a[10] = {1,2,3,4,5,6,7,8,9,10};//a[10] = { 0 };//错误赋值方法,这种初始化的方法只能在创建a数组时才能用//如果要把数组a置空,需要遍历修改/*int i;for(i= 0;i<10;i++){a[i] = 0;}*///采用memset可以简化上述的代码,需要加string.h的头文件memset(a, 0, sizeof(a));//memset(a, 0 ,10);//错误,只会把前10个字节清空/*int *p = a;memset(a, 0 ,sizeof(p));错误,指针变量的大小是8或4,所以只会清空前两个或者前一个字节*/int i;for (i=0;i<10;i++){printf("a[%d] = %d",i,a[i]);}return 0;
}
memcpy:在两块内存之间拷贝数据(参数1:目标地址;参数2:原地址;参数3:拷贝多少内容,字节)
memcpy(a,b,sizeof(b));
//描 述:memcpy在两块内存之间拷贝数据(参数1:目标地址;参数2:原地址;参数3:拷贝多少内容,字节)#include<stdio.h>
#include<string.h>int main0009()
{short a[10] = {1,2,3,4,5,6,7,8,9,10};//short一个整数占2个字节int b[10] = { 0 };//int型一个整数占4个字节memcpy(b, a, sizeof(a));int i;for(i = 0;i<10;i++){printf("%08x\n",b[i]);//%x以十六进制数格式输出整数,08补齐前面的0,为了看起来更容易理解一些}/*输出结果:由于a和b类型不一致,所以拷贝的时候会出现下列情况00020001000400030006000500080007000a00090000000000000000000000000000000000000000*/return 0;
}
memmove:移动内存(参数与memcpy一致)
memmove(a,b,sizeof(b));
注意:使用memcpy的时候一定要确保内存没有重叠区域
memcpy(&a[3],&a[0],20);//出现内存重叠区域
指针小结
int i; 定义整型变量
int *p; 定义指向int型变量的指针变量
int a[10]; 定义int数组
int *a[10]; 定义指针数组,数组中的每个元素指向一个int型变量的地址
int func(); 定义函数,返回值类型为int
int *func();定义函数,返回值类型为int *型
int **p; 定义指向int型指针的指针,二级指针
字符指针与字符串
练习:利用指针对字符串进行倒置
//描 述:利用指针对字符串进行倒置
//思 路:设两个指针,p和p1,p从头开始,p1从后开始,第一个字符与最后一个字符交换,第二个与倒数第二个,直到p>p1;
#include<stdio.h>
#include<string.h>int main0011()
{char a[100] = "hello world";char *p = a;int len = strlen(a);char *p1 = p;//等同于*p1 = a;p1 += len -1;while(p<p1){char tmp = *p;//值交换*p = *p1;*p1 = tmp;p1--;//地址加1减1p++;}printf("%s\n",a);//%s字符串return 0;
}
c语言中,大部分的字符操作就是指针操作。
char s[] = "hello,world"
char *p = s;
p[0] = 'a';
数组作为函数的参数
如果一个数组作为函数的参数,那么数组的成员数量在函数内部是不可见的,一般在传递一个数组的时候,同时提供另一个参数,表明这个数组有几个成员
但是如果传递的是一个字符串,那么并不需要传递一个参数说明字符串的长度(因为字符串总是以0结尾,可以在内部判断0从而判断字符串的长度)
数组作为函数的参数
//描 述:数组作为函数的参数#include<stdio.h>//void test(char a[10])等价
//void test(char a[])
void print_array(int n,int *a)//提供另一个参数n表明数组的成员数量
{int i;for(i = 0;i<n;i++){printf("%d\n",a[i]);}}
int main()
{int a[] = {1,2,3,4,5,6,7,8,9};print_array(sizeof(a)/sizeof(a[0]),a);//n=sizeof(a)/sizeof(a[0])return 0;
}
指针数组作为main函数的形参
int main(int argc, char *argv[]);
main函数是系统调用的,main函数的参数功能是得到命令行的参数
argc:argv数组的成员数量
argv:数组的每个成员都是char类型
argc:命令行参数的数量
argv:命令行参数的字符串数组
指针数组作为main函数的形参
//描 述:指针数组作为main函数的形参#include<stdio.h>//int main(int argv, char *args[])
int main(int argv, char **args)//args是一个指针数组char*,argc代表数组的成员数量
{int i;for(i=0;i<argv;i++){printf("%s\n",args[i]);}return 0 ;
}
练习:通过main函数实现四则加法运算,例如,命令行输入a 5 + 6 输出5+6的结果11
//描 述:利用main实现四则加法运算,例如,命令行输入a 5 + 6 输出5+6的结果11#include<stdio.h>
#include<stdlib.h>//atoi的头文件int main(int argc, char **args)
{if (argc<4)//如果参数不足直接提示并退出{printf("参数不足\n");return 0;}//注意:main函数的参数都是字符串,没有char,中间的+是“+”而不是‘+’int a = atoi(args[1]);//把第一个参数5转化为int型int b = atoi(args[3]);//把第三个参数6转化为int型char *s = args[2];//+是字符串,因此不能写成下面一句//char c = args[2];char c = s[0];//+是“+”的第一个字符,可得到第二个参数+字符//以上两句建议合并为下面一句//char c = args[2][0];switch (c){case '+':printf("%d\n",a+b);case '-':printf("%d\n",a-b);case '*':printf("%d\n",a*b);case '/':printf("%d\n",a/b);default:printf("error\n");}return 0;
}
//注意:*代表的是通配符,运算时结果是error,要想使用*运算符,加转移符号\
//如:a 1 \* 5
总结
最近刚考完嵌入式操作系统,顺路将指针用法整理了一下,如有错误,请大家在评论区或私信我就可以,谢谢!
相关文章:
C/C++:指针用法详解
C/C:指针 指针概念 指针变量也是一个变量 指针存放的内容是一个地址,该地址指向一块内存空间 指针是一种数据类型 指针变量定义 内存最小单位:BYTE字节(比特) 对于内存,每个BYTE都有一个唯一不同的编号…...
JDK8-17新特性
一、JDK8新特性:Lambda表达式 1.Lambda表达式及其使用举例 Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力…...
文件加载的管理:探索三种方法
目录 1. 空闲表法和空闲链表法 空闲表法 优点 缺点 示例 空闲链表法 优点 缺点 示例 优缺点对比 适用场景 综合示例 2. 位图法 概述 优点 缺点 适用场景 示例 位图法的操作 3. 成组链接法 概述 优点 缺点 适用场景 示例 实现细节 结语 在计算机系统中…...
【机器学习】基于Transformer架构的移动设备图像分类模型MobileViT
1.引言 1.1. MobileViT是什么? MobileViT是一种基于Transformer的轻量级视觉模型,专为移动端设备上的图像分类任务而设计。 背景与目的: MobileViT由Google在2021年提出,旨在解决移动设备上的实时图像分类需求。与传统的卷积神…...
grub引导LinuxMint
注意事项:文件系统必须是FAT32 安装 sudo apt install gparted -y 分区管理软件 使用gparted分区和查看设备路径 sudo apt-get install grub-efi-amd64 #/dev/sdd1 是需要制作分区引导的设备路径 sudo mount /dev/sdd1 /mnt/123 #bios sudo grub-install --targe…...
Hadoop 2.0:主流开源云架构(四)
目录 五、Hadoop 2.0访问接口(一)访问接口综述(二)浏览器接口(三)命令行接口 六、Hadoop 2.0编程接口(一)HDFS编程(二)Yarn编程 五、Hadoop 2.0访问接口 &am…...
PythonSQL应用随笔4——PySpark创建SQL临时表
零、前言 Python中直接跑SQL,可以很好的解决数据导过来导过去的问题,本文方法主要针对大运算量时,如何更好地让Python和SQL打好配合。 工具:Zeppelin 语法:PySpark(Apache Spark的Python API)…...
C# OpenCvSharp 矩阵计算-determinant、trace、eigen、calcCovarMatrix、solve
🚀 在C#中使用OpenCvSharp库进行矩阵操作和图像处理 在C#中使用OpenCvSharp库,可以实现各种矩阵操作和图像处理功能。以下是对所列函数的详细解释和示例,包括运算过程和结果。📊✨ 1. determinant - 计算行列式 🧮 定义: double determinant(InputArray mtx); 参数…...
知识普及:什么是边缘计算(Edge Computing)?
边缘计算是一种分布式计算架构,它将数据处理、存储和服务功能移近数据产生的边缘位置,即接近数据源和用户的位置,而不是依赖中心化的数据中心或云计算平台。边缘计算的核心思想是在靠近终端设备的位置进行数据处理,以降低延迟、减…...
大型企业IT基础架构和应用运维体系
大型企业IT基础架构和应用运维体系 在数字化转型的浪潮中,大型企业面临着日益复杂的IT环境。高效的IT基础架构和应用运维体系,是确保企业业务连续性和竞争力的关键。本文将探讨大型企业如何构建强健的IT基础架构,并建立高效的应用运维体系&a…...
【源码】16国语言交易所源码/币币交易+期权交易+秒合约交易+永续合约+交割合约+新币申购+投资理财/手机端uniapp纯源码+PC纯源码+后端PHP
测试环境:Linux系统CentOS7.6、宝塔面板、Nginx、PHP7.3、MySQL5.6,根目录public,伪静态laravel5,开启ssl证书 语言:16种,看图 这套带前端uniapp纯源码,手机端和pc端都有纯源码,后…...
word空白页删除不了怎么办?
上方菜单栏点击“视图”,下方点击“大纲视图”。找到文档分页符的位置。将光标放在要删除的分节符前,按下键盘上的“Delet”键删除分页符。...
Java web应用性能分析之【prometheus+Grafana监控springboot服务和服务器监控】
Java web应用性能分析之【java进程问题分析概叙】-CSDN博客 Java web应用性能分析之【java进程问题分析工具】-CSDN博客 Java web应用性能分析之【jvisualvm远程连接云服务器】-CSDN博客 Java web应用性能分析之【java进程问题分析定位】-CSDN博客 Java web应用性能分析之【…...
JavaEE——声明式事务管理案例:实现用户登录
一、案例要求 本案例要求在控制台输入用户名密码,如果用户账号密码正确则显示用户所属班级,如果登录失败则显示登录失败。实现用户登录项目运行成功后控制台效果如下所示。 欢迎来到学生管理系统 请输入用户名: zhangsan 请输入zhangsan的密…...
解决用Three.js实现嘴型和语音同步时只能播放部分部位的问题 Three.js同时渲染播放多个组件变形动画的方法
前言 参考这篇文章ThreeJSChatGPT 实现前端3D数字人AI互动,前面搭后端、训练模型组内小伙伴都没有什么问题,到前端的时候,脸部就出问题了。看我是怎么解决的。 好文章啊,可惜百度前几个都找不到,o(╥﹏╥)o 问题情况 …...
阅读笔记:明朝那些事儿太监弄乱的王朝
阅读豆评高分作品《明朝那些事儿太监弄乱的王朝》第三部,截止到今天告一段落了,前两部皇帝,太子相对比较少,了解故事的主线,分支不算多,记忆起来还能应付过来,第三部皇帝,太子更换的…...
算法第六天:力扣第977题有序数组的平方
一、977.有序数组的平方的链接与题目描述 977. 有序数组的平方的链接如下所示:https://leetcode.cn/problems/squares-of-a-sorted-array/description/https://leetcode.cn/problems/squares-of-a-sorted-array/description/ 给你一个按 非递减顺序 排序的整数数组…...
设计模式学习(二)工厂模式——工厂方法模式
设计模式学习(二)工厂模式——工厂方法模式 前言工厂方法模式简介示例优点缺点使用场景 前言 前一篇文章介绍了简单工厂模式,提到了简单工厂模式的缺点(违反开闭原则,扩展困难),本文要介绍的工…...
TCP与UDP案例
udp不会做拆分整合什么的 多大就是多大...
Adaboost集成学习 | Matlab实现基于CNN-LSTM-Adaboost集成学习时间序列预测(股票价格预测)
目录 效果一览基本介绍模型设计程序设计参考资料 效果一览 基本介绍 Adaboost集成学习 | Matlab实现基于CNN-LSTM-Adaboost集成学习时间序列预测(股票价格预测) 模型设计 融合Adaboost的CNN-LSTM模型的时间序列预测,下面是一个基本的框架。 …...
你焦虑了吗
前段时间,无意间在图书馆看到一本书《认知觉醒》,书中提到了焦虑的相关话题,从焦虑的根源,焦虑的形式,如何破解焦虑给了我点启示,分享给一下。 引语: 焦虑肯定是你的老朋友了,它总像…...
一键分析Bulk转录组数据
我们前面介绍了经典的转录组分析流程:Hisat2 Stringtie,可以帮助用户快速获得基因的表达量矩阵。 云上生信,未来已来 | 转录组标准分析流程重磅上线! RNA STAR 也是一款非常流行的转录组数据分析工具。它不仅可以将测序 Reads 比…...
Django DetailView视图
Django的DetailView是一个用于显示单个对象详情的视图。下面是一个使用DetailView来显示单个书籍详情的例子。 1,添加视图 Test/app3/views.py from django.shortcuts import render# Create your views here. from django.views.generic import ListView from .m…...
openGauss学习笔记-300 openGauss AI特性-AI4DB数据库自治运维-DBMind的AI子功能-SQL Rewriter SQL语句改写
文章目录 openGauss学习笔记-300 openGauss AI特性-AI4DB数据库自治运维-DBMind的AI子功能-SQL Rewriter SQL语句改写300.1 概述300.2 使用指导300.2.1 前提条件300.2.2 使用方法示例300.3 获取帮助300.4 命令参考300.5 常见问题处理openGauss学习笔记-300 openGauss AI特性-AI…...
typescript-泛型
typescript-泛型 泛型程序设计是一种编程风格或编程范式,允许在程序中定义形式类型参数,然后再泛型实例化时候使用实际类型参数来替代形式类型参数,通过泛型,可以定义通用的数据结构或类型,这种数据结构或类型仅仅再它…...
应急响应 | 基本技能 | 01-系统排查
系统排查 目录 系统基本信息 Windows系统Linux系统 用户信息 Windows系统 1、命令行方式2、图形界面方法3、注册表方法4、wmic方法 Linux系统 查看所有用户信息分析超级权限账户查看可登录的用户查看用户错误的登录信息查看所有用户最后的登录信息查看用户最近登录信息查看当…...
用c语言实现通讯录
目录 静态简易通讯录 代码: 功能模块展示: 设计思路: 动态简易通讯录(本质顺序表) 代码: 扩容模块展示: 设计思路: 文件版本通讯录 代码: 文件模块展示&#x…...
AI大模型技术揭秘-参数,Token,上下文和温度
深入理解 AI 大模型:参数、Token、上下文窗口、上下文长度和温度 人工智能技术的飞速发展使AI大模型大放异彩,其中涉及的“参数”、“Token”、“上下文窗口”、“上下文长度”及“温度”等专业术语备受瞩目。这些术语背后究竟蕴含何意?它们如何影响AI大模型的性能?一起揭开…...
攻防世界-fakebook题目__详解
1.打开题目先用dirsearch工具扫描一波,扫出来了robots.php目录,然后访问robots.txt 目录,发现了有一个备份文件 ,访问备份文件,下载内容 文件的大致内容如下 里面有一个curl_exec这个函数容易造成ssrf攻击的漏洞 我…...
Ubuntu 18.04下普通用户的一次提权过程
Ubuntu 18.04下普通用户的一次提权过程 一.背景介绍:二.主要调试过程:三.相关命令:1.设置BMC密码,获取BMC IP2.找一台ubuntu搭建TFTP服务,用来替换grub.cfg文件3.从调试服务器的/boot/grub/grub.cfg中提取出recovery mode的配置,简化并生成新的配置文件grub.cfg,放在tftp服务的…...
做灯箱到哪个网站找业务/商务网站建设
在从数据库中读取数据时最好直接在select语句中加入选择条件,从而直接限制筛选出符合条件的数据,而不建议读出所有的数据然后用ABAP代码来过滤筛选。 例如,不建议使用: Select * from zflight. Check : zflight-airln ‘LF’ a…...
网站建设安全协议/google站长工具
1.3 MySQL数据操作DML 在MySQL管理软件中,可以通过SQL语句中的DML语言来实现数据的操作,包括使用INSERT实现数据 的插入、DELETE实现数据的删除以及UPDATE实现数据的更新。 更新数据 insert 更新数据 update 删除数据 delete一、插入数据INSERT 1…...
人社局网站建设/网推是什么
ClassLoader翻译过来就是类加载器,普通的Java开发者其实用到的不多,但对于某些框架开发者来说却非常常见。理解ClassLoader的加载机制,也有利于我们编写出更高效的代码。ClassLoader的具体作用就是将class文件加载到jvm虚拟机中去,…...
食品网站建设策划/谷歌三件套一键安装
当我进行Python编程时,我总是使用制表符进行缩进。 但后来我在SO上遇到了一个问题,有人指出大多数Python程序员使用空格而不是制表符来最小化编辑器到编辑器的错误。这有什么不同? 还有其他原因可以使用空格而不是Python的制表符吗࿱…...
美食网站建设策划书/企业网站排名优化方案
2018年谷歌推出了跨平台框架Flutter,一时间让各位技术开发者兴趣暴涨(因为做过混合开发的程序猿早就被js的性能低效,rn的js桥接麻烦,weex的社区小和坑多。。。等技术而感到焦头烂额)。随着高性能的跨平台框架Flutter正式版一发布,…...
wordpress邮件订阅功能/seo必备工具
部署Docker 运行以下命令,安装Docker存储驱动的依赖包。 dnf install -y device-mapper-persistent-data lvm2 运行以下命令,添加稳定的Docker软件源。 dnf config-manager --add-repohttps://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo…...