考研C语言复习初阶(5)

目录

一.表达式求值

 1.1隐式类型转换

 1.2 算术转换

 12.3 操作符的属性

二. 指针是什么?

三 指针和指针类型 

3.1 指针+-整数 

 3.2 指针的解引用

3.3 野指针

四.指针运算 

4.1 指针+-整数

4.2 指针-指针 

4.3 指针的关系运算  

5. 指针和数组

6. 二级指针 

7. 指针数组


一.表达式求值


表达式求值的顺序一部分是由操作符的优先级和结合性决定。
同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型

 1.1隐式类型转换

C的整型算术运算总是至少以缺省整型类型的精度来进行的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型
提升。
整型提升的意义:
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度
一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长
度。
通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令
中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转
换为int或unsigned int,然后才能送入CPU去执行运算。

/实例1
char a,b,c;
...
a = b + c;

b和c的值被提升为普通整型,然后再执行加法运算。

加法运算完成之后,结果将被截断,然后再存储于a中。
如何进行整体提升呢?
整形提升是按照变量的数据类型的符号位来提升的 

//负数的整形提升
char c1 = -1;
变量c1的二进制位(补码)中只有8个比特位:
1111111
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为1
提升之后的结果是:
11111111111111111111111111111111
//正数的整形提升
char c2 = 1;
变量c2的二进制位(补码)中只有8个比特位:
00000001
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为0
提升之后的结果是:
00000000000000000000000000000001
//无符号整形提升,高位补0

整形提升的例子:

//实例1
int main()
{
char a = 0xb6;
short b = 0xb600;
int c = 0xb6000000;
if(a==0xb6)
printf("a");
if(b==0xb600)
printf("b");
if(c==0xb6000000)
printf("c");
return 0;
}

实例1中的a,b要进行整形提升,但是c不需要整形提升

a==0xb6 二进制就是10110110,首位是1,高位补1
a,b整形提升之后,变成了负数,所以表达式 a==0xb6 , b==0xb600 的结果是假,但是c不发生整形提升,则表达式 c==0xb6000000 的结果是真.
所程序输出的结果是:

//实例2
int main()
{
char c = 1;
printf("%u\n", sizeof(c));
printf("%u\n", sizeof(+c));
printf("%u\n", sizeof(-c));
return 0;
}

实例2中的,c只要参与表达式运算,就会发生整形提升,表达式 +c ,就会发生提升,所以 sizeof(+c) 是4个字节.
表达式 -c 也会发生整形提升,所以 sizeof(-c) 是4个字节,但是 sizeof(c) ,就是1个字节. 

 1.2 算术转换

如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类型,否则操作就无法进行。下面的层次体系称为寻常算术转换。

 long double
double
float
unsigned long int
long int
unsigned int
int

如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算。

警告:但是算术转换要合理,要不然会有一些潜在的问题 

float f = 3.14;
int num = f;//隐式转换,会有精度丢失 

 12.3 操作符的属性

复杂表达式的求值有三个影响的因素。
1. 操作符的优先级
2. 操作符的结合性
3. 是否控制求值顺序。
两个相邻的操作符先执行哪个?取决于他们的优先级。如果两者的优先级相同,取决于他们的结合性。
操作符优先级

 一些问题表达式

 //表达式的求值部分由操作符的优先级决定。
//表达式1
a*b + c*d + e*f

注释:代码1在计算的时候,由于*比+的优先级高,只能保证,*的计算是比+早,但是优先级并不
能决定第三个*比第一个+早执行。
所以表达式的计算机顺序就可能是:

a*b
c*d
a*b + c*d
e*f
a*b + c*d + e*f 

或者:
a*b
c*d
e*f
a*b + c*d
a*b + c*d + e*f

//表达式2
c + --c; 

注释:同上,操作符的优先级只能决定自减--的运算在+的运算的前面,但是我们并没有办法得
知,+操作符的左操作数的获取在右操作数之前还是之后求值,所以结果是不可预测的,是有歧义
的。

//代码3-非法表达式
int main()
{
int i = 10;
i = i-- - --i * ( i = -3 ) * i++ + ++i;
printf("i = %d\n", i);
return 0;

表达式3在不同编译器中测试结果:非法表达式程序的结果

//代码4
int fun()
{
  static int count = 1;
  return ++count;
}
int main()
{
  int answer;
  answer = fun() - fun() * fun();
  printf( "%d\n", answer);//输出多少?
  return 0;

这个代码有没有实际的问题?
有问题!
虽然在大多数的编译器上求得结果都是相同的。
但是上述代码 answer = fun() - fun() * fun(); 中我们只能通过操作符的优先级得知:先算乘法,
再算减法。
函数的调用先后顺序无法通过操作符的优先级确定。

//代码5
#include <stdio.h>
int main()
{
int i = 1;
int ret = (++i) + (++i) + (++i);
printf("%d\n", ret);
printf("%d\n", i);
return 0;
}
//尝试在linux 环境gcc编译器,VS2013环境下都执行,看结果。 

看看同样的代码产生了不同的结果,这是为什么?
简单看一下汇编代码.就可以分析清楚.
这段代码中的第一个 + 在执行的时候,第三个++是否执行,这个是不确定的,因为依靠操作符的优先级和结合性是无法决定第一个 + 和第三个前置 ++ 的先后顺序。
总结:我们写出的表达式如果不能通过操作符的属性确定唯一的计算路径,那这个表达式就是存在问题的。 

二.

练习1.交换两个变量(不创建临时变量) 

include <stdio.h>
int main()
{int a = 10;int b = 20;printf("交换前:a = %d b = %d\n", a,b);a = a^b;b = a^b;a = a^b;printf("交换后:a = %d b = %d\n", a,b);return 0;
}

练习2.

写一个函数返回参数二进制中 1 的个数。

比如: 15    0000 1111    4 个 1

一个int类型的数据,对应的二进制一共有32个比特位,可以采用位运算的方式一位一位的检测,具体如下
*/
int NumberOf1(unsigned int n)
{int count = 0;int i = 0;for(i=0; i<32; i++){if(((n>>i)&1) == 1)count++;}return count;
}
方法二:
思路:采用相邻的两个数据进行按位与运算
举例:
9999:‭10 0111 0000 1111‬
第一次循环:n=9999   n=n&(n-1)=9999&9998= 9998
第二次循环:n=9998   n=n&(n-1)=9998&9997= 9996
第三次循环:n=9996   n=n&(n-1)=9996&9995= 9992
第四次循环:n=9992   n=n&(n-1)=9992&9991= 9984
第五次循环:n=9984   n=n&(n-1)=9984&9983= 9728
第六次循环:n=9728   n=n&(n-1)=9728&9727= 9216
第七次循环:n=9216   n=n&(n-1)=9216&9215= 8192
第八次循环:n=8192   n=n&(n-1)=8192&8191= 0可以观察下:此种方式,数据的二进制比特位中有几个1,循环就循环几次,而且中间采用了位运算,处理起来比较高效
*/
int NumberOf1(int n)
{int count = 0;while(n){n = n&(n-1);count++;}return count;
}

 练习3:A进制转B进制

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <math.h>
int main() {char x_num[100];int base_x, base_y;int len, i, j, sum = 0;printf("请输入X进制数: ");scanf("%s", x_num);printf("请输入X进制数的基数: ");scanf("%d", &base_x);printf("请输入Y进制数的基数: ");scanf("%d", &base_y);len = strlen(x_num);//X进制转10进制for (i = 0; i < len; i++) {if (x_num[i] >= '0' && x_num[i] <= '9') {j = x_num[i] - '0';}else if (x_num[i] >= 'A' && x_num[i] <= 'Z') {j = x_num[i] - 'A' + 10;}else if (x_num[i] >= 'a' && x_num[i] <= 'z') {j = x_num[i] - 'a' + 10;}sum += j * pow(base_x, len - i - 1);}int y_num[100];int k = 0;//10进制数转Y进制while (sum != 0) {y_num[k++] = sum % base_y;sum /= base_y;}printf("对应的Y进制数为: ");for (i = k - 1; i >= 0; i--) {if (y_num[i] >= 0 && y_num[i] <= 9) {printf("%d", y_num[i]);}else if (y_num[i] >= 10 && y_num[i] <= 35) {printf("%c", y_num[i] - 10 + 'A');}}//printf("");return 0;
}
```

二. 指针是什么?


指针理解的2个要点:
1. 指针是内存中一个最小单元的编号,也就是地址
2. 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量
总结:指针就是地址,口语中说的指针通常指的是指针变量

指针变量
我们可以通过&(取地址操作符)取出变量的内存其实地址,把地址可以存放到一个变量中,这个
变量就是指针变量

#include <stdio.h>
int main()
{
int a = 10;//在内存中开辟一块空间
int *p = &a;//这里我们对变量a,取出它的地址,可以使用&操作符。//a变量占用4个字节的空间,这里是将a的4个字节的第一个字节的地址存放在p变量
中,p就是一个之指针变量。
return 0;
}

 

总结:
指针变量,用来存放地址的变量。(存放在指针中的值都被当成地址处理)。
那这里的问题是:
一个小的单元到底是多大?(1个字节)
如何编址?
经过仔细的计算和权衡我们发现一个字节给一个对应的地址是比较合适的。
对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电
平(低电压)就是(1或者0);
那么32根地址线产生的地址就会是:

        00000000 00000000 00000000 00000000
        00000000 00000000 00000000 00000001
        ...
        11111111 11111111 11111111 11111111

这里就有2的32次方个地址。
每个地址标识一个字节,那我们就可以给 (2^32Byte == 2^32/1024KB ==
2^32/1024/1024MB==2^32/1024/1024/1024GB == 4GB) 4G的空闲进行编址。
同样的方法,那64位机器,如果给64根地址线,那能编址多大空间


这里我们就明白:
在32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储,所以
一个指针变量的大小就应该是4个字节。
那如果在64位机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地
址。 

总结:
指针是用来存放地址的,地址是唯一标示一块地址空间的。
指针的大小在32位平台是4个字节,在64位平台是8个字节。

三 指针和指针类型 

 这里我们在讨论一下:指针的类型
我们都知道,变量有不同的类型,整形,浮点型等。那指针有没有类型呢?
准确的说:有的这里可以看到,指针的定义方式是: type + * 。
其实:
char* 类型的指针是为了存放 char 类型变量的地址。
short* 类型的指针是为了存放 short 类型变量的地址。
int* 类型的指针是为了存放 int 类型变量的地址。

3.1 指针+-整数 

#include <stdio.h>
//演示实例
int main()
{
int n = 10;
char *pc = (char*)&n;
int *pi = &n;
printf("%p\n", &n);
printf("%p\n", pc);
printf("%p\n", pc+1);
printf("%p\n", pi);
printf("%p\n", pi+1);
return  0;
}

总结:指针的类型决定了指针向前或者向后走一步有多大(距离)。 

 3.2 指针的解引用

 

//演示实例
#include <stdio.h>
int main()
{
int n = 0x11223344;
char *pc = (char *)&n;
int *pi = &n;
*pc = 0;  //重点在调试的过程中观察内存的变化。
*pi = 0;  //重点在调试的过程中观察内存的变化。
return 0;
}

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

3.3 野指针


概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
野指针成因
1. 指针未初始化 

 

#include <stdio.h>
int main()
{
int *p;//局部变量指针未初始化,默认为随机值*p = 20;
return 0;
}

2. 指针越界访问

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

3. 指针指向的空间释放 

如何规避野指针
1. 指针初始化
2. 小心指针越界
3. 指针指向空间释放即使置NULL
4. 避免返回局部变量的地址
5. 指针使用之前检查有效性

四.指针运算 

4.1 指针+-整数

#define N_VALUES 5
float values[N_VALUES];
float *vp;
//指针+-整数;指针的关系运算
for (vp = &values[0]; vp < &values[N_VALUES];)
{*vp++ = 0;
}

4.2 指针-指针 

int my_strlen(char *s)
{char *p = s;while(*p != '\0' )p++;return p-s;
}

4.3 指针的关系运算  

 

for(vp = &values[N_VALUES]; vp > &values[0];)
{*--vp = 0;
}

代码简化, 这将代码修改如下:

for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--)
{*vp = 0;
}

 

 标准规定:
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与
指向第一个元素之前的那个内存位置的指针进行比较。

5. 指针和数组


我们看一个例子: 

#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,0};printf("%p\n", arr);printf("%p\n", &arr[0]);return 0;
}

 

可见数组名和数组首元素的地址是一样的。
结论:数组名表示的是数组首元素的地址。(2种情况除外,数组章节讲解了)
那么这样写代码是可行的: 

int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int *p = arr;//p存放的是数组首元素的地址 

既然可以把数组名当成地址存放到一个指针中,我们使用指针来访问一个就成为可能。
例如: 

#include <stdio.h>
int main()
{int arr[] = {1,2,3,4,5,6,7,8,9,0};int *p = arr; //指针存放数组首元素的地址int sz = sizeof(arr)/sizeof(arr[0]);for(i=0; i<sz; i++){printf("&arr[%d] = %p  <====> p+%d = %p\n", i, &arr[i], i, p+i);}return 0;
}

 

所以 p+i 其实计算的是数组 arr 下标为i的地址。
那我们就可以直接通过指针来访问数组。
如下: 

 

int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int *p = arr; //指针存放数组首元素的地址
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i<sz; i++)
{
printf("%d ", *(p + i));
}
return 0;
}

6. 二级指针 

指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?
这就是 二级指针 。 

 

对于二级指针的运算有:
*ppa 通过对ppa中的地址进行解引用,这样找到的是 pa , *ppa 其实访问的就是 pa .         

int b = 20;
*ppa = &b;//等价于 pa = &b; 

**ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,那找到的是 a . 

**ppa = 30;
//等价于*pa = 30;
//等价于a = 30;

7. 指针数组


指针数组是指针还是数组?
答案:是数组。是存放指针的数组。
数组我们已经知道整形数组,字符数组。 

int arr1[5];
char arr2[6]; 

 

那指针数组是怎样的? 

int* arr3[5];//是什么? 

arr3是一个数组,有五个元素,每个元素是一个整形指针。 

 

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

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

相关文章

202012青少年软件编程(图形化) 等级考试试卷(一级)

青少年软件编程(图形化) 等级考试试卷(一级)2020年12月 第1题:【 单选题】 下面哪个区域是“舞台区” ?( ) A:A B:B C:C D:D 【正确答案】: B 【试题解析】 : 第2题:【 单选题】 下图为小猫的初始方向, 哪个积木可以让小猫面向正右方?( ) A: B: C:…

2024.3.11 训练记录(13)

继续补题 文章目录 ICPC 2018青岛I Soldier GameICPC 2018青岛K Airdrop ICPC 2018青岛I Soldier Game 题目链接 线段树 果然稍微复杂一点的线段树就很难实现啊&#xff0c;不看题解根本没反应过来是线段树 struct Node {int l, r, lb, rb, nb, b; } tr[N * 4];其中&#x…

一个Promise全新API

1. 资讯速览 最近&#xff0c;Promise 新出了一个方法&#xff0c;已经进入 Stage 3 &#xff08;候选阶段&#xff09; &#xff0c;相信很快就能达到 Stage 4 &#xff08;完成阶段&#xff09;&#xff0c;并在项目中广泛使用。 这个方法就是 Promise.withResolvers。它是…

【C++干货基地】面向对象核心概念与实践原理:拷贝构造函数的全面解读

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引入 哈喽各位铁汁们好啊&#xff0c;我是博主鸽芷咕《C干货基地》是由我的襄阳家乡零食基地有感而发&#xff0c;不知道各位的…

游戏行业需要堡垒机吗?用哪款堡垒机好?

相信大家对于游戏都不陌生&#xff0c;上到老&#xff0c;下到小&#xff0c;越来越多的小伙伴开始玩游戏。随着游戏用户的增加&#xff0c;如何保障用户资料安全&#xff0c;如何确保游戏公司数据安全等是一个不容忽视的问题。因此不少人在问&#xff0c;游戏行业需要堡垒机吗…

系统设计 - SDK设计流程

▌从 0 到 1 开发 一般从 0 设计一款 SDK&#xff0c;总体上可以分为 5 个步骤&#xff1a;基础架构的设计、开放 API 接口设计、业务功能框架设计与开发、基础核心库设计与开发、打包与发布。 1. 第一步是基础架构设计&#xff0c;一个好的架构可主要从可读性、可扩展性、可维…

css3实现3D立方体旋转特效源码

源码介绍 CSS3自动旋转正方体3D特效是一款基于css3 keyframes属性制作的图片相册自动旋转立方体特效 效果展示 下载地址 css3实现3D立方体旋转特效代码

PCL点云处理之四点确定球心和半径(克拉默法则C++) (二百二十九)

PCL点云处理之四点确定球心和半径(克拉默法则C++) (二百二十九) 一、算法介绍二、算法实现1.代码2.结果一、算法介绍 相比于计算点坐标均值作为球心和某点到均值距离作为半径的快速计算法,这里介绍的方法更加适合精度要求较高的四点定球计算,下面是具体的实现代码,C++编…

搭建mysql主从复制(主主复制)

1&#xff1a;设主库允许远程连接(注意&#xff1a;设置账号密码必须使用的插件是mysql_native_password&#xff0c;其他的会连接失败) #切换到mysql这个数据库&#xff0c;修改user表中的host&#xff0c;使其可以实现远程连接 mysql>use mysql; mysql>update user se…

蓝牙系列十三:协议栈L2CAP层

L2CAP 全称为逻辑链路控制与适配协议(Logical Link Control and Adaptation Protocol)&#xff0c;位于基带层之上&#xff0c;将基带层的数据分组交换为便于高层应用的数据分组格式&#xff0c;并提供协议复用和服务质量交换等功能。 该层属于主机的内容&#xff0c;位于HCI层…

手写Mybatis自动填充插件

目录 一、Mybatis插件简介&#x1f959;二、工程创建及前期准备工作&#x1f96b;实现代码配置文件 三、插件核心代码实现&#x1f357;四、测试&#x1f953; 一、Mybatis插件简介&#x1f959; Mybatis插件运行原理及自定义插件_简述mybatis的插件运行原理,以及如何编写一个…

HTML 语义化:构建优质网页的关键

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

深度学习与强化学习的绝妙融合:引领未来智能科技新潮流!

深度学习在强化学习中的应用已经取得了显著的成果&#xff0c;特别是在处理复杂环境和大规模数据方面。 一、概述 强化学习是一种独特的机器学习范式&#xff0c;其核心在于通过代理与环境的交互来学习最优行为策略。这种学习方式是试错性的&#xff0c;代理在不断地尝试、接…

【JavaScript】面试手撕深拷贝

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 深拷贝的作用深浅拷贝的区别浅拷贝深拷贝 深拷贝实现方式JSON.parse(JSON.stringi…

微信小程序云开发教程——墨刀原型工具入门(素材面板)

引言 作为一个小白&#xff0c;小北要怎么在短时间内快速学会微信小程序原型设计&#xff1f; “时间紧&#xff0c;任务重”&#xff0c;这意味着学习时必须把握微信小程序原型设计中的重点、难点&#xff0c;而非面面俱到。 要在短时间内理解、掌握一个工具的使用&#xf…

在云端构建和部署工作负载的最佳方式是怎样的?

如果要问当今企业希望从云计算中获得什么&#xff0c;那么 “低延迟” 以及 “更接近客户” 可能会是很多企业的首要目标。低延迟可以带来诸多好处&#xff0c;如提升用户满意度、增加竞争优势、降低运营成本等&#xff1b;更接近客户则有助于降低网络拥塞、减少数据丢失、符合…

Java设计模式:外观模式

❤ 作者主页&#xff1a;欢迎来到我的技术博客&#x1f60e; ❀ 个人介绍&#xff1a;大家好&#xff0c;本人热衷于Java后端开发&#xff0c;欢迎来交流学习哦&#xff01;(&#xffe3;▽&#xffe3;)~* &#x1f34a; 如果文章对您有帮助&#xff0c;记得关注、点赞、收藏、…

ArcGIS学习(十四)OD分析

ArcGIS学习(十四)OD分析 1.上海市KFC与麦当劳的空间聚集度分析 本任务给大家带来的内容是网络节点关系分析。网络节点关系分析一般也叫OD分析。“O”指的是起点(ORIGIN),"D”指的是终点(DESTINATION),0D分析即为基于起点到终点的分析。 网络节点关系分析我们经常…

基于springboot的厨艺交流平台

采用技术 基于springboot的厨艺交流平台的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBootMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 页面展示 食材分类管理 用户信息管理 菜谱分类管理 菜谱信息管理 食材信息…

Swarm集群负载均衡的实现方式

目录 1. 背景2. 参考3. 环境4. 概念5. Swarm 网络5.1 Swarm 网络连接情况5.2 外部访问数据包转发流程 6 Swarm集群服务信息7 Swarm集群数据包转发流程7.1 Client发送请求至集群节点9090端口7.1.1 集群节点宿主机Netfilter规则7.1.2 Tcpdump抓包验证结果 7.2 Ingress_sbox下IPVS…