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

文章目录

      • 前言
    • 一、字符指针变量
    • 二、数组指针变量
      • 2.1 数组指针变量是什么
      • 2.2 数组指针变量怎么初始化
        • 2.2.1 静态初始化
        • 2.2.2 动态初始化
    • 三、二维数组传参的本质
    • 四、函数指针变量
      • 4.1 函数指针变量的创建
      • 4.2 函数指针变量的使用
      • 4.3 typedef关键字
      • 4.4拓展
    • 五、函数指针数组
    • 六、转移表
    • 总结

前言

在C语言中,指针一直是一个让初学者头疼的话题。它看似复杂难懂,但其实只要掌握了正确的方法,就能轻松驾驭。在之前的两篇博客中,我们已经对指针有了初步的认识。今天,我们将继续深入探索指针的更多奥秘。
在这里插入图片描述

一、字符指针变量

字符指针变量是用来存储字符数组(字符串)首地址的变量。它的声明方式是char *指针变量名;。例如:

char *str = "Hello, World!";

这里,str就是一个字符指针变量,它指向了字符串"Hello, World!"的首地址。通过字符指针变量,我们可以对字符串进行操作。比如,printf("%s", str);就可以输出整个字符串。

二、数组指针变量

2.1 数组指针变量是什么

数组指针变量是用来存储数组首地址的变量。它的声明方式是类型 (*指针变量名)[数组长度];。例如:

int arr[5] = {1, 2, 3, 4, 5};
int (*p)[5] = &arr;

这里,p就是一个指向包含5个整数的数组的指针变量。它指向了数组arr的首地址。通过数组指针变量,我们可以访问数组中的元素。比如,printf("%d", (*p)[2]);就可以输出数组中的第三个元素3。

数组指针变量与普通指针变量的区别在于,数组指针变量指向的是一个数组,而普通指针变量指向的是一个单一的变量或一个字符串。数组指针变量在内存中占用的空间比普通指针变量大,因为它需要存储整个数组的地址信息。

2.2 数组指针变量怎么初始化

数组指针变量的初始化可以通过以下两种方式:

2.2.1 静态初始化

在声明数组指针变量时,直接将其初始化为一个已知数组的地址。例如:

int arr[5] = {1, 2, 3, 4, 5};
int (*p)[5] = &arr;

这里,p被初始化为指向数组arr的首地址。

2.2.2 动态初始化

在程序运行过程中,通过malloc函数动态分配一个数组,并将数组指针变量初始化为分配的内存地址。例如:

int (*p)[5] = (int (*)[5])malloc(sizeof(int) * 5);
if (p == NULL) {printf("Memory allocation failed\n");exit(1);
}
for (int i = 0; i < 5; i++) {(*p)[i] = i + 1;
}

这里,p被动态分配了一个包含5个整数的数组,并通过循环初始化了数组中的元素。

三、二维数组传参的本质

在C语言中,当我们把二维数组作为参数传递给函数时,实际上传递的是数组首地址。函数接收的是一个指向一维数组的指针。例如:

void printArray(int arr[][3], int rows) {for (int i = 0; i < rows; i++) {for (int j = 0; j < 3; j++) {printf("%d ", arr[i][j]);}printf("\n");}
}

这里,arr是一个指向包含3个整数的一维数组的指针。通过这种方式,我们可以在函数中操作二维数组。

四、函数指针变量

4.1 函数指针变量的创建

函数指针变量是用来存储函数地址的变量。它的声明方式是返回类型 (*指针变量名)(参数列表);。例如:

int add(int a, int b) {return a + b;
}int (*funcPtr)(int, int) = add;

这里,funcPtr就是一个指向add函数的指针变量。通过函数指针变量,我们可以调用函数。比如,printf("%d", (*funcPtr)(1, 2));就可以输出3。

4.2 函数指针变量的使用

函数指针变量的使用非常灵活,可以用于多种场景。例如,我们可以根据不同的条件调用不同的函数:

int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }int (*funcPtr)(int, int);int choice;
printf("Enter your choice (1 for add, 2 for sub): ");
scanf("%d", &choice);if (choice == 1) {funcPtr = add;
} else if (choice == 2) {funcPtr = sub;
} else {printf("Invalid choice\n");return 1;
}printf("%d\n", (*funcPtr)(5, 3));

这里,根据用户输入的选择,程序会调用addsub函数。

4.3 typedef关键字

typedef关键字可以用来为数据类型定义一个别名,包括函数指针类型。例如:

typedef int (*FuncPtr)(int, int);FuncPtr funcPtr = add;

这里,FuncPtrint (*funcPtr)(int, int)的别名。通过typedef,我们可以简化函数指针的声明,使代码更加清晰易读。

4.4拓展

两段来自《C陷阱和缺陷》有趣的代码

五、函数指针数组

函数指针数组是一个数组,其元素都是函数指针。它的声明方式是返回类型 (*指针数组名[数组长度])(参数列表);。例如:

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 (*funcPtrArr[4])(int, int) = {add, sub, mul, div};

这里,funcPtrArr就是一个包含4个函数指针的数组。通过函数指针数组,我们可以根据不同的条件调用不同的函数。比如:

for (int i = 0; i < 4; i++) {printf("%d ", (*funcPtrArr[i])(4, 2));
}

输出结果为6 2 8 2。

六、转移表

转移表是一种利用函数指针数组实现的控制结构。它根据不同的输入条件,选择执行不同的函数。例如,在一个简单的菜单系统中,我们可以使用转移表来实现不同的功能选项:

void option1() { printf("Option 1\n"); }
void option2() { printf("Option 2\n"); }
void option3() { printf("Option 3\n"); }void (*transferTable[3])() = {option1, option2, option3};int choice;
printf("Enter your choice (1-3): ");
scanf("%d", &choice);if (choice >= 1 && choice <= 3) {transferTable[choice - 1]();
} else {printf("Invalid choice\n");
}

这里,根据用户输入的选择,程序会调用对应的函数。

总结

通过本篇博客的学习,我们深入理解了字符指针变量、数组指针变量、二维数组传参的本质、函数指针变量、函数指针数组以及转移表等指针的高级应用。指针是C语言中非常强大的工具,它能让我们的程序更加灵活和高效。希望读者能够通过不断地实践和思考,真正掌握指针的精髓。

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

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

相关文章

Linux之 权限提升(Linux Privilege Escalation)

Linux 之权限提升 系统信息 1.获取操作系统信息 2.检查PATH&#xff0c;是否有任何可写的文件夹&#xff1f; 3.检查环境变量&#xff0c;有任何敏感细节吗&#xff1f; 4.使用脚本&#xff08;DirtyCow&#xff1f;&#xff09;搜索内核漏洞 5.检查sudo 版本是否存在漏洞…

【leetcode hot 100 215】数组中的第K个最大元素

解法一&#xff1a;维护最大最小值 -> 堆 -> k个元素的最小值堆 class Solution {public int findKthLargest(int[] nums, int k) {// 维护最大最小值 -> 堆 -> k个元素的最小值堆PriorityQueue<Integer> heap new PriorityQueue<>((n1, n2) -> n…

csp信奥赛C++常用的数学函数详解

csp信奥赛C常用的数学函数详解 在信息学奥林匹克竞赛&#xff08;信奥赛&#xff09;中&#xff0c;C 的 <cmath> 头文件提供了丰富的数学函数&#xff0c;用于高效处理数学运算。以下是常用系统数学函数的详细讲解及汇总表格。 绝对值函数 int abs(int x)&#xff1a;返…

Java IntelliJ IDEA 中配置多个 JDK 版本

目录 一、添加多个 JDK 版本1. 下载并安装多个 JDK 版本2. 配置 JDK 在 IntelliJ IDEA 中 二、在项目中切换 JDK 版本1. 设置项目使用的 JDK 版本2. 设置模块使用的 JDK 版本 三、在运行配置中指定 JDK 版本四、总结 在实际开发中&#xff0c;我们常常需要在同一个项目中使用不…

ChatDBA VS DeepSeek:快速诊断 OceanBase 集群新租户数据同步异常

社区王牌专栏《一问一实验&#xff1a;AI 版》改版以来已发布多期&#xff08;51-60&#xff09;&#xff0c;展现了 ChatDBA 在多种场景下解决问题的效果。 下面让我们正式进入《一问一实验&#xff1a;AI 版》第 62 期&#xff0c;看看 ChatDBA 最新效果以及与热门大模型 De…

Java条码与二维码生成技术详解

一、技术选型分析 1.1 条码生成方案 Barbecue是最成熟的Java条码库&#xff0c;支持&#xff1a; Code 128EAN-13/UPC-AUSPS Inteligent Mail等12种工业标准格式 1.2 二维码方案对比 库名称维护状态复杂度功能扩展性ZXing★★★★☆较高强QRGen★★★☆☆简单一般BoofCV★…

air780eq 阿里云

硬件&#xff1a;APM32F030C8 Air 780eq 参考文档&#xff1a; 合宙780E-4G模块通过AT指令连接到阿里云平台&#xff0c;实现信息的收发_air780e上传阿里云属性值at命令-CSDN博客 阿里云 - atair780eq - 合宙文档中心 4G模块接入阿里云-实现数据上传和命令下发_4g模块上传…

oracle数据库(数据库启动关闭/sqlplus登录及基本操作/设置字符集/distinct去重)

目录 1. Oracle数据库启动 2. Oracle数据库关闭 3. sqlplus登录Oracle数据库 3.1 使用sqlplus登录Oracle数据库 3.2 使用sqlplus登录Oracle数据库 3.3 远程登录 3.4 解锁用户 3.5 修改用户密码 3.6 查看当前语言环境 4. sqlplus基本操作 4.1 显示当前用户 4.2 查看当前用户…

Java 大视界 -- Java 大数据在智能金融区块链跨境支付与结算中的应用(154)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

大模型词表注入

大模型词表注入&#xff08;Vocabulary Injection&#xff09; 大模型词表注入&#xff08;Vocabulary Injection&#xff09;是指在预训练语言模型&#xff08;如GPT、LLAMA等&#xff09;的基础上&#xff0c;动态扩展其词表&#xff08;Vocabulary&#xff09;的技术&#…

在Cesium中使用ThreeJs材质(不是场景融合哦)

在Cesium中使用ThreeJs材质(不是场景融合哦&#xff09;_哔哩哔哩_bilibili

初教六双机一飞冲天动作要领

初教六双机一飞冲天动作要领 初教六双机“一飞冲天”是典型的垂直爬升特技动作&#xff0c;要求双机以近乎垂直的姿态同步高速爬升&#xff0c;展现飞机的动力性能与编队协同能力。以下是该动作的详细技术解析与执行要点&#xff1a; 一、动作定义与特点 基本形态 双机以相同速…

给Web开发者的HarmonyOS指南02-布局样式

给Web开发者的HarmonyOS指南02-布局样式 本系列教程适合鸿蒙 HarmonyOS 初学者&#xff0c;为那些熟悉用 HTML 与 CSS 语法的 Web 前端开发者准备的。 本系列教程会将 HTML/CSS 代码片段替换为等价的 HarmonyOS/ArkUI 代码。 布局基础对比 在Web开发中&#xff0c;我们使用CS…

京东软件测试岗位经典面试题(附答案)

1、黑盒测试的测试用例常见设计方法都有哪些&#xff1f;请分别以具体的例子来说明这些方法在测试用例设计工作中的应用。 1&#xff09;等价类划分&#xff1a;等价类是指某个输入域的子集合.在该子集合中&#xff0c;各个输入数据对于揭露程序中的错误都是等效的.并合理地假…

3.26[a]paracompute homework

5555 负载不平衡指多个线程的计算量差异显著&#xff0c;导致部分线程空转或等待&#xff0c;降低并行效率。其核心矛盾在于任务划分的静态性与计算动态性不匹配&#xff0c;尤其在处理不规则数据或动态任务时尤为突出。以稀疏矩阵的向量乘法为例&#xff0c;假设其非零元素分…

网站安全专栏-------浅谈CC攻击和DDoS攻击的区别

CC攻击和DDoS攻击都是网络攻击的类型&#xff0c;但它们在攻击方式、目标和效果上有所不同。以下是它们之间的一些主要区别&#xff1a; ### 1. 定义 - **DDoS攻击&#xff08;分布式拒绝服务攻击&#xff09;**&#xff1a; DDoS攻击是指攻击者通过大量的分布式计算机&#x…

帕金森患者的生活重塑:从 “嘴” 开启康复之旅

当提到帕金森病&#xff0c;许多人会联想到震颤、僵硬和行动迟缓等症状。这种神经系统退行性疾病&#xff0c;给患者的生活带来了巨大的挑战。然而&#xff0c;你可知道&#xff0c;帕金森患者恢复正常生活&#xff0c;可以从 “嘴” 开始管理&#xff1f; 帕金森病在全球影响着…

Android14 Settings应用添加有线网开关条目实现

Android14 Settings应用添加有线网开关条目 文章目录 Android14 Settings应用添加有线网开关条目一、前言二、适配修改1、network_provider_settings.xml2、NetworkProviderSettings.java3、TurnOnOffEthernetNetworkController.java4、去除有线网提示条目。5、效果UI&#xff…

Axure RP设计软件中的各种函数:包括数字、数学、字符串、时间及中继器函数,详细解释了各函数的用途、参数及其应用场景。

文章目录 引言函数分类数字函数数学函数字符串函数时间函数函数中继器函数引言 在axure交互设计时,函数可以用在条件公式和需要赋值的地方,其基本语法是用双方括号包含,变量值和函数用英文句号连接。 在交互事件编辑器中通过fx按钮插入函数表达式,例如设置文本内容为: …

c#难点整理3

1.静态类的说明 a.静态类里不能定义实例方法&#xff0c;实例属性&#xff0c;所以说非静态类是无法继承静态类的。父类无法拥有实例化的方法和属性&#xff0c;子类可以&#xff0c;这从逻辑上是矛盾的&#xff0c;不符合继承的逻辑。 b.那么静态类与静态类之间能否继承能呢…