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

目录

1. 字符指针

2. 数组指针

2.1 数组指针变量

2.2 数组指针变量的初始化

3.二维数组传参(本质)

4. 函数指针

4.1 函数指针变量的创建

4.2 函数指针的使用

4.3 typedef 

5. 函数指针数组

6. 转移表(函数指针数组的使用)


1. 字符指针

在指针的类型中有一种指针类型为字符指针 char*

#include<stdio.h>
int main()
{char ch = 'h';char* pc = &ch;//pc就是字符指针const char* pstr = "hello";//常量字符串//这里不是把字符串存在p中,而是把第一个字符的地址存放在p中//1,你可以把字符串相信成一个字符数组//2.当常量字符串出现在表达式中的时候,他点值是第一个字符的地址printf("%c\n", "hello"[3]);printf("%s\n", pstr);
}

 

 举例:

#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)//str1和str2是两个不同地址的字符数组。printf("str1 and str2 are same\n");elseprintf("str1 and str2 are not same\n");if (str3 == str4)//str3和str4指向的是同一个常量字符串。printf("str3 and str4 are same\n");elseprintf("str3 and str4 are not same\n");return 0;
}

 注意:内容相同的常量字符串只会保存一份。

2. 数组指针

2.1 数组指针变量

在前面的文章中,我们学了指针数组,它是一种数组,里面存的是地址(指针)。

数组指针其实跟指针数组不同,数组指针是:指针变量。

我们回忆一下指针之前的一些指针变量:

整形指针变量: int * p1; 存放的是整形变量的地址,能够指向整形数据的指针。

浮点型指针变量: float * p2; 存放浮点型变量的地址,能够指向浮点型数据的指针。

那么数组指针变量就应该是:存放的是数组的地址,能够指向数组的指针变量。

数组指针变量
int (*p)[10];
p先和*结合,说明p是⼀个指针变量变量,然后指着指向的是⼀个⼤⼩为10个整型的数组。

注意:[]的优先级要高于*号的,所以必须加上()来保证p先和*结合

2.2 数组指针变量的初始化

int arr[10] = {0};
&arr;//得到的就是数组的地址
int(*p)[10] = &arr;//p数组指针指向arr数组的指针
&arr表示整个数组的地址

 数组指针类型:

int (*p) [10] = &arr;| | || | || | p指向数组的元素个数| p是数组指针变量名p指向的数组的元素类型

3.二维数组传参(本质)

之前我们需要把一个二维数组传参给一个函数的时候,我们是这么写的

#include <stdio.h>
void test(int a[3][5], int r, int c)//这里的形参是二维数组
{int i = 0;int j = 0;for (i = 0; i < r; i++){for (j = 0; j < c; j++){printf("%d ", a[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} };test(arr, 3, 5);return 0;
}

 那还有什么其他的写法吗?

 我们可以看到二维数组可以被分为多个一维数组,可以把每个一维数组看成一个元素,那么二维数组的首元素就是第一个一维数组。根据数组名是数组⾸元素的地址这个规则,⼆维数组的数组名表示的就是第⼀⾏的地址,是⼀维数组的地址。既然是数组地址我们就要用数组指针 int (*p)来存,但是一维数组里面还有很多数,这时我们就要在数组指针后面加个数组 int(*p)[] ,来把这些数存下来。

⼆维数组传参本质上也是传递了地址,传递的是第⼀行这个⼀维数组的地址。

int main()
{int arr[3][5] = { {1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7} };test(arr, 3, 5);return 0;
}
#include <stdio.h>
void test(int (*p)[5], int r, int c)
{int i = 0;int j = 0;for (i = 0; i < r; i++){for (j = 0; j < c; j++){printf("%d ", a[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} };test(arr, 3, 5);return 0;
}

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

4. 函数指针

4.1 函数指针变量的创建

根据我们前面学的指针变量,我们大概可以推出,函数指针变量就是用来存放函数地址的,后面可以通过地址来调用函数。

函数是有地址的,且函数名就是函数的地址,我们可以通过&函数来获得函数的地址。要存地址,那就要用到指针,存函数的地址,就要用函数指针。函数指针的创建跟数组指针差不多。

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

举例:

#include <stdio.h>
int Add(int x, int y)
{return x + y;
}
int main()
{//int(*pf3)(int, int) = Add;int(*pf3)(int x, int y) = &Add;//x和y写上或者省略都是可以的printf("%p\n", pf3);return 0;
}

4.2 函数指针的使用

#include <stdio.h>
int Add(int x, int y)
{return x + y;
}
int main()
{//int(*pf3)(int, int) = Add;int(*pf3)(int x, int y) = &Add;printf("%d\n", pf3(1, 2));//pf3(1, 2)==Add(1,2)printf("%d\n", (*pf3)(1, 2));return 0;
}

 我们根据之前学的来看两个代码

(*(void (*)())0)();
void (*signal(int , void(*)(int)))(int);

4.3 typedef 

typedef 是用来给类型重名的,可以将复杂的类型,简单化。

typedef unsigned int uint;
//将unsigned int 重命名为uint

指针类型一样可以重命名。

typedef int* ptr_t;
//将 int* 重命名为 ptr_t

注意:数组指针和函数指针的类型重名有点不同

数组指针:

typedef int(*parr_t)[5]; //新的类型名必须在*的右边
//将指针类型 int(*)[5] ,重命名为 parr_t

函数指针:

typedef void(*pfun_t)(int);//新的类型名必须在*的右边
//将 void(*)(int) 类型重命名为 pf_t

5. 函数指针数组

数组是一个存放相同类型数组空间。那把函数的地址存到⼀个数组中,那这个数组就叫函数指针数组。

int (*parr1[3])();
int (*)() 类型的函数指针。

6. 转移表(函数指针数组的使用)

计算机的实现:

#include <stdio.h>
int add(int a, int b)
{return a + b;
}
int sub(int a, int b)
{return a - b;
}
int mul(int a, int b)
{return a * b;
}
int div(int a, int b)
{return a / b;
}
int main()
{int x, y;int input = 1;int ret = 0;int(*p[5])(int x, int y) = { 0, add, sub, mul, div }; //转移表--函数指针数组的存入do{printf("*************************\n");printf(" 1:add 2:sub \n");printf(" 3:mul 4:div \n");printf(" 0:exit \n");printf("*************************\n");printf("请选择:");scanf("%d", &input);if ((input <= 4 && input >= 1)){printf("输入要求的数:");scanf("%d %d", &x, &y);ret = (*p[input])(x, y);//函数指针数组的元素使用printf("ret = %d\n", ret);}else if (input == 0){printf("退出计算器\n");}else{printf("输入错误,请重新输入\n");}} while (input);return 0;
}

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

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

相关文章

sqli-labs(7)

32. 看到“前面有了\这里使用宽字节注入 当字符的大小为一个字节时为窄字节 当字符的大小为两个字节时为宽字节 英文字符的大小为一个字节&#xff0c;汉字为两个 漏洞产生的成因在sql中使用像GB2312,GBK,GB18030,BIG5,Shift_JIS这些宽字节编码而php使用utf-8编码 为了防止注…

token认证机制,基于JWT的Token认证机制实现,安全性的问题

文章目录 token认证机制几种常用的认证机制HTTP Basic AuthOAuthCookie AuthToken AuthToken Auth的优点 基于JWT的Token认证机制实现JWT的组成认证过程登录请求认证 对Token认证的五点认识JWT的JAVA实现 基于JWT的Token认证的安全问题确保验证过程的安全性如何防范XSS Attacks…

基于YOLOv5的人群计数系统设计系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介系统概述系统功能核心技术系统架构系统优势 二、功能三、系统四. 总结  总结 一项目简介 基于YOLOv5的人群计数系统设计是一个非常有趣且具有挑战性的项目…

第20章 多线程

创建线程 继承Thread 类 Thread 类时 java.lang 包中的一个类&#xff0c;从类中实例化的对象代表线程&#xff0c;程序员启动一个新线程需要建立 Thread 实例。 Thread 对象需要一个任务来执行&#xff0c;任务是指线程在启动时执行的工作&#xff0c;start() 方法启动线程&am…

java开发需要用到的软件,必备软件工具一览

java开发需要用到的软件&#xff0c;必备软件工具一览 如果你对Java编程感兴趣或已经是一名Java开发者&#xff0c;你需要一些必备的软件工具来提高你的生产力和简化开发过程。在本文中&#xff0c;我们将探讨Java开发所需的关键软件工具&#xff0c;并通过具体示例来解释它们的…

人力资源管理后台 === 上传+权限数据

目录 1.员工详情-封装员工头像组件 2.员工详情-上传图片-创建腾讯云存储桶 3.员工详情-使用cos-sdk完成上传 4. 权限管理-搭建权限页面 5.权限管理-获取数据转化树形 6.权限管理-作业 7.权限应用-权限概念 8.权限应用-员工分配角色-弹出层 9.权限应用-员工分配角色-回…

15:00面试,15:06就出来了,问的问题有点变态。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到8月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…

【计算机网络】虚拟路由冗余(VRRP)协议原理与配置

目录 1、VRRP虚拟路由器冗余协议 1.1、协议作用 1.2、名词解释 1.3、简介 1.4、工作原理 1.5、应用实例 2、 VRRP配置 2.1、配置命令 1、VRRP虚拟路由器冗余协议 1.1、协议作用 虚拟路由冗余协议(Virtual Router Redundancy Protocol&#xff0c;简称VRRP)是由IETF…

前端开发学习 (三) 列表功能

一、列表功能 1、列表功能 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv"X-UA-Compa…

【hacker送书第4期】推荐4本Java必读书籍(各送一本)

第4期图书推荐 Java从入门到精通&#xff08;第7版&#xff09;内容简介参与方式 项目驱动零基础学Java内容简介参与方式 深入理解Java高并发编程内容简介参与方式 Java编程讲义内容简介参与方式 Java从入门到精通&#xff08;第7版&#xff09; 内容简介 《Java从入门到精通&…

Leetcode—160.相交链表【简单】

2023每日刷题&#xff08;四十一&#xff09; Leetcode—160.相交链表 算法思想 两个链表的节点之和是相等的 如果两个链表相交&#xff0c;那么相交点之后的长度是相同的 我们需要做的事情是&#xff0c;让两个链表从同距离末尾同等距离的位置开始遍历。这个位置只能是较短…

python操作Mysql学习

文章目录 版权声明准备&#xff1a;MYSQL数据库数据库简介数据库分类数据库管理系统SQL语句关系型数据库中核心元素MySQL环境搭建Mysql数据类型数据完整性和约束MYSql基本操作登录和退出数据库命令数据库基本操作命令数据表基本操作命令数据表结构修改命令表数据操作命令Mysql查…

【Python3】【力扣题】349. 两个数组的交集

【力扣题】题目描述&#xff1a; 【Python3】代码&#xff1a; 1、解题思路&#xff1a;集合的交集。两个数组都转为集合&#xff0c;获取集合的交集。 知识点&#xff1a;set(...)&#xff1a;转为集合&#xff0c;集合的元素不重复。 集合1.intersection(集合2)&#xff1a…

ZYNQ_project:lcd_pic_400x400

在lcd液晶屏上显示400x400像素的图片&#xff0c; 像素信息通过电脑的串口调试助手&#xff0c;发送给fpga&#xff0c;存储在例化的双端口ram中&#xff0c; 在要显示图像区域&#xff0c;读取ram中的像素信息。 模块框图&#xff1a; 时序图&#xff1a; 代码&#xff1a;…

Windows下搭建Tomcat HTTP服务,发布公网远程访问

文章目录 前言1.本地Tomcat网页搭建1.1 Tomcat安装1.2 配置环境变量1.3 环境配置1.4 Tomcat运行测试1.5 Cpolar安装和注册 2.本地网页发布2.1.Cpolar云端设置2.2 Cpolar本地设置 3.公网访问测试4.结语 前言 Tomcat作为一个轻量级的服务器&#xff0c;不仅名字很有趣&#xff0…

C语言——数组转换

将的两行三列数组转换为三行两列的数组 #define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h> int main() {int a[2][3]{{1,2,3},{4,5,6}};int b[3][2],i,j;for ( i 0; i <1; i){for ( j 0; j <2; j){printf("%5d",a[i][j]);b[j][i]a[i][j];}printf(&…

LTD253次升级 | 官网“活动“增报名 • 名片展示个人简介 • 合伙人设置个性邀请码

1、活动类型支持报名&#xff1b; 2、产品详情页支持房产类型产品的地图显示&#xff1b; 3、官微名片独立版支持个人简介&#xff1b; 4、多语言系统支持挪威语&#xff1b; 5、极速官微首页提速、合伙人页面优化&#xff1b; 6、 已知问题优化与修复&#xff1b; 01网站编辑器…

Mysql8.1.0 安装问题-缺少visual studio 2019x64组件

缺少visual studio x64组件的问题 使用Mysql8以上的安装包mysql-8.1.0-winx64.msi进行安装&#xff0c; 提示缺少visual studio 2019 x64可再发行组件 在微软官网下载vc可再发行程序包 Microsoft Visual C 可再发行程序包最新支持的下载 在Visual Studio 2015、2017、2019 和…

Arch Linux 安装 dwm 窗口管理器

窗口管理器是管理桌面上各种窗口的组件&#xff0c;主要功能有&#xff1a;窗口堆叠方式&#xff0c;窗口移动规则等。大多数人接触到的是堆叠式窗口管理器&#xff0c;一个窗口可以叠放在其他窗口之上&#xff0c;调整窗口的主要方式是鼠标。而dwm&#xff08;Dynamic Window …

【C++】异常处理 ① ( 异常概念引入 | 抛出异常语法 | 捕获异常语法 | 异常捕获流程 | 异常处理代码示例 )

文章目录 一、异常处理1、异常概念引入2、抛出异常语法3、捕获异常语法4、异常捕获流程 二、异常处理代码示例1、错误代码示例 - 抛出异常 / 不捕获异常2、正确代码示例 - 抛出异常 / 捕获异常3、正确代码示例 - 抛出异常 / 捕获异常不处理继续抛出异常 一、异常处理 1、异常概…