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

总结

在这里插入图片描述

  最近刚考完嵌入式操作系统,顺路将指针用法整理了一下,如有错误,请大家在评论区或私信我就可以,谢谢!

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

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

相关文章

积木搭建游戏-第13届蓝桥杯省赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第83讲。 积木搭建游戏&…

QT属性系统,简单属性功能快速实现 QT属性的简单理解 属性学习如此简单 一文就能读懂QT属性 QT属性最简单的学习

4.4 属性系统 Qt 元对象系统最主要的功能是实现信号和槽机制&#xff0c;当然也有其他功能&#xff0c;就是支持属性系统。有些高级语言通过编译器的 __property 或者 [property] 等关键字实现属性系统&#xff0c;用于提供对成员变量的访问权限&#xff0c;Qt 则通过自己的元对…

回归预测 | Matlab实现GWO-ESN基于灰狼算法优化回声状态网络的多输入单输出回归预测

回归预测 | Matlab实现GWO-ESN基于灰狼算法优化回声状态网络的多输入单输出回归预测 目录 回归预测 | Matlab实现GWO-ESN基于灰狼算法优化回声状态网络的多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现GWO-ESN基于灰狼算法优化回声状态…

软件下载网站源码附手机版和图文教程

PHP游戏应用市场APP软件下载平台网站源码手机版 可自行打包APP&#xff0c;带下载统计&#xff0c;带多套模板&#xff0c;带图文教程&#xff0c;可以做软件库&#xff0c;也可以做推广app下载等等&#xff0c;需要的朋友可以下载 源码下载 软件下载网站源码附手机版和图文…

Guava-EventBus 源码解析

EventBus 采用发布订阅者模式的实现方式&#xff0c;它实现了泛化的注册方法以及泛化的方法调用,另外还考虑到了多线程的问题,对多线程使用时做了一些优化&#xff0c;观察者模式都比较熟悉&#xff0c;这里会简单介绍一下&#xff0c;重点介绍的是如何泛化的进行方法的注册以及…

FineReport简单介绍

一、介绍 官网 &#xff1a;FineReport产品简介- FineReport帮助文档 - 全面的报表使用教程和学习资料 报表是以表格、图表的形式来动态展示数据&#xff0c;企业通过报表进行数据分析&#xff0c;进而用于辅助经营管理决策。 FineReport 是一款用于报表制作&#xff0c;分析和…

uniapp中unicloud接入支付宝订阅消息完整教程

经过无数次的尝试,终于还是让我做出来了 准备工作 设置接口加签方式 使用支付宝小程序订阅消息,首先要设置接口加签方式,需要下载支付宝开放平台密钥工具,按照步骤生成秘钥,然后按照支付宝设置密钥加签方式添加接口加签方式。 有一点需要注意的,因为要在云函数中使用,…

Mac M3 Pro安装Hadoop-3.3.6

1、下载Hadoop安装包 可以到官方网站下载&#xff0c;也可以使用网盘下载 官网下载地址&#xff1a;Hadoop官网下载地址 网盘地址&#xff1a;https://pan.baidu.com/s/1p4BXq2mvby2B76lmpiEjnA?pwdr62r提取码: r62r 2、解压并添加环境变量 # 将安装包移动到指定目录 mv …

基于flask的网站如何使用https加密通信-问题记录

文章目录 项目场景&#xff1a;问题1问题描述原因分析解决步骤解决方案 问题2问题描述原因分析解决方案 参考文章 项目场景&#xff1a; 项目场景&#xff1a;基于flask的网站使用https加密通信一文中遇到的问题记录 问题1 问题描述 使用下面的命令生成自签名的SSL/TLS证书和…

大模型基础——从零实现一个Transformer(3)

大模型基础——从零实现一个Transformer(1)-CSDN博客 大模型基础——从零实现一个Transformer(2)-CSDN博客 一、前言 之前两篇文章已经讲了Transformer的Embedding,Tokenizer,Attention,Position Encoding, 本文我们继续了解Transformer中剩下的其他组件. 二、归一化 2.1 L…

红队攻防渗透技术实战流程:中间件安全:JettyJenkinsWeblogicWPS

红队攻防渗透实战 1. 中间件安全1.1 中间件-Jetty-CVE&信息泄漏1.2 中间件-Jenkins-CVE&RCE执行1.2.1 cve_2017_1000353 JDK-1.8.0_291 其他版本失效1.2.2 CVE-2018-10008611.2.3 cve_2019_100300 需要用户帐号密码1.3 中间件-Weblogic-CVE&反序列化&RCE1.4 应…

使用python绘制三维曲线图

使用python绘制三维曲线图 三维曲线图定义特点 效果代码 三维曲线图 三维曲线图&#xff08;3D曲线图&#xff09;是一种用于可视化三维数据的图表&#xff0c;它展示了数据在三个维度&#xff08;X、Y、Z&#xff09;上的变化。 定义 三维曲线图通过在三维坐标系中绘制曲线…

数据结构之线性表(4)

前面我们了解到线性表中的顺序表、链表等结构&#xff0c;今天我们探讨新的一种线性表——栈。 那么我们开始栈的探讨之旅吧。 1.栈的基本概念 1.1栈&#xff08;Stack&#xff09;&#xff1a; 是只允许在一端进行插入或删除的线性表。首先栈是一种线性表&#xff0c;但限定…

sudo 用户切换

切换到centos 用户 sudo -i -u centos 解决centos sudo执行仍旧显示Permission denied 方法一&#xff08;建议&#xff09; 暂时切换到root用户 sudo -i然后执行命令即可 方法二 赋给当前用户权限&#xff1a; sudo chmod -R 777 目录路径 sudo chmod 777 文件路径.txt…

IDEA 设置主题、背景图片、背景颜色

一、设置主题 1、点击菜单 File -> Settings : 点击 Settings 菜单 2、点击 Editor -> Color Scheme -> Scheme, 小哈的 IDEA 版本号为 2022.2.3 , 官方默认提供了 4 种主题&#xff1a; Classic Light &#xff08;经典白&#xff09; ;Darcula &#xff08;暗黑主…

2.2 抽头

目录 为什么要抽头 什么是抽头 接入系数 怎么抽头 信号源端抽头 负载端抽头 例题分析 要点总结 为什么要抽头 阻抗转换&#xff0c;使信号源内阻Rs与负载电阻RL变得很大&#xff0c;分流小&#xff0c;再使用并联方式。 什么是抽头 接入系数 电容越大&#xff0c;分压越…

【RabbitMQ】异步消息及Rabbitmq安装

https://blog.csdn.net/weixin_73077810/article/details/133836287 https://www.bilibili.com/video/BV1mN4y1Z7t9/ 同步调用和异步调用 如果我们的业务需要实时得到服务提供方的响应&#xff0c;则应该选择同步通讯&#xff08;同步调用&#xff09;。 如果我们追求更高的效…

MySQL-连接查询

049-内连接之等值连接 案例&#xff1a;查询每个员工所在的部门名称&#xff0c;要求显示员工名、部门名。 select e.ename, d.dname from emp e inner join dept d on e.deptnod.deptno;注意&#xff1a;inner可以省略 select e.ename, d.dname from emp e join dept d on…

Vue49-props属性

一、当同一个组件标签被使用多次 因为data属性写的是函数形式&#xff01; 二、需求&#xff1a;老王也想用<Student>组件&#xff0c;但是需要动态把老王想要的值传进来。 2-1、使用props属性接收参数 使用props属性&#xff0c;接收的这三个参数&#xff0c;是被保存在…

vs+qt5.0 使用poppler 操作库

Poppler 是一个用来生成 PDF 的C类库&#xff0c;从xpdf 继承而来。vs编译库如下&#xff1a; vs中只需要添加依赖库即可 头文件&#xff1a;