C语言----深入理解指针(3)

1.字符指针变量

//int main()
//{
//    char ch = 'w';
//    char*pc=&ch;
//    printf("%c", *pc);
//    return 0;
//}/*int main()
{//char* p = "abcdef";//char arr[] = "abcdef";//常量字符串 a b c d e f \0//char* pc = arr;//将数组首元素的地址存在p中const char* p = "abcdef";//这里的赋值是讲字符串中首字符的地址存在p中printf("%c\n", *p);//打印a//如何打印一整个字符串呢?printf("%s\n", p);//使用%s打印字符串的时候,只需要提供首字符的地址就行了//*p='q'------不允许修改,因为p指向的是常量字符串,常量字符串不能被修改//在5303行添加const可以防止*p被修改return 0;
}*/int main()
{char str1[] = "hello bit.";char str2[] = "hello bit.";const char* str3 = "hello bit.";const char* str4 = "hello bit.";if (str1 == str2)printf("str1 and str2 are same\n");elseprintf("str1 and str2 are not same\n");if (str3 == str4)printf("str3 and str4 are same\n");elseprintf("str3 and str4 are not same\n");return 0;
}//输出结果
/*str1 and str2 are not same
str3 and str4 are same
为什么会出现这种情况呢?str1是一个数组
str2是一个数组,只是内容相同而已"hello bit."是一组常量字符串,是不能被修改的
内容相同的常量字符串只需要保存一份就可以
str3和str4存的都是h的地址,两个指针变量各自指向同一个地址在这个条件语句中if (str1 == str2)
str1是数组名,首元素的地址,str2也是数组名,也是首元素的地址
str1和str2各占两份不同的空间,只是内容一样
完全不同的两个空间在这个条件语句中if (str3 == str4)
str3和str4存放的都是h的地址,存放的是同一个地址
所以二者相同这个代码里面的比较,不是比较字符串,比较的是地址
*/

使用%s打印字符串的时候,只需要提供首字符的地址就行了

char* p = "abcdef";//这里的赋值是讲字符串中首字符的地址存在p中

2.数组指针变量

指针数组--是数组--存放的是指针(地址)

数组指针是什么呢?

类比:字符指针--char*---指向字符的指针--字符指针变量中存放字符的地址

char ch='w';

char *pc=&ch;

整型指针---int*--指向整型的指针--整型指针变量中存放的整型变量的地址

int a=10

int *p=&a

那么数组指针就是指向数组的指针

数组指针变量存放的是数组的地址

数组的地址--&数组名

指针数组

1.是数组

2.是存放指针的数组

char* arr[6]-----char*是数组的元素类型---存放字符串指针的数组

int *arr2[5]---存放整型指针的数组

数组指针

是指针,指向数组的指针

*p--表示这是一个指针变量

这个指针指向的是数组,得有大小[10]

(*p)[10]

数组指向的元素类型是什么呢?在前面加上类型

int (*p)[10]--这里的p就是数组指针,P指向的数组有10个元素,每个元素的类型是int

p的类型是int (*)[10]

将数组的地址取出来,存放在指针变量里面,

charptr)=&arr---arr里面都是char类型的

//指针数组
//int main()
//{
//    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//    int(*p)[10] = &arr;//取出的是数组的地址,那么数组的地址就应该放到数组指针里面
//
//    //想使用p这个数组指针访问arr数组的内容
//    //p里面放的是数组的地址,那么*p就相当于拿到了一个数组
//    for (int i = 0; i < 10; i++)
//    {//*p就是数组,那么咱们加上[i]就说明直接访问arr[i],随着i的变化,逐步打印数组内的内容
//        printf("%d", (*p)[i]);
//    }
//    return  0;
//}
//上面这种就显得有点麻烦//int main()
//{
//    //int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//    //int(*p)[10] = &arr;//取出的是数组的地址,那么数组的地址就应该放到数组指针里面
//
//    想使用p这个数组指针访问arr数组的内容
//    p里面放的是数组的地址,那么*p就相当于拿到了一个数组
//    //for (int i = 0; i < 10; i++)
//    //{//*p就是数组,那么咱们加上[i]就说明直接访问arr[i],随着i的变化,逐步打印数组内的内容
//    //  printf("%d", (*p)[i]);
//    //}
//    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//    int* p = arr;
//    for (int i = 0; i < 10; i++)
//    {
//        printf("%d",p[i]);//p就是首元素的地址   p[i]---*(p+i)
//    }
//
//
//    return  0;
//}

3.二维数组传参的本质

不管是一位数组还是二维数组传参,形参可以写成数组,也可以写成指针

这里要对数组名做一个深入的理解

咱们要考虑到arr是数组首元素的地址

数组名+i就是跳过i个数组

arr[i]-----(arr+i)---第i行 arr[i][j]-----((arr+i)+j)---(arr+i)是第i行首元素的地址,+j就表示下标为j的数字的地址,再解引用就能得到下标为j的数字

对于一个二维数组的话,arr是数组名,同时也是这个二维数组第一行的元素地址

arr+i就是这个二维数组第i行的地址

对于(*(arr + i))[j]的理解

*(arr + i)就是这个二维数组的第i行的地址解引用得到第i行

[j]这个就是第i行下标为j的元素

对于((arr + i)+j)的理解

*(arr + i)是第i行首元素的地址,这个首元素的地址+j就是第i行下标为j的数字的地址,

*(arr + i)+j再将其解引用得到的就是第i行下标为j的元素

//二维数组传参的本质/*void print(int arr[3][5], int r, int c)
{//两层循环,第一层循环打印行,第二层循环打印列for (int i = 0; i < r; i++){for (int j = 0; j < 5; j++){printf("%d ", arr[i][j]);//打印一行的内容}printf("\n");//换行}}int main()
{int arr[3][5] = { {1,2,3,4,5}, {2,3,4,5,6}, {3,4,5,6,7} };print(arr, 3, 5);//将arr数组的内容打印出来,数组名、行和列都要传上去return 0;
}*/
//一维数组传参
/*数组名是首元素的地址
* 一维数组在传参的时候,其实传递的是首元素的地址
* 
* 函数的参数可以写成数组,也可以写成指针
* 
* 那么二维数组呢?
* 二维数组的数组名该如何理解呢?
* 其实二维数组的数组名也是数组首元素的地址,但是是那个数字呢?二维数组可以理解为一维数组的数组
将二维数组里面的三个一维数组当成一个元素
二维数组有三个元素,每个元素有三个数组
二维数组的每一行可以看成是一个一维数组‘二维数组的首元素就是这个二维数组的第一行二维数组的数组名就是第一行的地址
不是第一行首元素的地址,而是第一行整个一维数组的地址*/void print(int(*arr)[5], int r, int c)//因为传过来的是一位数组的地址,我们要用数组指针接收
//使用数组指针存放第一行的地址,传过来的是一个一维数组,那么我们就需要一个数组指针来接收
{//这个数组指针并不是指向的二维数组,而是指向的是这个二维数组的第一行//两层循环,第一层循环打印行,第二层循环打印列for (int i = 0; i < r; i++){for (int j = 0; j < 5; j++){//第一行是arr//第二行是arr+1printf("%d ", (*(arr + i))[j]);//arr+i就是第几行,*(arr + i)就是解引用相当于直接访问数组后面的[j]就是那一行一维数组里面的第几个元素}   //printf("%d ", *(*(arr + i)+j))//arr+i是某一行的地址,将其括起来解引用就是这一行,相当得到第i行的数组名// *(arr+i)==arr[i],arr[i]是第i行的数组名,数组名是数组首元素的地址// *(arr + i)数组首元素的地址+j就是这一行首元素后面第j个元素的地址,再解引用// 再将这个地址解引用得到的就是数组首元素// *(arr + i)一行首元素的地址再+j就是下标为j的元素了// 对于这个二维数组,arr[i]表示的是arr[i][0],第i行第1个元素的地址// // //*(arr + i)这个是某一行,相当于拿到这一行的数组名字//对于二维数组arr的话//arr[0]是第一行的数组名//arr[1]是第二行的数组名printf("\n");//换行}
}int main()
{int arr[3][5] = { {1,2,3,4,5}, {2,3,4,5,6}, {3,4,5,6,7} };print(arr, 3, 5);//将arr数组的内容打印出来,数组名、行和列都要传上去//arr是在这个二维数组首元素的地址,是第一行的地址,第一行是一位数组//这里传过去的是第一行的地址return 0;
}
/*不管怎么写对于二维数组arr+i就是这个二维数组的第i行一维数组,
* 传参时的arr是二维数组第一行,
* 
* 数组名+i就是跳过一整个数组,对于二维数组,里面是存在好几个一维数组的
对于(*(arr + i))[j]的理解
*(arr + i)就是这个二维数组的第i行的地址解引用得到第i行
[j]这个就是第i行下标为j的元素对于*(*(arr + i)+j)的理解
*(arr + i)是第i行首元素的地址,这个首元素的地址+j就是第i行下标为j的数字的地址,
*(arr + i)+j再将其解引用得到的就是第i行下标为j的元素arr[i]-----*(arr+i)---第i行
arr[i][j]-----*(*(arr+i)+j)---*(arr+i)是第i行首元素的地址,+j就表示下标为j的数字的地址,再解引用就能得到下标为j的数字*/

*(*(arr+i)+j) 是访问二维数组中第i行,第j列元素的方法。

在C语言中,二维数组可以看作是由多个一维数组组成的连续存储空间。定义一个 int 类型的二维数组 arr,用 arr[i][j] 表示其第 i 行、第 j 列的元素,也可以写成 *(*(arr+i)+j)

解释 *(*(arr+i)+j) 的过程如下:

  1. arr 是一个指向二维数组首地址的指针,*(arr+i) 表示访问第 i 个一维数组的首地址。

  2. *(arr+i)+j 表示在第 i 个一维数组的基础上向后移动 j 个位置,即访问第 i 行、第 j 列元素的地址。

  3. *(*(arr+i)+j) 表示访问上述地址所存储的值,即获取第 i 行、第 j 列的元素值。

(*(arr + i))[j] 也可以用来访问二维数组中第 i 行,第 j 列的元素。

在C语言中,二维数组可以看作是由多个一维数组组成的连续存储空间。定义一个 int 类型的二维数组 arr,用 arr[i][j] 表示其第 i 行、第 j 列的元素,也可以写成 *(*(arr+i)+j)(*(arr + i))[j]

解释 (*(arr + i))[j] 的过程如下:

  1. arr 是一个指向二维数组首地址的指针,*(arr + i) 表示访问第 i 个一维数组的首地址。

  2. (*(arr + i))[j] 表示使用 [] 运算符访问该一维数组中下标为 j 的元素,即获取第 i 行、第 j 列的元素值。

4.函数指针变量

变量有地址,数组有地址,函数是否有地址呢?

/*int Add(int x, int y)
{return x + y;
}int main()
{printf("%p\n", &Add);//地址是00701040printf("%p\n", Add);//地址是00701040//这两种写法没区别//如果想将函数名存起来怎么搞呢?int(*pf)(int,int) = &Add;//函数指针变量//*和pf结合,表示pf是指针变量//后面的(int,int)是指向的那个函数的参数//前面的int是指向的那个函数的返回类型//那么pf的指针类型是什么呢?//int(*)(int,int)---pf的类型//交代pf指向的函数的参数个数和类型就行//那我们能通过这个pf调用这个函数呢?int ret=(*pf)(4, 5);//pf是地址,加*解引用,然后得到函数后咱们就要提供数据,传参,在后面的括号内添加数据printf("%d", ret);//打印的结果就是9//int ret =Add(4,5)//还存在一种写法:int ret=pf(4, 5);---直接用过pf找到函数,因为pf里面存放的是函数的地址//只要是函数指针变量就能这么写,可以不写*//如果要写*的话,那么就要带上括号//通过函数的地址,也能调用函数return 0;
}*/
    //对于这种复杂的代码,我们应该如何简单化呢?return 0;
}*//*typedef unsigned int unit;//将unsigned int类型的数重定义名字为unit
int main()
{unsigned int num;//把一个相对长的类型简单化了unit num2;//上面两个代码的内容是一样的return 0;
}*///typedef是用于类型重命名的,可以将复杂的类型简单化
//但如果是指针,能否重命名呢?
//typedef int* pint_t;
//int main()
//{
//    pint_t p2;//整形指针
//
//    
//        
//    return 0;
//}//那么对于复杂点的数组指针和函数指针该如何命名呢?
/*typedef int(*parr_t)[6];
//对于数组指针重命名时,新的名字应该放在*的旁边
int main()
{int arr[6] = { 0 };int(*p)[6]= & arr;//当我们把名字去掉,那么剩下的就是p的类型了 //p是指针变量的的名字//在重新定义的时候,新的名字放在原本p的位置parr_t p2;return 0;
}*///现在对函数重命名
/*typedef int(*pf_t)(int, int);//函数的重命名还是把新名字放到*号旁边
Add(int x, int y)
{return x + y;
}
int main()
{int(*pf)(int ,int)=Add;//去掉名字就是函数指针类型pf_t pf2 = Add;return 0;
}*/

整型指针、数组指针、函数指针

5.函数指针数组

int Add(int x, int y)
{return x + y;
}
int Sub(int x, int y)
{return x - y;
}
int Mull(int x, int y)
{return x * y;
}
int Div(int x, int y)
{return x / y;
}
//指针数组
int main()
{//int* arr1[6];整型指针数组//char* arr2[5];字符指针数组//arr[3][5];//每个元素是函数---函数指针数组int (*pf1) (int ,int) = Add;int (*pf2) (int, int) = Sub;int (*pf3) (int, int) = Mull;int (*pf4) (int, int) = Div;//函数指针数组来存放这些函数的地址呢?//函数指针数组从函数指针的基础来写int (*pf[4]) (int, int) = { Add, Sub ,Div ,Mull };//将函数指针放到函数指针数组里面//通过下标来找数据for (int i = 0; i < 4; i++){int ret=pf[i](6,2);//后面的括号内放的是计算的数据printf("%d\n", ret);}return 0;
}

从函数指针的基础来写函数指针数组来写是最方便的

存放的都是相同类型的元素

6.转移表

函数指针数组

创建函数指针数组来调用

//实现一个计数器
//完成加减乘除
/*int Add(int x, int y)//加法
{return x + y;
}
int Sub(int x, int y)//减法
{return x - y;
}
int Mull(int x, int y)//乘法
{return x * y;
}
int Div(int x, int y)//除法
{return x / y;
}
void menu()
{printf("**************************************************\n");printf("************    1. add      2. sub   *************\n");printf("************    3. mull     4. div   *************\n");printf("**************       0. exit         *************\n");
}int main()
{int input = 0;int x =0, y = 0,ret=0;do{menu();//菜单printf("请选择");scanf("%d", &input);switch (input)//判断输入的值{case 1:printf("请输入两个操作数");scanf("%d %d", &x, &y);//输入数字//调用函数Addret=Add(x, y);printf("%d\n", ret);break;case 2:printf("请输入两个操作数");scanf("%d %d", &x, &y);//输入数字//调用函数Subret = Sub(x, y);printf("%d\n", ret);break;case 3:printf("请输入两个操作数");scanf("%d %d", &x, &y);//输入数字//调用函数Mullret = Mull(x, y);printf("%d\n", ret);break;case 4:printf("请输入两个操作数");scanf("%d %d", &x, &y);//输入数字//调用函数Divret = Div(x, y);printf("%d\n", ret);break;case 0:printf("退出计算器\n");break;default://输入的值不是这里面的任何的一个值printf("选错了,重新选择\n");break;}} while (input);return 0;
}*/
//这种写法过去复杂,对于不同符号的计算
//
//将这些函数的地址放到 一个指针数组里面
int Add(int x, int y)//加法
{return x + y;
}
int Sub(int x, int y)//减法
{return x - y;
}
int Mull(int x, int y)//乘法
{return x * y;
}
int Div(int x, int y)//除法
{return x / y;
}
void menu()
{printf("**************************************************\n");printf("************    1. add      2. sub   *************\n");printf("************    3. Mull     4. div   *************\n");printf("**************       0. exit         *************\n");
}int main()
{int input = 0;int x =0, y = 0,ret=0;//创建一个数组放函数//函数指针数组---转移表int (*pfArr[5])(int, int) = {0,   Add,Sub,Mull,Div};//                           0     1   2    3   4     下标do{menu();//菜单printf("请选择");scanf("%d", &input);if (input >= 1 && input <= 4){printf("请输入两个操作数");scanf("%d %d", &x, &y);//输入要运算的数字ret = pfArr[input](x, y);//通过数组下标访问数组内存放的函数,再通过输入再传入数据进行计算printf("%d\n", ret);//直接调用数组内的函数}else if (input == 0){printf("退出计数器\n");}else//选择的不是这些值{printf("选择错误,重新选择\n");}} while (input);return 0;
}
//通过数组的方式把函数都调用起来,用过下标找到函数再进行调用

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

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

相关文章

高防IP是什么意思?

在网络安全中&#xff0c;企业和用户经常会受到网络攻击和流量攻击&#xff0c;比如DDOS攻击和CC攻击等&#xff0c;那么对于这些网络攻击&#xff0c;企业和用户有什么解决方案呢&#xff1f; 对于网络攻击&#xff0c;高防IP是一种针对网络攻击和分布式拒绝服务攻击设计的IP解…

【002】FlexBison原理分析

0. 前言 Flex和Bison是用于构建处理结构化输入的程序的工具。它们最初是用于构建编译器的工具&#xff0c;但它们已被证明在许多其他领域都很有用。 &#xfeff; 在第一章中&#xff0c;我们将首先看一点(但不是太多)它们背后的理论&#xff0c;然后我们将深入研究一些使用它…

K8S认证|CKA题库+答案| 5. 创建 Ingress

5 . 创建 Ingress 您必须在以下Cluster/Node上完成此考题&#xff1a; Cluster Master node Worker node k8s master …

基于Tensorflow卷积神经网络垃圾智能分类系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景与意义 随着城市化进程的加速&#xff0c;垃圾问题日益严重&#xff0c;垃圾分类成为解决这一问题的关…

浅谈金融行业数据安全分类分级

数据安全管理是一项从上而下的、多方配合开展的工作。在进行数据安全管理组织架构建设时&#xff0c;需要从上而下建设&#xff1b;从而全面推动数据安全管理工作的执行和落地&#xff1b;以保证数据安全的合法合规、并长效推动业务的发展和稳定运行。 金融行业机构应设立数据…

「项目」负载均衡在线OJ(ONLINE_JUDGE)系统

&#x1f436;博主主页&#xff1a;ᰔᩚ. 一怀明月ꦿ ❤️‍&#x1f525;专栏系列&#xff1a;线性代数&#xff0c;C初学者入门训练&#xff0c;题解C&#xff0c;C的使用文章&#xff0c;「初学」C&#xff0c;linux &#x1f525;座右铭&#xff1a;“不要等到什么都没有了…

机器学习系列--强化学习

强化学习&#xff08;Reinforcement Learning&#xff0c;RL&#xff09;是一种机器学习方法&#xff0c;旨在通过智能体&#xff08;Agent&#xff09;在环境&#xff08;Environment&#xff09;中采取行动&#xff08;Actions&#xff09;并获取反馈&#xff08;Reward&…

技术驱动未来,全面揭秘 Sui 的生态发展和布局

在不到一年的时间里&#xff0c;由 Mysten Labs 团队创立的 Layer1 区块链 Sui 迅速崛起&#xff0c;成功跃升至去中心化金融&#xff08;DeFi&#xff09;的前十名。根据 DeFi Llama 的数据&#xff0c;Sui的总锁定价值&#xff08;TVL&#xff09;在短短四个月内增长超过 100…

13-云原生监控体系-Mysqld_exporter 监控 MySQL[部署Dashborad告警规则实战]

文章目录 1. 部署1.1. 二进制方式部署1.1.1. 下载1.1.2. 部署1.1.3. MySQL 服务的配置1.2 docker-compose 方式1.3 配置 Prometheus1.4 测试1.5 mysqld_exporter 命令行运行参数1.5.1. 配置格式1.5.2. 运行参数详解1.5.3. 监控不同的集群2. Dashboard2.

【好玩的经典游戏】Docker环境下部署retroarch-web经典游戏模拟器

【好玩的经典游戏】Docker环境下部署retroarch-web经典游戏模拟器 前言一、RetroArch-web介绍二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍三、检查本地环境3.1 检查系统版本3.2 检查Docker服务状态四、拉取镜像五、创建retroarch-web容器5.1 创建容器5.2 查看容器状态六…

深度学习之基于Tensorflow+Flask框架Web手写数字识别

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景与意义 手写数字识别是深度学习领域中的一个经典问题&#xff0c;也是计算机视觉领域的重要应用之一。…

BFT Robotics - 您的智能自动化伙伴

“买机器人&#xff0c;上BFT” 自动化和机器人技术是推动现代工业发展的重要力量。BFT Robotics以其创新的产品系列和定制化解决方案&#xff0c;为企业提供了一条通往高效、智能生产环境的道路。通过采用BFT Robotics的产品和服务&#xff0c;企业不仅能够提高生产效率&#…

编程语言的集合判断逻辑

当判断一个Item是否在集合中&#xff0c;比如List&#xff0c;Map&#xff0c;Array等&#xff0c;只可以判断真&#xff0c;不可以判断假。 如果执着判断&#xff0c;也可以通过设置标志位去实现&#xff0c;这样代码就会显得臃肿&#xff0c;效率低下。 比如 list.forEach…

js JSON.stringify 对象转字符串

通过 JSON.stringify() 把 JavaScript 对象转换为字符串 注&#xff1a; 在 JSON 中&#xff0c;不允许日期对象。JSON.stringify() 函数将把任何日期转换为字符串。在 JSON 中&#xff0c;不允许函数作为对象值。 JSON.stringify() 函数将从 JavaScript 对象删除任何函数&am…

iView实现表格拖拽列宽度,列显示顺序及显示字段

需要实现表格列宽度调整,选择展示表格字段,以及显示顺序,先看效果,每次变动后保存到本地缓存中,也可以与后台配合保存到数据库,实现用户自定义表格. 1.安装vuedraggable实现拖拽 npm i vuedraggable2.新建组件 FilterColumns.vue 我这里默认把操作列放到最后一个并且不允许…

机器学习(五) -- 监督学习(3) -- 决策树

系列文章目录及链接 上篇&#xff1a;机器学习&#xff08;五&#xff09; -- 监督学习&#xff08;2&#xff09; -- 朴素贝叶斯 下篇&#xff1a;机器学习&#xff08;五&#xff09; -- 监督学习&#xff08;4&#xff09; -- 集成学习方法-随机森林 前言 tips&#xff1a…

学习Uni-app开发小程序Day23

今天学习了将上一章的所有核算的js&#xff0c;抽离出去&#xff0c;让在其他地方可以直接调用&#xff0c;然后和适配抖音的办法&#xff0c;封装网络请求&#xff1b; 抽离公共方法 如何将公共方法抽离&#xff1f; 1、在根目录创建一个目录&#xff0c;一般起名是:utils 2…

物联网网关在电梯按需维保方案中起到什么作用?梯联网网关

为减少电梯故障和预防电梯事故&#xff0c;保障人身和财产安全&#xff0c;基于物联网技术的电梯按需维保已在全国多地陆续推行&#xff0c;做到了电梯安全隐患预测式排查&#xff0c;处理问题更具科学性、针对性和精准性&#xff0c;有效提升了电梯运行的安全性。那么&#xf…

深度学习之基于YoloV5入侵检测系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 随着信息技术的飞速发展&#xff0c;网络安全问题日益凸显。入侵检测系统&#xff08;IDS&#xff0…