指针 (5)

目录

1. 字符指针变量

2. 数组指针变量

3. ⼆维数组传参的本质

 4. 函数指针变量

5.typedef 关键字

6 函数指针数组

7.转移表

计算器的⼀般实现


1. 字符指针变量

在指针的类型中我们知道有⼀种指针类型为字符指针 char*

#include <stdio.h>
int main()
{char* ch = "asdfff ";//这个表达式就是字符指针表达式//这里的字符串是常量字符串,将a的地址赋值给chreturn 0;
}

常量字符串是不能被修改的 , 使用% s 打印字符串时候只需要首字符的地址即可

 下面大家来看这个代码:可以先思考一下这个代码的运行结果是什么?

我们发现代码中的字符串不都是一样吗? 那一定就是都相同了。可结果是这样吗?

#include <stdio.h>
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;
}

 答案并不是:这是为什么呢?

 

这里因为str 1和str2 都是数组变量 ,当然虽然他们存的字符都相同,但是他们的地址不同,所以就有了str 1 不等与str2,数组是可以被修改的 。

那么str3 和ste4 为什么又相等呢?由代码中我们可以看到 str 3和str4 前面都有加const 来修饰变量,当const 修饰字符串就成为了常变量字符串,此时这里的常量字符串是不可被修改的,所以str3 和str 4 的地址是同一个地址。

2. 数组指针变量

指向数组的指针,存放数组的地址 

int main()
{
    int arr[5] = { 1,2,3,4,5 };
    int (*p) [5] = &arr;//这里的p就是数组指针,p中存放的是数组的地址

    return 0;
}

 解释:p先和*结合,说明p是⼀个指针变量,然后指针指向的是⼀个⼤⼩为10个整型的数组。所以p是 ⼀个指针,指向⼀个数组,叫 数组指针。 这⾥要注意:[]的优先级要⾼于*号的,所以必须加上()来保证p先和*结合。

3. ⼆维数组传参的本质

有了数组指针的理解,我们就能够讲⼀下⼆维数组传参的本质了。

过去我们有⼀个⼆维数组的需要传参给⼀个函数的时候,我们是这样写的:

void  Print(int arr[3][5], int r, int c)
{int i = 0;for (i = 0; i < r; i++){int j = 0;for (j = 0; j < c; 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);return 0;

⾸先我们再次理解⼀下⼆维数组,⼆维数组其实可以看做是每个元素是⼀维数组的数组,也就是⼆维 数组的每个元素是⼀个⼀维数组。那么⼆维数组的⾸元素就是第⼀⾏,是个⼀维数组。

然而第一行就是二位数组的首地址。一维数组的首地址就是一个元素

 那就意味着⼆维数组传参本质上也是传递了地址,传递的是第⼀⾏就是这个⼀维数组的地址。

 代码优化:

void  Print( int ( *p)[5], int r, int c)//这里写成指针的形式
{int i = 0;for (i = 0; i < r; i++){int j = 0;for (j = 0; j < c; j++){printf(" %d ",*(*(p+i)+j));// *(p+i)等价于  *p[i]就是找到一行的第一个元素的地址   +j是因为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);return 0;
}

 可以结合上面的图来理解:

 画的有些潦草,不过大概就是这么个意思

 总结:⼆维数组传参,形参的部分可以写成数组,也可以写成指针形式

 4. 函数指针变量

那要把函数的地址存到⼀个数组中,那这个数组就叫函数指针数组,那函数指针的数组如何定义呢

void  Add(int x, int y)
{

    return x + y;
 }
int main()
{
    int arr = 10;
    int (*pa)(int, int) = &Add;//pa就是函数指针

int ret = (*pa)(4, 5);
printf("%d ", ret);
    return 0;
}

函数指针类型解析

int (*pf3) (int x, int y)| | ------------ | | || | pf3指向函数的参数类型和个数的交代| 函数指针变量名pf3指向函数的返回类型
int (*) (int x, int y)

5.typedef 关键字

 typedef 是⽤来类型重命名的,可以将复杂的类型,简单化

 ⽐如,你觉得 unsigned int 写起来不⽅便,如果能写成 uint 就⽅便多了,那么我们可以使⽤

typedef unsigned int uint;//将ungsigned int 简化为uint 名字自己来写
int main()
{
    unsigned int n;

    uint n2;

    return 0;
}

 类型也可以 自定义名称,与类型相同

#include <stdio.h>
typedef int(*type)[5]; //当指针类型定义时候要把名称写在*号右面
int main()
{int a = 10;int(*p)[5] = &a;type p2 = &a;//type就是指针类型return 0;
}

6 函数指针数组

数组是⼀个存放相同类型数据的存储空间,我们已经学习了指针数组,

#include <stdio.h>
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 Dvi(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) = Dvi;*///此时上面的函数指针也可以优化为下面的函数指针数组 ,来存放这些地址int (*p[4])(int, int) = { Add ,Sub,Mul,Dvi };//这里存储的类型必须相同,相同类型元素int i = 0;for (i = 0; i < 4; i++){int ret = p[i](9, 3);//p[i]是上面函数指针数组 printf("%d\n", ret);}return 0;
}

7.转移表

函数指针数组的⽤途:转移表 就是函数指针数组

计算器的⼀般实现

计算器的实行代码。

#include <stdio.h>
int   Sum(int x, int y)
{printf("请输入两个操作数\n");scanf("%d%d", &x, &y);return x + y;
}
int   Sub(int x, int y)
{printf("请输入两个操作数\n");scanf("%d%d", &x, &y);return x - y;
}
int   Mul(int x, int y)
{printf("请输入两个操作数\n");scanf("%d%d", &x, &y);return x * y;
}
int   Div(int x, int y)
{printf("请输入两个操作数\n");scanf("%d%d", &x, &y);return x / y;
}void mune()
{printf("********************\n");printf("*****1.sum 2.sub****\n");printf("*****3.mul 4.div****\n");printf("*****  0 . exit  ***\n");printf("********************\n");}
int main()
{int input = 0;int a = 0;int b = 0;int ret = 0;do {mune();printf("请选择:");scanf("%d", &input);switch (input){case 1:ret =Sum(a,b);printf("%d\n ", ret);break;case 2:ret =Sub(a, b);printf("%d\n ", ret);break;case 3:ret =Mul(a, b);printf("%d\n ", ret);break;case 4:ret =Div(a, b);printf("%d\n", ret);break;case  0:printf("退出计算器\n");break;default :printf("输入错误,请重新输入\n");break;}} while (input);return 0; }

但是如果发现你不仅仅需要这几个,老板让你增加几个字符操作,上面代码太麻烦了

可以使用函数指针数组来实现这个计算器

#include<stdio.h>int   Sum(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 mune()
{printf("********************\n");printf("*****1.sum 2.sub****\n");printf("*****3.mul 4.div****\n");printf("*****  0 . exit  ***\n");printf("********************\n");
}
int main()
{int input = 0;int a = 0;int b = 0;int ret = 0;int (*p[5])(int, int) = { 0,Sum,Sub,Mul,Div };//假设要加入>> 操作符 可以在后面添加,//指针数量增加,添加0 是为了下标元素对应do{mune();printf("请选择:");scanf("%d", &input);if ( input >=1&&input <=4){printf("请输入两个操作数\n");scanf("%d%d", &a, &b);ret = p[input](a, b);printf("%d\n", ret);}else if (input == 0){printf("退出计算器\n");}else{printf("输入错误,请重新输入\n");}} while (input);return 0;
}

上面的代码已经得到了优化

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

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

相关文章

VB.net读写NDEF标签URI智能海报WIFI蓝牙连接

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?ftt&id615391857885 Public Class Form1Dim oldpicckey(0 To 5) As Byte 卡片旧密码Dim newpicckey(0 To 5) As Byte 卡片新密码Function GetTagUID() As StringDim status As ByteDim myctrlword As …

矩阵系统源码搭建的具体步骤,支持oem,源码搭建

一、前期准备 明确需求 确定矩阵系统的具体用途&#xff0c;例如是用于社交媒体管理、电商营销还是其他领域。梳理所需的功能模块&#xff0c;如多账号管理、内容发布、数据分析等。 技术选型 选择适合的编程语言&#xff0c;如 Python、Java、Node.js 等。确定数据库类型&…

Activiti7 工作流引擎学习

目录 一. 什么是 Activiti 工作流引擎 二. Activiti 流程创建步骤 三. Activiti 数据库表含义 四. BPMN 建模语言 五. Activiti 使用步骤 六. 流程定义与流程实例 一. 什么是 Activiti 工作流引擎 Activiti 是一个开源的工作流引擎&#xff0c;用于业务流程管理&#xf…

Linux开发讲课45--- 链表

Linux内核代码中广泛使用了数据结构和算法,其中最常用的有链表、队列kfifo、红黑树、基数树和位图。 链表 Linux内核代码大量使用了链表这种数据结构。链表是在解决数组不能动态扩展这个缺陷而产生的一种数据结构。 链表所包含的元素可以动态创建并插入和删除。链表的每个元素…

【经典机器学习算法】谱聚类算法及其实现(python)

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;深度学习_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 1. 前言 2. 前…

躺平成长:微信小程序运营日记第二天

在进行属于生活的开源之后&#xff0c;自己更加感受到自己存在的渺茫&#xff0c;同时更加开始深刻领会&#xff0c;开源的重要性&#xff0c;在开源&#xff0c;开放&#xff0c;创造&#xff0c;再创新的思维模式下&#xff0c;不发布八部金刚功相关的训练视频&#xff0c;自…

每日一题|983. 最低票价|动态规划、记忆化递归

本题求解最小值&#xff0c;思路是动态规划&#xff0c;但是遇到的问题是&#xff1a;动态规划更新的顺序和步长&#xff0c;以及可能存在的递归溢出问题。 1、确定dp数组含义 dp[i]表示第i天到最后一天&#xff08;可能不在需要出行的天数里&#xff09;&#xff0c;需要花费…

Suricata:开源网络分析和威胁检测

Suricata 是一款高性能、开源网络分析和威胁检测软件&#xff0c;被大多数私人和公共组织使用&#xff0c;并被主要供应商嵌入以保护他们的资产。 Suricata 功能 Suricata 提供全面的网络安全监控 (NSM) 功能&#xff0c;包括记录 HTTP 请求、捕获和存储 TLS 证书以及从网络流…

汽车3d动画渲染选择哪个?选择最佳云渲染解决方案

面临汽车3D动画渲染挑战&#xff1f;选择正确的云渲染服务至关重要。探索最佳解决方案&#xff0c;优化渲染效率&#xff0c;快速呈现逼真动画。 汽车3d动画渲染选择哪个&#xff1f; 对于汽车3D动画渲染&#xff0c;选择哪个渲染器取决于你的项目需求、预算和期望的效果。Ble…

yolov8/9/10模型在安全帽、安全衣检测中的应用【代码+数据集+python环境+GUI系统】

yolov8910模型安全帽、安全衣检测中的应用【代码数据集python环境GUI系统】 yolov8/9/10模型在安全帽、安全衣检测中的应用【代码数据集python环境GUI系统】 背景意义 安全帽和安全衣在工业生产、建筑施工等高风险作业环境中是保护工人免受意外伤害的重要装备。然而&#xff0…

Qt 学习第十一天:QTableWidget 的使用

一、创建QTableWidget对象&#xff0c;设置大小&#xff0c;在窗口的位置 //创建tablewidgetQTableWidget *table new QTableWidget(this);table->resize(550, 300);table->move(100, 100); //移动 二、设置表头 //设置表头QStringList headerList; //定义headerList…

web开发(1)-基础

这是对b站课程的总结&#xff0c;后续可能会继续更 01 前后端分离介绍_哔哩哔哩_bilibili01 前后端分离介绍是Web应用开发-后端基础-基于Springboot框架的第1集视频&#xff0c;该合集共计29集&#xff0c;视频收藏或关注UP主&#xff0c;及时了解更多相关视频内容。https://w…

GPG error golang 1.19

1. 问题描述及原因分析 在飞腾2000的服务器&#xff0c;OS为Kylin Linux Advanced Server release V10环境下&#xff0c;docker版本为18.09.0&#xff08;docker-engine-18.09.0-101.ky10.aarch64&#xff09;&#xff0c;基于容器镜像golang:1.19编译新的容器镜像&#xff0…

【C++篇】启航——初识C++(上篇)

下篇&#xff1a;【C篇】启航——初识C&#xff08;下篇&#xff09; 目录 引言 一、C的起源和发展史 1.起源 2.C版本更新 二、C在⼯作领域中的应⽤ 三、C入门建议 1.参考文档 2.推荐书籍 四、C的第一个程序 1.C语言写法 2.C写法 五、命名空间 1.为什么要有命名空…

AI 对话工具汇总

&#x1f423;个人主页 可惜已不在 &#x1f424;这篇在这个专栏AI_可惜已不在的博客-CSDN博客 &#x1f425;有用的话就留下一个三连吧&#x1f63c; 目录 前言: 正文: 前言: 在科技飞速发展的时代&#xff0c;AI 对话正逐渐成为我们获取信息、交流思想的新方式。它以强…

若无向图G(V,E)中含7个顶点,为保证图G在任何情况下都是连通的,则需要的边数最少是多少?

这乍一看是不是可抽象&#xff08;迷糊&#xff09;了&#xff0c;butttt待我小翻译一下。 先举少一点的例子&#xff0c;假如我们有三个点&#xff0c;我给你两条边&#xff0c;那是不是不管咋连都一定一定是连通的。 那我们再进一步&#xff0c;假如四个点呢&#xff1f;我给…

RabbitMQ 界面管理说明

1.RabbitMQ界面访问端口和后端代码连接端口不一样 界面端口是15672 http://localhost:15672/ 后端端口是 5672 默认账户密码登录 guest 2.总览图 3.RabbitMq数据存储位置 4.队列 4.客户端消费者连接状态 5.队列运行状态 6.整体运行状态

在Linux中将设备驱动的地址映射到用户空间

本期主题&#xff1a; MMU的简单介绍&#xff0c;以及如何实现设备地址映射到用户空间 往期链接&#xff1a; Linux内核链表零长度数组的使用inline的作用嵌入式C基础——ARRAY_SIZE使用以及踩坑分析Linux下如何操作寄存器&#xff08;用户空间、内核空间方法讲解&#xff09;…

Redis篇(最佳实践)(持续更新迭代)

介绍一&#xff1a;键值设计 一、优雅的key结构 Redis 的 Key 虽然可以自定义&#xff0c;但最好遵循下面的几个最佳实践约定&#xff1a; 遵循基本格式&#xff1a;[业务名称]:[数据名]:[id]长度不超过 44 字节不包含特殊字符 例如&#xff1a; 我们的登录业务&#xff0…

『功能项目』宠物的攻击巨型化【80】

本章项目成果展示 我们打开上一篇79宠物的召唤跟随的项目&#xff0c; 本章要做的事情是实现在战斗中有几率触发宠物巨型化攻击将怪物击飞的效果 首先在主角预制体中增加隐藏的宠物巨型化 制作巨型化宠物的攻击效果 将该动画控制器放置在隐藏的巨型化宠物的动画控制器上 首先查…