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

玩转指针(3)

一、字符指针变量

字符指针变量(如char* p)的两种赋值方式

①将字符类型地址赋值给字符指针变量
int main()
{char a = 'w';char* p = &a;*p = 'm';return 0;
}
②将常量字符串赋值给字符指针变量
常量字符串的介绍:用" "引起来的就是常量字符串,常量字符串存放在只读数据区,这块区域的内容是可以用的,但是不能被修改的。在这里插入图片描述
将常量字符串赋值给字符指针时,可以将字符指针当做一个字符数组,此时数组的内容无法修改。
int main()
{char* p = "abcdef";//"abcdef"是常量字符串,常量字符串在内存中是连续存放的,且p里面是常量字符串中首字符a的地址/*因此可以认为p是一个字符数组,可以用下标来访问数组中的内容。p数组的内容无法修改,因为常量字符串的内容无法修改*/for (int i = 0; i < 6; i++){printf("%c ", p[i]);}return 0;
}

在这里插入图片描述

一道关于字符指针变量的面试题

在这里插入图片描述
在这里插入图片描述

二、数组指针变量

①何为数组指针变量

字符指针变量(如char * p),p中存放的是字符变量的地址,p指向的是字符;整型指针变量(如int * p),p中存放的是整型变量的地址,p指向的是整型。同理,数组指针变量存放的是数组的地址(&数组名),它指向的是数组。

在这里插入图片描述

小练习:正确书写数组指针变量

在这里插入图片描述

②数组指针变量的使用

在这里插入图片描述

但这种写法不常见,通常不会这么写

③区分指针数组与数组指针

int main()
{//指针数组int a = 0, b = 0, c = 0;int* arr[3] = { &a,&b,&c };//arr是指针数组,数组中每个元素的类型都是int *//数组指针int* (*p)[3] = &arr;//括号中的*表示p是数组指针,存放的是数组arr的地址。它指向的数组类型是int* [3]return 0;
}

三、二维数组传参的本质

①二维数组的数组名

二维数组的每一行可以看做是一个一维数组,即二维数组是由一维数组组成的数组。二维数组的首元素就是它的第一行,因此二维数组的数组名就是数组第一行的地址。

②二维数组中的元素在内存中是连续存放的

在这里插入图片描述

③二维数组传参

二维数组传参时,实参写数组名,形参既可以写成数组的形式(此时二维数组的行的大小可以省略),也可以写成指针的形式。
a、形参写成指针的形式

在这里插入图片描述

b、形参写成数组的形式

在这里插入图片描述

c、补充
对一维数组而言: arr[i]==*(arr+i)
对二维数组而言: arr[i][j] =* (*(arr+i)+j)

四、函数指针变量

①函数地址的介绍:

数组有地址,变量(如int a)也有地址,那么函数有地址吗?答案是有的。函数的地址是存放在函数指针变量中的。&(函数名)与函数名均表示函数的地址,两者没有区别。 这点与数组不同:&(数组名)表示取出整个数组的地址,数组名表示数组首元素的地址。

在这里插入图片描述

② 函数指针变量的创建

函数指针变量是用来存放函数的地址
int Add(int x, int y)
{return x + y;
}int main()
{int(*pa)(int, int) = Add;//或者写成int(*pa)(int x,int y)=Add;//*表示pa是指针变量(函数指针变量),存放的是函数Add的地址。pa指向的函数的返回类型为int,函数的两个参数也是int类型//pa的类型是int(*)(int, int)//*pa表示通过pa中Add的地址,调用Add函数int ret1 = (*pa)(3, 5);printf("%d\n", ret1);//8//一般调用Add函数的方式int ret2 = Add(3, 5);//这里的Add是函数名,也就是函数的地址。pa中存放的也是函数的地址,故可以将这里的Add换成paret2 = pa(3, 5);return 0;
}
总结:可以通过函数名(函数的地址)来调用函数,也可以通过对函数指针变量解引用来调用函数。

五、typedef关键字

①作用

用于对变量类型(如int、int*)重新命名,将复杂类型的名字简单化。
//比如觉得unsigned int这个类型比较复杂,那么就可以使用typedef将该类型重命名为unit 
typedef unsigned int unit;
int main()
{unsigned int a = 1;//等价于unit a=1;return 0;
}

②typedef关键字的使用

typedef int* ptr_t;
int main()
{ptr_t a;//等价于int* a;return 0;
}

③typedef在重命名数组指针类型和函数指针类型时,稍微有点不同

a.typedef在重命名数组指针类型
typedef int(*parr)[5];//将数组指针类型int(*)[5]重命名为parr
//typedef int(*)[5]  parr    这种写法是错误的
int main()
{int arr[5] = { 0 };int(*p)[5] = &arr;//数组指针p的类型是int(*)[5]parr m = &arr;return 0;
}
b.typedef重命名函数指针类型
typedef int (*pf)(int, int);//将函数指针类型int (*)(int, int)重命名为pf
//typedef int (*)(int, int)  pf   这种写法是错误的int Add(int x, int y)
{return x + y;
}
int main()
{int (*p)(int, int) = Add;//p是函数指针变量,它的类型是int (*)(int, int)pf p2 = Add;return 0;
}

六、函数指针数组

①函数指针数组是用来存放函数指针或者函数的地址。(函数指针也是用来存放函数的地址,但函数指针只能存放一个函数的地址,而函数指针数组可以存放多个相同类型函数的地址)

②函数指针数组该怎么写呢?

先写出函数指针变量,然后对函数指针变量进行使当的修改,就是函数指针数组。
int Add(int x, int y)
{return x + y;
}int Sub(int x, int y)
{return x - y;
}int Mul(int x, int y)
{return x * y;
}int Div(int x, int y)
{return x / y;
}
int main()
{int(*p)(int, int) = Add;//p是函数指针变量,p所指向的函数的返回类型是int,函数的两个参数的类型也是intint(* p1[4])(int, int) = { Add,Sub,Mul,Div };//p1是函数指针数组的数组名,数组有4个元素,每个元素的类型都是int(*)(int,int)return 0;
}

③函数指针数组的使用

int Add(int x, int y)
{return x + y;
}int Sub(int x, int y)
{return x - y;
}int Mul(int x, int y)
{return x * y;
}int Div(int x, int y)
{return x / y;
}int main()
{int(*p1)(int, int) = Add;int(*p2)(int, int) = Sub;int(*p3)(int, int) = Mul;int(*p4)(int, int) = Div;//p1、p2、p3、p4是四个函数指针变量,分别存放四个函数的地址,比较麻烦。//观察到这四个函数的类型是一样的,因此可以使用函数指针数组来存放四个函数的地址int(*p[4])(int, int) = {Add,Sub,Mul,Div};//p是函数指针数组的数组名,数组有4个元素,每个元素都是int(*)(int,int)类型//p[0]=Add,p[1]=Sub,p[2]=Mul,p[3]=Divfor (int i = 0; i < 4; i++){printf("%d\n", p[i](6, 3));}return 0;
}

七、转移表

/*设计一个简单的计算器,实现整数的加减乘除*/
int Add(int x, int y)
{return x + y;
}int Sub(int x, int y)
{return x - y;
}int Mul(int x, int y)
{return x * y;
}int Div(int x, int y)
{return x / y;
}
void menu()
{printf("*****    1.Add   2.Sub   *****\n");printf("*****    3.Mul   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);int(*p[5])(int, int) = { 0,Add,Sub,Mul,Div }; //转移表if (input >= 1 && input <= 4){printf("请输入两个操作数:");scanf("%d %d", &x, &y);ret = p[input](x, y);printf("%d\n", ret);}else if (input == 0){printf("退出计算器\n");}else{printf("输入错误,请重新输入\n");}} while (input);return 0;
}
http://www.lryc.cn/news/449841.html

相关文章:

  • 【CSS in Depth 2 精译_040】6.3 CSS 定位技术之:相对定位(下)—— 用纯 CSS 绘制一个三角形
  • HTML流光爱心
  • java技能
  • 本省第一所!新大学,揭牌!
  • 企业微信(企微)审批与影刀RPA结合
  • 新手教学系列——用 VSCode 实现高效远程开发
  • [uni-app]小兔鲜-04推荐+分类+详情
  • PHP人才机遇桥梁招聘求职全能系统小程序源码
  • 计算机毕业设计Hadoop+Spark抖音可视化 抖音舆情监测 预测算法 抖音爬虫 抖音大数据 情感分析 NLP 自然语言处理 Hive 机器学习 深度学习
  • Linux 学习 awk 和sed 命令使用
  • 双端搭建个人博客
  • PHP 面向对象编程
  • 应急响应(1)-同事电脑
  • class 023 随机快速排序
  • 如何理解矩阵的复数特征值和特征向量?
  • 怎么查看网站是否被谷歌收录,查看网站是否被搜索引擎收录5个方法与步骤
  • Java工具--stream流
  • 什么是 JWT?它是如何工作的?
  • 微信小程序使用picker,数组怎么设置默认值
  • Springboot生成树工具类,可通过 id/code 编码生成 2.0版本
  • 17、CPU缓存架构详解高性能内存队列Disruptor实战
  • 算法训练营打卡Day18
  • 【leetcode】169.多数元素
  • MyBatis<foreach>标签的用法与实践
  • R语言Shiny包新手教程
  • [大象快讯]:PostgreSQL 17 重磅发布!
  • CHI trans--Home节点发起的操作
  • Rust和Go谁会更胜一筹
  • 记HttpURLConnection下载图片
  • 物联网实训室建设的必要性