【C语言】指针详解(一)
个人主页 : zxctscl
如有转载请先通知
文章目录
- 1.内存与地址
- 2.指针变量与地址
- 2.1 取地址操作符&
- 2.2 指针变量
- 2.3 指针类型
- 2.4 解引用操作符
- 2.5 指针变量的大小
- 3. 指针变量类型的意义
- 3.1 指针的解引用
- 4. const修饰指针
- 4.1 const修饰变量
- 4.2 const修饰指针变量
- 5. 指针运算
- 5.1 指针+-整数
- 5.2 指针-指针
- 5.3 指针的运算关系
- 6. 野指针
- 6.1 野指针成因
- 6.2 如何规避野指针
- 6.2.1 指针初始化
- 6.2.2 小心指针越界
- 6.2.3 指针变量不再使用时,及时置NULL,指针使用之前检查有效性
- 7. assert断言
- 8. 指针的使用和传址调用
1.内存与地址
大家对地址都不陌生,就像在生活中住酒店如何找到房间?那不就通过房卡上的房间号先确定楼层在确定房间。而这些房间号我们也叫地址。
把内存划分为一个个内存单元,一个单元为一个字节,而计算机中都是以一个比特位存储一个2进制位,一个字节也就是8个比特位。
这使得每个内存单元都有一个编号,通过这个编号,就能迅速找到这个内存空间。
在C语言中给地址起了新名叫:指针

所以我们理解的:内存单元的编号 == 地址 == 指针
2.指针变量与地址
2.1 取地址操作符&
在C语言中创建变量其实就是在向内存申请空间。就像这样:
#include <stdio.h>
int main()
{int a = 5;return 0;
}
创建了整型变量a,内存中就申请了4个字节,用来存放整数5。每个字节都有地址,而上面申请的4个字节的地址分别在下面划红线四个。

如果我们想得到a的地址,就需要用到取地址操作符&。
像下面这样就可,但值得注意的是我们打印的是地址用到的是**%p**。
#include <stdio.h>
int main()
{int a = 5;&a;printf("%p\n", &a);return 0;
}

2.2 指针变量
我们通过取地址操作符&,得到的仅仅是地址,它就只是一个数值,有时候为了方便使用,我们把它用指针变量存储。
#include <stdio.h>
int main()
{int a = 5;int* p = &a;return 0;
}
指针变量也是一种变量,不过是用来存放地址,存放在指针变量中的值被理解为指针。
2.3 指针类型
指针也是有类型的。
就像前面所写的:
int a = 5;
int* p = &a;
在p的左边就是int*,*说明的是p为指针变量,而前面的int就是说明p指向的是整型(int)类型的对象。
同理指向char型的指针变量就是char*。
char b = 'a';
char* p = &b;
2.4 解引用操作符
在C语言中,我们找到地址,就可以对地址所指向的对象,而此时所要用到的就是解引用操作符(*)。
#include <stdio.h>
int main()
{int a = 5;int* p = &a;*p=0;return 0;
}
而在上面的代码中,原来a为5,我们通过指针拿到了a的地址,然后通过解引用操作*p=0将原来a的5改为0。
2.5 指针变量的大小
32位机器假设有32根地址总线,每根地址线出来的电信号转换成数字信号后是1或者0,那我们把32根地址线产⽣的2进制序列当做⼀个地址,那么⼀个地址就是32个bit位,需要4个字节才能存储。
如果指针变量是⽤来存放地址的,那么指针变的⼤⼩就得是4个字节的空间才可以。
同理64位机器,假设有64根地址线,⼀个地址就是64个⼆进制位组成的⼆进制序列,存储起来就需要8个字节的空间,指针变的⼤⼩就是8个字节。
#include <stdio.h>
int main()
{printf("%zd\n", sizeof(char *));printf("%zd\n", sizeof(short *));printf("%zd\n", sizeof(int *));printf("%zd\n", sizeof(double *));printf("%zd\n", sizeof(float *));return 0;
}
32位平台下地址,指针变量大小是4个字节

64位平台下地址,指针变量大小是8个字节

结论:
- 32位平台下地址,指针变量大小是4个字节
- 64位平台下地址,指针变量大小是8个字节
- 注意指针变量的大小和类型是无关的,只要指针类型的变量,在相同的平台下,大小都是相同的。
3. 指针变量类型的意义
指针变量的大小和类型无关,只要是指针变量,在同一个平台下,大小都是一样的,为什么还要有各种各样的指针类型呢
3.1 指针的解引用
对比,下面2段代码,主要在调试时观察内存的变化。
//代码1
#include <stdio.h>
int main()
{int n = 0x11223344;int* pi = &n;*pi = 0;return 0;
}
//代码2
#include <stdio.h>
int main()
{int n = 0x11223344;char* pc = (char*)&n;*pc = 0;return 0;
}
调试我们可以看到,代码1会将n的4个字节全部改为0,

但是代码2只是将n的第一个字节改为0。

结论:指针的类型决定了,对指针解引用的时候有多大的权限(一次能操作几个字节)。比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。
4. const修饰指针
4.1 const修饰变量
变量是可以修改的,如果把变量的地址交给一个指针变量,通过指针变量的也可以修改这个变量。
但是如果我们希望一个变量加上一些限制,不能被修改,怎么做呢?这就是const的作用。
#include <stdio.h>
int main()
{int m = 0;m = 20;//m是可以修改的const int n = 0;n = 20;//n是不能被修改的return 0;
}

代码中n是不能被修改的,其实n本质是变量,只不过被const修饰后,在语法上加了限制,只要我们在代码中对n就行修改,就不符合语法规则,就报错,致使没法直接修改n。
但是如果我们绕过n,使用n的地址,去修改n就能做到了,虽然这样做是在打破语法规则。
#include <stdio.h>
int main()
{const int n = 0;printf("n = %d\n", n);int* p = &n;*p = 20;printf("n = %d\n", n);return 0;
}

可以看到这里一个确实修改了,但是我们还是要思考一下,为什么n要被const修饰呢?就是为了不能被修改,如果p拿到n的地址就能修改n,这样就打破了const的限制,这是不合理的,所以应该让p拿到n的地址也不能修改n,那接下来怎么做呢?
4.2 const修饰指针变量
测试无const修饰的情况:
#include <stdio.h>
//代码1
void test1()
{int n = 10;int m = 20;int* p = &n;*p = 20;//ok?p = &m; //ok?
}
测试const放在*的左边情况:
void test2()
{//代码2int n = 10;int m = 20;const int* p = &n;*p = 20;//ok?p = &m; //ok?
}

测试const放在*的右边情况
void test3()
{int n = 10;int m = 20;int* const p = &n;*p = 20; //ok?p = &m; //ok?
}

测试*的左右两边都有const
void test4()
{int n = 10;int m = 20;int const* const p = &n;*p = 20; //ok?p = &m; //ok?
}

const修饰指针变量的时候:
- const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。但是指针变量本身的内容可变。
- const如果放在*的右边,修饰的是指针变量本身,保证了指针变量的内容不能修改,但是指针指向的内容,可以通过指针改变。
5. 指针运算
指针的基本运算有三种,分别是:
• 指针± 整数
• 指针-指针
• 指针的关系运算
5.1 指针±整数
数组在内存中是连续存储的,只要知道第一个元素的地址,后面的元素依次就能找到。
int arr[]={1,2,3,4,5};
而所对应的下标为0,1,2,3,4。
在对不同类型指针变量加减时结果不同,
举个例子:
#include <stdio.h>
int main()
{int n = 10;int* p1 = &n;char* p2 = &n;printf("p1=%p\n", p1);printf("p1+1=%p\n", p1+1);printf("p2=%p\n", p2);printf("p2+1=%p\n", p2+1);return 0;
}
在下面为结果
int类型的就跳过了4个字节,
char类型就跳过1个字节

结论:
指针的类型决定了,指针加减整数时,一次性跳过多少个字节。
5.2 指针-指针
在指针变量相同类型时,计算出的是中间间隔的个数。
举个例子:
#include <stdio.h>
int main()
{int arr[10] = { 0 };int* p1 = &arr[9];int* p2 = &arr[0];int ret = p1-p2 ;printf("%d\n", ret);return 0;
}
结果为

指针类型不同时不能进行指针的加减运算。
5.3 指针的运算关系
计算数组的元素个数时,我们使用了sizeof(数组名),而sizeof中单独放数组名,这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节。
sizeof(arr[0])计算的是首元素的大小,单位也是字节。
#include <stdio.h>
int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };int sz = sizeof(arr) / sizeof(arr[0]);printf("%d\n", sz);return 0;
}

数组名就是数组首元素(第一个元素)的地址是对的,但是有两个例外:
1.sizeof(数组名),sizeof中单独放数组名,这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节。
2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
除此之外,任何地方使用数组名,数组名都表示首元素的地址。
6. 野指针
概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
6.1 野指针成因
- 指针未初始化
#include <stdio.h>
int main()
{int* p;//局部变量指针未初始化,默认为随机值*p = 20;return 0;
}

- 指针越界访问
#include <stdio.h>
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;
}

- 指针指向的空间释放
#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也是地址,这个地址是无法使用的,读写该地址会报错。
#ifdef __cplusplus#define NULL 0
#else#define NULL ((void *)0)
#endif
初始化如下:
#include <stdio.h>
int main()
{int num = 10;int*p1 = #int*p2 = NULL;return 0;
}
6.2.2 小心指针越界
一个程序向内存申请了哪些空间,通过指针也就只能访问哪些空间,不能超出范围访问,超出了就是越界访问。
6.2.3 指针变量不再使用时,及时置NULL,指针使用之前检查有效性
当指针变量指向一块区域的时候,我们可以通过指针访问该区域,后期不再使用这个指针访问空间的时候,我们可以把该指针置为NULL。因为约定俗成的一个规则就是:只要是NULL指针就不去访问,同时使用指针之前可以判断指针是否为NULL。
我们可以把野指针想象成野狗,野狗放任不管是⾮常危险的,所以我们可以找一棵树把野狗拴起来,就相对安全了,给指针变量及时赋值为NULL,其实就类似把野狗栓前来,就是把野指针暂时管理起来。
不过野狗即使拴起来我们也要绕着走,不能去挑逗野狗,有点危险;对于指针也是,在使用之前,我们也要判断是否为NULL,看看是不是被拴起来起来的野狗,如果是不能直接使用,如果不是我们再去使用。
#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,67,7,8,9,10 };int* p = &arr[0];for (i = 0; i < 10; i++){*(p++) = i;}//此时p已经越界了,可以把p置为NULLp = NULL;//下次使⽤的时候,判断p不为NULL的时候再使⽤//...p = &arr[0];//重新让p获得地址if (p != NULL) //判断{//...}return 0;
}
7. assert断言
assert.h 头文件定义了宏 assert() ,用于在运行时确保程序符合指定条件,如果不符合,就报
错终止运行。这个宏常常被称为“断言”。
assert(p != NULL);
代码在程序运行到这一行语句时,验证变量 p 是否等于 NULL 。如果确实不等于 NULL ,程序继续运行,否则就会终止运行,并且给出报错信息提示。
assert() 宏接受一个表达式作为参数。如果该表达式为真(返回值非零), assert() 不会产生任何作用,程序继续运行。如果该表达式为假(返回值为零), assert() 就会报错,在标准错误流 stderr 中写入一条错误信息,显示没有通过的表达式,以及包含这个表达式的文件名和行号。
assert() 的使用对程序员是非常友好的,使用assert() 有几个好处:它不仅能自动标识文件和出问题的行号,还有一种无需更改代码就能开启或关闭 assert() 的机制。如果已经确认程序没有问题,不需要再做断言,就在 #include<assert.h> 语句的前面,定义一个宏 NDEBUG 。
#define NDEBUG
#include <assert.h>
然后,重新编译程序,编译器就会禁⽤⽂件中所有的 assert() 语句。如果程序⼜出现问题,可以移除这条 #define NDBUG 指令(或者把它注释掉),再次编译,这样就重新启⽤了 assert() 语句。
assert() 的缺点是,因为引入了额外的检查,增加了程序的运行时间。
⼀般我们可以在debug中使用,在release版本中选择禁⽤assert就行,在VS这样的集成开发环境中,在release版本中,直接就是优化掉了。这样在debug版本写有利于程序员排查问题,在release版本不影响用户使用时程序的效率。
8. 指针的使用和传址调用
学习指针的目的是使用指针解决问题,那什么问题,非指针不可呢?
例如:写一个函数,交换两个整型变量的值
一番思考后,我们可能写出这样的代码
#include <stdio.h>
void Swap1(int x, int y)
{int tmp = x;x = y;y = tmp;
}int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b);printf("交换前:a=%d b=%d\n", a, b);Swap1(a, b);printf("交换后:a=%d b=%d\n", a, b);return 0;
}

其实没产生交换的效果,这是为什么呢?
调试一下,试试呢?

我们发现在main函数内部,创建了a和b,a的地址是0x00cffdd0,b的地址是0x00cffdc4,在调用Swap1函数时,将a和b传递给了Swap1函数,在Swap1函数内部创建了形参x和y接收a和b的值,但是x的地址是0x00cffcec,y的地址是0x00cffcf0,x和y确实接收到了a和b的值,不过x的地址和a的地址不一样,y的地址和b的地址不一样,相当于x和y是独立的空间,那么在Swap1函数内部交换x和y的值,自然不会影响a和b,当Swap1函数调用结束后回到main函数,a和b的没法交换。Swap1函数在使用的时候,是把变量本身直接传递给了函数,这种调用函数的方式我们之前在函数的时候就知道了,这种叫传值调用。
结论:实参传递给形参的时候,形参会单独创建一份临时空间来接收实参,对形参的修改不影响实参。所以Swap是失败的了。
那怎么办呢?
我们现在要解决的就是当调用Swap函数的时候,Swap函数内部操作的就是main函数中的a和b,直接将a和b的值交换了。那么就可以使用指针了,在main函数中将a和b的地址传递给Swap函数,Swap函数里边通过地址间接的操作main函数中的a和b就好了
#include <stdio.h>void Swap2(int* px, int* py)
{int tmp = 0;tmp = *px;*px = *py;*py = tmp;
}
int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b);printf("交换前:a=%d b=%d\n", a, b);Swap2(&a, &b);printf("交换后:a=%d b=%d\n", a, b);return 0;
}

有问题请指出,大家一起进步!!!
相关文章:
【C语言】指针详解(一)
个人主页 : zxctscl 如有转载请先通知 文章目录 1.内存与地址2.指针变量与地址2.1 取地址操作符&2.2 指针变量2.3 指针类型2.4 解引用操作符2.5 指针变量的大小 3. 指针变量类型的意义3.1 指针的解引用 4. const修饰指针4.1 const修饰变量4.2 const修饰指针变量…...
unity3D雨雪等粒子特效不穿透房屋效果实现(粒子不穿透模型)
做项目有时候会做天气模拟,模拟雨雪天气等等。但是容易忽略一个问题,就是房屋内不应该下雨或者下雪,这样不就穿帮了嘛。 下面就粒子穿透物体问题做一个demo。 正常下雨下雪在室内的话,你可以看到,粒子是穿透建筑的。 那要怎么模拟真实的雨雪天气,不让粒子穿透房屋建筑呢…...
ROS2安装cartographer
2. 安装Cartographer和Cartographer ROS 使用apt安装(推荐): bash sudo apt install ros-humble-cartographer-ros或者,从源代码安装: bash sudo apt-get update sudo apt-get install -y python3-wstool python3…...
kafka测试
1】确认 ZooKeeper 服务状态 为了进一步确认 ZooKeeper 服务的状态,你可以执行以下操作: 检查 ZooKeeper 服务状态: docker ps 确保 ZooKeeper 容器正在运行。 检查 ZooKeeper 日志: docker logs zookeeper 查看最新的日志条目&…...
总结C/C++中内存区域划分
目录 1.C/C程序内存分配主要的几个区域: 2.内存分布图 1.C/C程序内存分配主要的几个区域: 1、栈区 2、堆区 3、数据段(静态区) 4.代码段 2.内存分布图 如图: static修饰静态变量成员——放在静态区 int globalVar 是…...
第168天:应急响应-ELK 日志分析系统Yara规则样本识别特征提取规则编写
目录 案例一:ELK 搭建使用-导入文件&监控日志&语法筛选 案例二:Yara 规则使用-规则检测&分析特征&自写规则 案例一:ELK 搭建使用-导入文件&监控日志&语法筛选 该软件是专业分析日志的工具,但是不支持安…...
MySQL 面试题及答案
MySQL 面试题及答案: 一、基础问题 什么是数据库索引?有哪些类型? 答:数据库索引是一种数据结构,用于提高数据库查询的效率。它就像一本书的目录,可以快速定位到特定的数据行。 类型主要有: …...
vue仿chatGpt的AI聊天功能--大模型通义千问(阿里云)
vue仿chatGpt的AI聊天功能–大模型通义千问(阿里云) 通义千问是由阿里云自主研发的大语言模型,用于理解和分析用户输入的自然语言。 1. 创建API-KEY并配置环境变量 打开通义千问网站进行登录,登陆之后创建api-key,右…...
养老院管理系统(含源码+sql+视频导入教程+文档)
👉文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 养老院管理系统拥有两种角色:管理员和护工 管理员:用户管理、老人信息管理、事故记录管理、入住费用管理、护工薪资管理、护工请假管理、床位管理、请假管理等 护…...
大数据的挑战是小文件
小文件可能会给存储平台及其支持的应用程序带来大问题。在 Google 上搜索 “small files performance” 会产生 2M 的结果。这篇博文将更深入地研究小文件问题,深入研究其根源并总结解决方案。 问题陈述 出于本讨论的目的,小文件通常被视为小于 64 KB …...
迁移学习案例-python代码
大白话 迁移学习就是用不太相同但又有一些联系的A和B数据,训练同一个网络。比如,先用A数据训练一下网络,然后再用B数据训练一下网络,那么就说最后的模型是从A迁移到B的。 迁移学习的具体形式是多种多样的,比如先用A训练…...
MCUboot 和 U-Boot区别
MCUboot 和 U-Boot 都是用于嵌入式系统的引导加载程序,但它们在一些方面存在区别: 功能特性 安全特性侧重不同 MCUboot :更专注于安全引导方面,强调安全启动、固件完整性验证和加密等安全功能。它提供了强大的安全机制来防止恶意…...
Apache OFBiz SSRF漏洞CVE-2024-45507分析
Apache OFBiz介绍 Apache OFBiz 是一个功能丰富的开源电子商务平台,包含完整的商业解决方案,适用于多种行业。它提供了一套全面的服务,包括客户关系管理(CRM)、企业资源规划(ERP)、订单管理、产…...
计算机毕业设计 饮食营养管理信息系统的设计与实现 Java实战项目 附源码+文档+视频讲解
博主介绍:✌从事软件开发10年之余,专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ 🍅文末获取源码联系🍅 👇🏻 精…...
828华为云征文|华为云Flexus云服务器X实例部署——盲盒抽奖商城系统以及编译发布小程序
盲盒抽奖商城系统使用 thinkphp6.0 uniapp 开发,做到了全移动端兼容。一个系统不仅可以打包 小程序 还可以 打包APP ,H5 华为云Flexus云服务器X实例在安装搭建盲盒商城小程序方面具有显著优势,这些优势主要体现在以下几个方面: …...
优化理论及应用精解【12】
文章目录 最优化基础基本概念一、目标函数二、约束条件三、约束函数 可行域与可行点可行点可行域可行点与可行域的关系示例 最优值与可行域的关系1. 最优值一定在可行域内取得2. 可行域定义了最优解的搜索空间3. 最优值的存在性与可行域的性质有关4. 最优值与可行域的边界关系示…...
excel 填充内容的公式
多行填充快捷方式: 使用“CtrlEnter”键,这样所有选中的空单元格前就会自动添加上相同的字符。 对于多行填充,Excel提供了几个快捷键来提高工作效率: “CtrlR”用于向右填充数据。如果你在表格的某一列输入了数据,选…...
这款工具在手,前端开发轻松搞定!
这款工具在手,前端开发轻松搞定! 引言 在之前的一篇文章中,已经给大家分享了一款AI助手。尽管该助手能够生成前端代码,但遗憾的是缺少了实时预览的功能。而现在,这一缺憾已经被弥补——你只需要描述你的设计想法&…...
Hadoop三大组件之HDFS(一)
HDFS 简介 HDFS (Hadoop Distributed File System) 是一个分布式文件系统,用于存储文件,采用目录树结构来定位文件。它由多个服务器组成,每个服务器在集群中扮演不同的角色。 适合一次写入,多次读取的场景。文件创建、写入和关闭…...
基于Hadoop的NBA球员大数据分析及可视化系统
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏:Java精选实战项目…...
使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...
