当前位置: 首页 > news >正文

【C语言系列】深入理解指针(1)

前言

总所周知,C语言中指针部分是非常重要的,这一件我们会介绍指针相关的内容,当然后续我还会出大概4篇与指针相关的文章,来深入的讲解C语言指针部分,希望能够帮助到指针部分薄弱或者根本不会的程序员们,后续文章尽情期待!

一、内存和地址

1.1内存

电脑上有内存,那么我们就会想内存是怎样高效管理的呢?

其实,就是把内存分为一个一个的内存单元,每个内存单元的大小为1个字节。
其中,每个内存单元,相当于一个学生宿舍,一个字节空间里面能放8个比特位,就像同学们住的八人间,每个人是一个比特位。
每个内存单元也都有一个编号(这个编号就相当于宿舍房间的门牌号),有了这个内存单元的编号,CPU就可以快速找到一个内存空间。

计算机中常见的单位(补充):
计算机在识别、存储、运算的时候都是使用的2进制;⼀个比特位可以存储⼀个2进制的位1或者0。

1byte(字节) = 8bit(比特位)
1KB = 1024byte(字节)(或者用2^10 =1024byte(字节)表示)
1MB= 1024KB(或者用2^10 =1024KB表示)
1GB = 1024MB(或者用2^10 =1024MB表示)
1TB = 1024GB(或者用2^10 =1024GB表示)
1PB = 1024TB(或者用2^10 =1024TB表示)

在计算机中我们把内存单元的编号称为地址,C语言中给地址起了新的名字叫:指针即指针的本质就是地址,也就是内存单元的编号。

1.2究竟该如何理解编址


在这里插入图片描述

今天我们重点关注一下地址总线和数据总线,通过图可以看出,数据是从CPU输入(写)到内存中,然后由内存输出(读)到CPU上,CPU是通过地址总线来发送目标地址,访问内存位置;而内存是通过数据总线把数据传输给CPU的。
在这里插入图片描述
这张图我们可以简单理解,32位机器有32根地址总线,每根线只有两态,表示0/1(即电脉冲的有无),那么一根线,就能表示2种含义,2根线就能表示4种含义,依次类推。32根地址线,就能表示2^32种含义,每一种含义都代表一个地址。地址信息被下达给内存,在内存上,就可以找到该地址对应的数据,将数据在通过数据总线传入CPU内寄存器。
在这里插入图片描述
总结:1、内存会被划分为一个一个的内存单元,每个内存单元的大小是1个字节。
2、每个内存单元都会给一个编号 == 地址 ==C语言中也叫指针。

二、指针变量和地址

2.1取地址操作符(&)

下面我们观察一段代码,并进行调试:

int main()
{
int a = 25;//变量创建的本质是什么呢?是在内存中开辟一块空间
//int占4个字节,&a ——>只取第1个字节的地址(即4个地址中最小的那个地址)
&a;//& —— 取地址操作符
printf("%p\n", &a);//%p —— 是专门用来打印地址的 —— 其实是以16进制的形式打印的
return 0;
}

运行结果如下图:
在这里插入图片描述
调试后发现a的地址为:0x00000090BB6FFAE4,并且以16进制形式打印出来(25转换为16进制的话就是19),当然编译器每次分配的地址可能是不一样的,可能打印的结果和地址会有差别,这是正常现象。

2.2指针变量和解引用操作符(*)

2.2.1指针变量

那我们通过取地址操作符(&)拿到的地址是一个数值,比如:0x00000090BB6FFAE4,这个数值有时候也是需要存储起来,方便后期再使用的,那我们把这个地址值存放在哪里呢?存放在指针变量。
如下图所示:

#include <stdio.h>
int main()
{
int a = 10;
int * p = &a;//取出a的地址,并存储到指针变量p中。
//地址 —— 指针
//p是指针变量 —— 存放指针的变量
//即指针变量是用来存放地址的变量
return 0;
}

注:指针变量也是一种变量,这种变量就是用来存放地址(指针)的,存放在指针变量中的值都会被理解为地址。

2.2.2如何拆解指针类型

int a = 20;
int *pa = &a;

结合上述代码我们可以看到,pa的类型是int*,那如何理解pa的类型呢?
这里pa左边写的是int* ,*是在说明pa是指针变量,而前面的int 是在说明pa指向的是整型(int)。
在这里插入图片描述

2.2.3解引用操作符

我们将地址保存起来,未来是要使用的,那怎么使用呢?
C语⾔中其实也是一样的,我们只要拿到了地址(指针),就可以通过地址(指针)找到地址(指针)指向的对象,这里使用的操作符叫解引用操作符(*)。

#include <stdio.h>
int main()
{
int a = 20;
int*p = &a;
*p = 100;
//解引用操作(间接访问操作符)*p等于a
//* —— 解引用操作符
printf("%d\n",a);
return 0;
}

*上面代码中第6行就使用了解引用操作符,p 的意思就是通过pa中存放的地址,找到指向的空间,p其实就是a变量了;所以p = 100,这个操作符是把a改成了100。
这里很容易理解错误,很多初学者认为这里把 a = 100;不就可以了吗?为什么要用指针呢?那是不是就没必要学指针呢?
答案当让是否认的,其实这里是把a的修改交给了pa来操作,这样对a的修改,就多了一种的途径,写代码就会更加灵活,相信后期初学者就会慢慢理解了。
总结:1、指针其实就是地址;
2、指针变量是存放指针(地址)的。
一般口语中说的指针一般都是指:指针变量比如:int *p; 。

2.3指针变量的大小

前面我们了解过,32位机器假设有32根地址总线,每根地址线出来的电信号转换成数字信号后是1或者0,那我们把32根地址线产生的2进制序列当做一个地址,那么一个地址就是32个bit位,需要4个字节才能存储,那么64位机器也一样,就需要8个字节来存储。
如果指针变量是用来存放地址的,那么指针变的大小就得是4个字节的空间才可以。
像上述指针变量p,是需要向内存申请一块空间的,这样才有能力存放地址。

那么指针变量的大小是多少呢?
指针变量是需要多大空间,是取决于存放的是什么?存放的是地址,地址的存放需要多大空间,指针变量的大小就是多大。
32位机器上(X86):地址是32个0/1的二进制序列,存储起来需要32个bit位,也就是4个字节,指针变量的大小就是4个字节。
64位机器上(X64):地址是64个0/1的二进制序列,存储起来需要64个bit位,也就是8个字节,指针变量的大小就是8个字节。
注:指针变量的大小与类型无关!只要指针类型的变量,在相同的平台下,大小都是相同的。

三、指针变量类型的意义

3.1指针的解引用

接下来我们看下面两个代码:

int main()
{
int a = 0x11223344;
int* pa = &a;
*pa = 0;//00000000
return 0;
}
int main()
{
int a = 0x11223344;
char* pa = &a;
*pa = 0;//00332211
return 0;
}

观察上述代码得出结论:指针类型决定了指针进行解引用操作的时候访问多大空间。
int * 的指针解引用访问4个字节。
char *的指针解引用访问1个字节。
指针的类型决定了,对指针解引用的时候有多大的权限(依次能操作几个字节)。

3.2指针±整数

下面我们看这样一个代码:

#include <stdio.h>
int main()
{
int a = 10;
int*pa = &a;
char*pc = &a;
printf("pa = %p\n",pa);//00000043DC1FFC94
printf("pa + 1 = %p\n",pa + 1);//00000043DC1FFC98
printf("pc = %p\n",pc);//00000043DC1FFC94
printf("pc + 1 = %p\n",pc + 1);//00000043DC1FFC95
return 0;
}

运行结果如下图:
在这里插入图片描述
结论:指针类型决定了指针的步长,就是向前/向后走一步走多大距离。

type* p;

p + i是跳过i个type类型的数据,相当于跳过了i*size(type)个字节。

int*p;

p + 2相当于跳过2个int类型的数据,相当于跳过了2*size(int) = 8个字节。
根据实际的需要,选择适当的指针类型才能达到效果。

3.3void*指针

void指针可以理解为无具体类型的指针(或者叫泛型指针),可以用来接受任意类型的地址。但也有局限性,void类型的指针不能直接进行指针的±整数和解引用的运算。
我们观察下面的代码:

#include <stdio.h>
int main()
{
int a = 10;
void* pa = &a;
void* pc = &a;
*pa = 10;
*pc = 0;
return 0;
}

运行时会报错如下图所示:
在这里插入图片描述
这里我们观察后不难看出,void* 类型的指针可以接收不同类型的地址,但是无法直接进行指针运算。
void*类型的指针到底有什么作用呢?

一般void*类型的指针是使用在函数参数的部分,用来接收不同类型数据的地址,这样的设计可以实现泛型编程的效果,使得一个函数来处理多种类型的数据。

四、const修饰指针

4.1const修饰变量

变量是可以被修改的,如果把变量的地址交给一个指针变量,通过指针变量也可以修改这个变量,但是如果我们希望⼀个变量不能被修改,那么我们就可以使用const修饰这个指针变量,这就是const的作用。
如下面代码所示:

#include <stdio.h>
int main()
{//const是常属性 —— 不能被修改了
const int n =10;//n是变量
n = 0;//这里会报错
//const修饰了n之后,n不能被修改了,但是n还是变量。
printf("%d\n",n);//C++中const修饰的n就是常量。
return 0;
}

上述代码中n是不能被修改的,其实n本质还是变量,只不过被const修饰后,在语法上加了限制,只要我们在代码中对n进行修改,就不符合语法规则,就会报错,致使无法直接修改n。

#include <stdio.h>
int main()
{
const int n = 10;
//n = 0;//err
int*p = &n;
*p = 20;
printf("n = %d\n",n);
return 0;
}

运行结果如下图:在这里插入图片描述
这里直接给n的地址是可以修改n中的内容的,但是这打破了语法规则。

4.2const修饰指针变量

预备知识如下图:
在这里插入图片描述

⼀般来说const修饰指针变量,可以放在* 的左边,也可以放在* 的右边,意义是不⼀样的。

//两种情况
int * p;//没有const修饰
int const * p;//const 放在*的左边做修饰
int * const p;//const 放在*的右边做修饰
#include <stdio.h>
//const放在*的左边情况
void test1()
{
const int n = 10;
int m = 100;
const int* p = &n;
//*p = 20;//err
p = &m; //ok
}
//const放在*的右边情况
void test2()
{
const int n = 10;
int m = 100;
int * const p = &n;
//*p = 20; //0k
p = &m; //err 
printf("%d\n",n);
}
int main()
{
//测试const放在*的左边情况 
test1();
//测试const放在*的右边情况
test2();
return 0;
}

const修饰指针变量有2种情况:
1、const放在*的左边:限制的是 *p,意思是不能通过p来改变p指向的对象的内容,但p本身是可以改变的,p可以指向其他对象。
2、const放在 *的右边:限制的是p,意思是不能修改p本身的值,但是p指向的内容是可以通过p来改变的。

五、指针运算

指针的基本运算有三种,分别是:
指针±整数
指针-指针
指针的关系运算

5.1指针±整数

数组在内存中是连续存放的,随着数组下标的增长,地址是由低到高变化的。

#include <stdio.h>
int main()
{
int arr[0] = {1,2,3,4,5,6,7,8,9,10};
//打印数组内容
//下标:0 1 2 3 4 5 6 7 8 9
int i = 0;
int sz = sizeof(arr)/sizeof(arr[0]);
int*p = &arr[0];
for(i = 0;i < sz;i++)
{
printf("%d",*p);
p++;//p = p + 1;
//这里可以合起来写为:printf("%d",*(p+i));这里的p+i就是指针+整数
}
return 0;
}

5.2指针-指针

指针-指针,运算的前提是两个指针指向了同一块空间,指针-指针得到是指针和指针之间元素的个数。
指针-指针就好比日期-日期 ==天数,但是日期+日期就什么也不是了,所以也没有指针+指针。

#include <stdio.h>
int main()
{//指针-指针,运算的前提是两个指针指向了同一块空间
int arr[10] = {0};
printf("%d\n",&arr[9] - &arr[0]);//指针-指针 9
//&arr[0] - &arr[9];//9
return 0;
//指针-指针的绝对值是指针和指针之间的元素个数
}

strlen是库函数,是专门用来求字符串长度的,接下来我们用指针-指针来实现这个库函数,代码如下:

#include <stdio.h>
int my_strlen(char*p)
{
char*p1 = p;
while(*p != '\0')
{
p++;
}
return p - p1;
}
int main()
{
char arr[] = "abcdef";
//数组名其实就是数组首元素的地址
//arr == &arr[0];
int len = my_strlen(arr);
printf("%d\n",len);
return 0;
}

5.3指针的关系运算

#include <stdio.h>
int main()
{
int arr[] = {1,2,3,4,5,6,7,8,9,10};
int sz =sizeof(arr)/sizeof(arr[0]);
int*p = &arr[0];
while(p < arr + sz)//指针的关系运算(即指针的大小比较)
{
printf("%d",*p);
p++;
}
return 0;
}

六、野指针(很危险)

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

6.1野指针的成因

1.指针变量未初始化

#include <stdio.h>
int main()
{
int*p;//局部变量
//局部变量未初始化的时候,它的值是随机值0xcccccccc
*p = 20;
printf("%d\n",*p);
return 0;
}

2.指针越界访问

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

3.指针指向的空间释放

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

6.2如何规避野指针

6.2.1指针初始化

如果明确知道指针的指向哪里就直接赋值地址,如果不知道指针应该指向哪里,可以给指针赋值NULL。NULL 是C语言中定义的一个标识符常量其值为0,0也是地址,这个地址是无法使用的,读写该地址会报错。

#include <stdio.h>
int main()
{
int a = 10;
int*pa = &a;
int*p = NULL;//NULL的值是0,0也是地址,这个地址是无法使用的,读写该地址会报错。
return 0;
}
int*p = NULL;
*p = 20;//这里会报错的

6.2.2小心指针越界

一个程序向内存申请了哪些空间,通过指针也就只能访问哪些空间,不能超出范围访问,超出了就是
越界访问。

6.2.3指针变量不再使用时,及时置NULL,指针使用之前检查有效性

当指针变量指向一块区域的时候,我们可以通过指针访问该区域,后期不再使用这个指针访问空间的
时候,我们可以把该指针置为NULL。因为约定俗成的一个规则就是:只要是NULL指针就不去访问,
同时使用指针之前可以判断指针是否为NULL。

6.2.4避免返回局部变量的地址

如造成野指针的第3个例子,不要返回局部变量的地址。

七、assert断言

assert.h 头文件定义了宏assert() ,用于在运行时确保程序符合指定条件,如果不符合,就报错终止运行。这个宏常常被称为“断言”。(使用assert时,要包含头文件<assert.h>)。

assert(p != NULL);//验证变量p是否等于NULL。

上面代码在程序运行到这一行语句时,验证变量p是否等于NULL 。如果确实不等于继续运行,否则就会终止运行,并且给出报错信息提示。

assert()宏接受⼀个表达式作为参数。如果该表达式为真(返回值非零),assert()不会产生任何作用,程序继续运行。如果该表达式为假(返回值为零),assert()就会报错,在标准错误流stderr中写入⼀条错误信息,显示没有通过的表达式,以及包含这个表达式的文件名和行号。

#include <stdio.h>
#include <assert.h>
int main()
{
int a = 0;
int*p = NULL;
assert(p != NULL);//err
*p = 20;
printf("%d\n",a);
return 0;
}

assert()有几个好处:它不仅能自动标识文件和出现问题的行数,还有一种无需更改代码就能开启或关闭assert()的机制。如果已经确认程序没有问题,不需要做断言,就可:

#define NDEBUG
#include <assert.h>

一般在Debug中使用,在Release版本中会被优化掉。
assert() 的缺点是,因为引入了额外的检查,增加了程序的运行时间。

八、指针的使用和传值使用

8.1strlen的模拟实现

库函数strlen的功能是求字符串长度,统计\0之前的字符的个数。
函数原型如下:

size_t strlen ( const char * str );

参数str接收一个字符串的起始地址,然后开始统计字符串中\0 之前的字符个数,最终返回长度。如果要模拟实现只要从起始地址开始向后逐个字符的遍历,只要不是\0计数器就+1,直到遇到\0为止。

#include <stdio.h>
#include <assert.h>
size_t my_strlen(const char*s)
{
size_t count = 0;
assert(s != NULL);
while(*s != '\0')
{
count++;
s++;
}
return count;
}
int main()
{
//strlen() —— 求字符串的长度 —— 统计的是字符串中\0之前的字符的个数。
char arr[] = "abcdef";
size_t len = my_strlen(arr);
printf("%zd\n",len);
return 0;
}

8.2传值调用和传址调用

题目:写一个函数,交换两个整型变量的值。

#include <stdio.h>
void Swap(int x,int y)//传值调用
{
int z = 0;
z = x;
x = y;
y = z;
}
int main()
{
int a = 10;
int b = 20;
printf("交换前:a = %d b = %d\n",a,b);//a = 10, b = 20
Swap(a,b);
printf("交换后:a = %d b = %d\n",a,b);//a = 10, b = 20
return 0;
}

运行结果如下图:
在这里插入图片描述

结论:当实参传递给形参的时候,形参是有自己独立的空间的,形参是实参的一份临时拷贝,对于形参的修改,不会影响实参。

#include <stdio.h>
void Swap2(int*pa,int*pb)//传址调用
{
int z = 0;
z = *pa;
*pa = *pb;
*pb = z;
}
int main()
{
int a = 10;
int b = 20;
printf("交换前:a = %d b = %d\n",a,b);//a = 10, b = 20
Swap2(&a,&b);
printf("交换后:a = %d b = %d\n",a,b);//a = 20, b = 10
return 0;
}

运行结果如下图:
在这里插入图片描述

总结:只是需要主调函数中的变量值来实现计算,就可以采用传值调用。如果函数内部要修改主调函数中的变量的值,就需要传址调用。

相关文章:

【C语言系列】深入理解指针(1)

前言 总所周知&#xff0c;C语言中指针部分是非常重要的&#xff0c;这一件我们会介绍指针相关的内容&#xff0c;当然后续我还会出大概4篇与指针相关的文章&#xff0c;来深入的讲解C语言指针部分&#xff0c;希望能够帮助到指针部分薄弱或者根本不会的程序员们&#xff0c;后…...

医院挂号就诊系统设计与实现(代码+数据库+LW)

摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装医院挂号就诊系统软件来发挥其高效地信息处理的作用&#…...

Mysql 主从复制原理及其工作过程,配置一主两从实验

主从原理&#xff1a;MySQL 主从同步是一种数据库复制技术&#xff0c;它通过将主服务器上的数据更改复制到一个或多个从服务器&#xff0c;实现数据的自动同步。 主从同步的核心原理是将主服务器上的二进制日志复制到从服务器&#xff0c;并在从服务器上执行这些日志中的操作…...

verilog笔记1

1. 阻塞赋值 阻塞赋值&#xff0c;顾名思义即在一个 always 块中&#xff0c;后面的语句会受到前语句的影响&#xff0c;具体来说就是在同一个always 中&#xff0c;一条阻塞赋值语句如果没有执行结束&#xff0c;那么该语句后面的语句就不能被执行&#xff0c;即被“阻塞”。也…...

人工智能之数学基础:线性代数中的线性相关和线性无关

本文重点 在线性代数的广阔领域中,线性相关与线性无关是两个核心概念,它们对于理解向量空间、矩阵运算、线性方程组以及人工智能等问题具有至关重要的作用。 定义与直观理解 当存在一组不全为0的数x1,x2,...,xn使得上式成立的时候,那么此时我们可以说向量组a1,a2...,an…...

Flask简介与安装以及实现一个糕点店的简单流程

目录 1. Flask简介 1.1 Flask的核心特点 1.2 Flask的基本结构 1.3 Flask的常见用法 1.3.1 创建Flask应用 1.3.2 路由和视图函数 1.3.3 动态URL参数 1.3.4 使用模板 1.4 Flask的优点 1.5 总结 2. Flask 环境创建 2.1 创建虚拟环境 2.2 激活虚拟环境 1.3 安装Flask…...

Ubuntu22.04安装paddle GPU版本

文章目录 确立版本安装CUDA与CUDNN安装paddle 确立版本 查看官网信息&#xff0c;确立服务版本&#xff1a;https://www.paddlepaddle.org.cn/documentation/docs/zh/2.6/install/pip/linux-pip.html 安装CUDA与CUDNN 通过nvidia-smi查看当前显卡驱动版本&#xff1a; 通过…...

读《SQL经典实例》学数据库(系列一)

目录 友情提醒第一章、数据库简述1.1&#xff09;数据库简述1.2&#xff09;常见的数据库软件1.3&#xff09;MySQL数据库安装 第二章、SQL语句分类2.1)操作数据仓库/数据表&#xff1a;DDL2.1.1&#xff09;创建数据仓库/数据表2.1.2&#xff09;删除数据仓库/数据表2.1.3&…...

Android系统开发(一):AOSP 架构全解析:开源拥抱安卓未来

引言 当我们手握智能手机&#xff0c;流畅地滑动屏幕、切换应用、欣赏动画时&#xff0c;背后其实藏着一套庞大且精密的开源系统——Android AOSP&#xff08;Android Open Source Project&#xff09;。这套系统不仅是所有安卓设备的根基&#xff0c;也是系统开发者的终极 pl…...

git系列之revert回滚

1. Git 使用cherry-pick“摘樱桃” step 1&#xff1a; 本地切到远程分支&#xff0c;对齐要对齐的base分支&#xff0c;举例子 localmap git pull git reset --hard localmap 对应的commit idstep 2&#xff1a; 执行cherry-pick命令 git cherry-pick abc123这样就会将远程…...

【统计的思想】假设检验(一)

假设检验是统计学里的重要方法&#xff0c;同时也是一种“在理想与现实之间观察求索”的测试活动。假设检验从概率的角度去考察理想与现实之间的关系&#xff0c;籍此来缓解测试可信性问题。 我们先来看一个例子。民航旅客服务系统&#xff0c;简称PSS系统&#xff0c;有一种业…...

Linux 管道操作

Linux 管道操作 在 Linux 中&#xff0c;管道&#xff08;Pipe&#xff09;是一个非常强大且常用的功能&#xff0c;它允许将一个命令的输出直接传递给另一个命令作为输入&#xff0c;从而能够高效地处理和分析数据。管道在多个命令之间建立数据流&#xff0c;减少了文件的读写…...

Rust 数据类型详解

一、标量类型&#xff08;Scalar Types&#xff09; 标量类型代表一个单独的值。Rust 中有四大基本标量类型&#xff1a;整数&#xff08;integer&#xff09;、浮点数&#xff08;floating-point number&#xff09;、布尔&#xff08;boolean&#xff09;和字符&#xff08;…...

(十四)WebGL纹理坐标初识

纹理坐标是 WebGL 中将 2D 图像&#xff08;纹理&#xff09;应用到 3D 物体表面的重要概念。在 WebGL 中&#xff0c;纹理坐标通常使用一个二维坐标系&#xff0c;称为 uv 坐标&#xff0c;它们决定了纹理图像如何映射到几何体上。理解纹理坐标的核心就是明白它们如何将二维纹…...

青少年CTF练习平台 EasyMD5解题思路

题目 EasyMD5 PHP弱类型/弱等于的判断 翻译 上传之后网页提示&#xff1a;Not a PDF! angry!!! get out from my page 修改文件后缀为pdf 再次上传&#xff0c;答案出来了 s878926199a s155964671a 成功获取flag...

二叉搜索树(TreeMapTreeSet)

文章目录 1.概念2.二叉搜索树的底层代码实现(1)首先构建二叉树(2)实现插入功能&#xff1b;(3)实现查找(4)删除&#xff08;重点&#xff09; 3.TreeMap 1.概念 TreeMap&TreeSet都是有序的集合都是基于二叉搜索树来实现的 二叉搜索树&#xff1a;是一种特殊的二叉树 若左子…...

鸿蒙动态路由实现方案

背景 随着CSDN 鸿蒙APP 业务功能的增加&#xff0c;以及为了与iOS、Android 端统一页面跳转路由&#xff0c;以及动态下发路由链接&#xff0c;路由重定向等功能。鸿蒙动态路由方案的实现迫在眉睫。 实现方案 鸿蒙版本动态路由的实现原理&#xff0c;类似于 iOS与Android的实…...

matlab实现一个雷达信号处理的程序,涉及到对原始图像的模拟、加权、加噪以及通过迭代算法对图像进行恢复和优化处理

clc clear close all load scene3.mat %加载原始图像,自己设计 设计为一个300*400的矩阵 300是距离向长度,400是方位向长度 Map_ori = scene3; [M,N_K] = size(Map_ori);figure imagesc(scene3) v = 100; %机载速度,单位m/s bandwidth = 30*1e6; …...

设置 Git 默认推送不需要输入账号和密码【Ubuntu、SSH】

如何设置 Git 默认推送不需要输入账号和密码 在使用 Git 管理代码时&#xff0c;许多开发者会遇到每次推送&#xff08;push&#xff09;或拉取&#xff08;fetch&#xff09;代码时都需要输入 GitHub 或 GitLab 等远程仓库的账号和密码的情况。虽然设置了用户名和电子邮件信息…...

【深度学习】Pytorch:导入导出模型参数

PyTorch 是深度学习领域中广泛使用的框架&#xff0c;熟练掌握其模型参数的管理对于模型训练、推理以及部署非常重要。本文将全面讲解 PyTorch 中关于模型参数的操作&#xff0c;包括如何导出、导入以及如何下载模型参数。 什么是模型参数 模型参数是指深度学习模型中需要通过…...

ABP - 缓存模块(1)

ABP - 缓存模块&#xff08;1&#xff09; 1. 与 .NET Core 缓存的关系和差异2. Abp 缓存的使用2.1 常规使用2.2 非字符串类型的 Key2.3 批量操作 3. 额外功能 1. 与 .NET Core 缓存的关系和差异 ABP 框架中的缓存系统核心包是 Volo.Abp.Caching &#xff0c;而对于分布式缓存…...

【unity进阶篇】unity如何实现跨平台及unity最优最小包体打包方式(.NET、Mono和IL2CPP知识介绍)

考虑到每个人基础可能不一样&#xff0c;且并不是所有人都有同时做2D、3D开发的需求&#xff0c;所以我把 【零基础入门unity游戏开发】 分为成了C#篇、unity通用篇、unity3D篇、unity2D篇。 【C#篇】&#xff1a;主要讲解C#的基础语法&#xff0c;包括变量、数据类型、运算符、…...

5-1 创建和打包AXI Interface IP

创建和打包AXI Interface IP的前流程和后流程 step 1 &#xff1a; 选择类型 1&#xff1a; 将当前的工程打包成IP 2&#xff1a; 将当前的BD工程打包成IP 3&#xff1a; 将指定的源码打包成IP 4&#xff1a; 创建一个新的AXI 接口IP 其中3和4是比较常用的&#xff0c;本次…...

【C++】如何从源代码编译红色警戒2地图编辑器

【C】如何从源代码编译红色警戒2地图编辑器 操作视频视频中的代码不需要下载三方库&#xff0c;已经包含三方库。 一、运行效果&#xff1a;二、源代码来源及编程语言&#xff1a;三、环境搭建&#xff1a;安装红警2安装VS2022下载代码&#xff0c;源代码其实不太多&#xff0c…...

HRNet,Deep High-Resolution Representation Learning for Visual Recognition解读

论文、代码和ppt地址&#xff1a;HRNet。代码地址: hrnet 本文通过paper解读和代码实例以及onnx模型的分析&#xff0c;来说明hrnet模型。 摘要——高分辨率表征对于诸如人体姿态估计、语义分割和目标检测等对位置敏感的视觉问题至关重要。现有的最先进框架首先通过一个子网&…...

Rust Actix Web 项目实战教程 mysql redis swagger:构建用户管理系统

Rust Actix Web 项目实战教程&#xff1a;构建用户管理系统 项目概述 本教程将指导你使用 Rust 和 Actix Web 构建一个完整的用户管理系统&#xff0c;包括数据库交互、Redis 缓存和 Swagger UI 文档。 技术栈 Rust 编程语言Actix Web 框架SQLx (MySQL 数据库)Redis 缓存Uto…...

# 爬楼梯问题:常见数列的解法总结

爬楼梯问题&#xff1a;常见数列的解法总结 在编程中&#xff0c;爬楼梯问题&#xff08;Climbing Stairs Problem&#xff09;是一个经典的动态规划问题&#xff0c;常常作为入门学习动态规划和递推的重要例题。这个问题看似简单&#xff0c;但背后包含了多种解决方式&#x…...

速通Docker === 常用命令

目录 Docker命令 镜像操作 容器操作 基础操作 启动参数 容器内部操作 打包成指定文件 发布镜像 总结 镜像操作 容器操作 启动容器参数 容器内部操作 打包镜像 启动指定镜像的容器 发布镜像 Docker命令 启动一个nginx,并将它的首页改为自己的页面&#xff0c;发布…...

AWS S3 跨账户访问 Cross Account Access

进入S3对应的存储桶&#xff0c;上面选项选权限&#xff0c;存储桶策略 -- 编辑&#xff0c;输入对应的policy。 完全控制&#xff0c;包含上传删除权限&#xff0c;policy如下&#xff1a; {"Version": "2012-10-17","Statement": [{"Si…...

C#中常见的锁以及用法--18

目录 一.C#中存在的锁 二.锁的作用 三.锁的概念和定义 关于锁的完整代码示例 代码逐层剖析: 全局变量与同步变量 Lock(锁)关键字示例 Monitor(监视器锁)示例 Mutex(互斥量)示例(支持跨进程同步) SemaphoreSlim(信号量)示例 ReadWriterLockSlim(读写锁)示例 SpinLock…...

【数据分享】1929-2024年全球站点的逐年平均气温数据(Shp\Excel\无需转发)

气象数据是在各项研究中都经常使用的数据&#xff0c;气象指标包括气温、风速、降水、湿度等指标&#xff0c;其中又以气温指标最为常用&#xff01;说到气温数据&#xff0c;最详细的气温数据是具体到气象监测站点的气温数据&#xff01;本次我们为大家带来的就是具体到气象监…...

Docker部署MySQL 5.7:持久化数据的实战技巧

在生产环境中使用Docker启动MySQL 5.7时&#xff0c;需要考虑数据持久化、配置文件管理、安全性等多个方面。以下是一个详细的步骤指南。 1. 准备工作 &#xff08;1&#xff09;创建挂载目录 在宿主机上创建用于挂载的目录&#xff0c;以便持久化数据和配置文件。 sudo mkdi…...

二叉树和堆

树概念及结构&#xff08;了解&#xff09; 树的概念&#xff08;看看就行&#xff09; 树是一种 非线性 的数据结构&#xff0c;它是由 n &#xff08; n>0 &#xff09;个有限结点组成一个具有层次关系的集合。 把它叫做树是因 为它看起来像一棵倒挂的树&#xff0c;也就是…...

Zookeeper(15)Zookeeper的ZooKeeper API包含哪些主要操作?

Zookeeper 的 ZooKeeper API 提供了一系列操作来管理 Zookeeper 的数据节点&#xff08;znodes&#xff09;。这些操作主要包括创建节点、删除节点、读取节点数据、设置节点数据、列出子节点、检查节点是否存在&#xff0c;以及注册 Watcher 等。以下是这些操作的详细介绍和代码…...

深入浅出:Go语言os包中的API使用指南

深入浅出:Go语言os包中的API使用指南 引言 Go语言以其简洁、高效和强大的生态系统著称,是现代编程中不可或缺的一部分。其中,os包作为Go标准库的一部分,提供了丰富的API来与操作系统进行交互。本文将深入探讨os包中的核心功能,并通过实际案例帮助读者更好地理解和应用这些…...

【云岚到家】-day02-客户管理-认证授权

第二章 客户管理 1.认证模块 1.1 需求分析 1.基础概念 一般情况有用户交互的项目都有认证授权功能&#xff0c;首先我们要搞清楚两个概念&#xff1a;认证和授权 认证: 就是校验用户的身份是否合法&#xff0c;常见的认证方式有账号密码登录、手机验证码登录等 授权:则是该用…...

vben5 admin ant design vue如何使用时间范围组件RangePicker

本文参考&#xff1a;https://pusdn-dev.feishu.cn/wiki/VF4hwBAUliTE6TkUPKrcBNcZn9f?fromfrom_copylink 由PUSDN整理发行&#xff0c;收录时请保留PUSDN。 前端组件专题 年月日时间范围表单回显RangePicker 推荐使用多个字段存储&#xff0c;不推荐用英文逗号拼接时间&am…...

安全策略配置实验

安全策略配置实验 1.拓扑 2.需求 2、办公区PC在工作日时间(周一至周五&#xff0c;早8到晚6)可以正常访问OA srver&#xff0c;其他时间不允许 3、办公区PC可以在任意时刻访问web server 4、生产区PC可以在任意时刻访问OA Server&#xff0c;但是不能访问Web server 5、特…...

Win10安装WebODM和操作全流程

效果 以下是在 Windows 10 上安装和部署 WebODM 的详细教程: 一、安装 Docker Desktop for Windows 1、访问 Docker 官方网站:https://www.docker.com/products/docker-desktop 。 2、下载 Docker Desktop for Windows 的安装程序。 3、运行安装程序: 双击下载的安装程序,…...

wireshark抓路由器上的包 抓包路由器数据

文字目录 抓包流程概述设置抓包配置选项 设置信道设置无线数据包加密信息设置MAC地址过滤器 抓取联网过程 抓包流程概述 使用Omnipeek软件分析网络数据包的流程大概可以分为以下几个步骤&#xff1a; 扫描路由器信息&#xff0c;确定抓包信道&#xff1b;设置连接路由器的…...

第8章:Python TDD处理货币类代码重复问题

写在前面 这本书是我们老板推荐过的&#xff0c;我在《价值心法》的推荐书单里也看到了它。用了一段时间 Cursor 软件后&#xff0c;我突然思考&#xff0c;对于测试开发工程师来说&#xff0c;什么才更有价值呢&#xff1f;如何让 AI 工具更好地辅助自己写代码&#xff0c;或许…...

C#,入门教程(01)—— Visual Studio 2022 免费安装的详细图文与动画教程

通过本课程的学习&#xff0c;你可以掌握C#编程的重点&#xff0c;享受编程的乐趣。 在本课程之前&#xff0c;你无需具备任何C#的基础知识&#xff0c;只要能操作电脑即可。 不过&#xff0c;希望你的数学不是体育老师教的。好的程序是数理化的实现与模拟。没有较好的数学基础…...

Agent Laboratory: Using LLM Agents as Research Assistants 论文简介

加速机器学习研究的智能实验室——Agent Laboratory 1. 引言 随着人工智能技术的飞速发展&#xff0c;机器学习领域正以前所未有的速度推进科学发现和技术创新。然而&#xff0c;传统的科学研究模式往往受到时间、资源和专业知识限制&#xff0c;阻碍了研究者们探索新想法的能…...

cuda + cudnn安装

1.安装CUDA Toolkit 在设备管理器&#xff08;此电脑–右键–属性&#xff09;的显示适配器中可以查看自己的显卡型号&#xff0c;去下载对应的CUDA Toolkit 。或者输入以下命令查看Driver Version &#xff0c;cuda Version&#xff1a;12.2代表12.2版本以下兼容可以进行安装 …...

Next.js 实战 (八):使用 Lodash 打包构建产生的“坑”?

前言 最近一直在折腾 Nextjs15 &#xff0c;也在断断续续地写《Next.js15 实战系列》的文章&#xff0c;后来总感觉文章如果没有线上效果预览差点意思&#xff0c;所以就想着先把目前做的项目先部署上线&#xff0c;后续再慢慢添加新功能。 因为之前没有部署过 Nextjs15 工程…...

owasp SQL 注入-03 (原理)

1: 先看一下注入界面: 点submit 后&#xff0c;可以看到有语法报错&#xff0c;说明已经起作用了: 报如下的错误: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near at line 1 2:…...

wireshark工具简介

目录 1 wireshark介绍 2 wireshark抓包流程 2.1 选择网卡 2.2 停止抓包 2.3 保存数据 3 wireshark过滤器设置 3.1 显示过滤器的设置 3.2 抓包过滤器 4 wireshark的封包列表与封包详情 4.1 封包列表 4.2 封包详情 参考文献 1 wireshark介绍 wireshark是非常流行的网络…...

队列的基本用法

以下是关于 C 语言中队列的详细知识&#xff0c;包括队列的生成、相关函数使用以及其他重要概念&#xff1a; 一、队列的概念 队列是一种线性数据结构&#xff0c;它遵循先进先出&#xff08;First In First Out&#xff0c;FIFO&#xff09;的原则&#xff0c;就像日常生活中…...

OpenHarmony-7.IDL工具

IDL 工具 1.openharmony IDL工具 在OpenHarmony中&#xff0c;当应用/系统服务的客户端和服务端进行IPC&#xff08;Inter-Process Communication&#xff09;跨线程通信时&#xff0c;需要定义双方都认可的接口&#xff0c;以保障双方可以成功通信&#xff0c;OpenHarmony ID…...

封装Redis工具类

基于StringRedisTemplate封装一个缓存工具类,满足以下需求: 方法1:将任意Java对象序列化为json并存储在string类型的key中,并且可以设置TTL过期时间 方法2:将任意Java对象序列化为json并存储在string类型的key中,并且可以设置TTL过期时间,用于处理缓存击穿问题 方法3:根据指定的…...