【C语言】(15)指针进阶

1. 指针与const

在C语言中,const关键字和指针一起使用时,可以创建对常量的引用,或者创建指向常量的指针。这对于保护重要数据不被意外修改以及提高程序的可读性和运行时的安全性非常有用。

1.1 const的基本用法

const关键字用于声明一个变量为常量,这意味着一旦被初始化之后,它的值就不能被修改。

const int a = 10; // a是一个常量,不能被修改
// a = 20; // 错误:尝试修改常量的值

1.2 指针与const结合的用法

1.2.1 指向常量的指针

const关键字出现在星号*的左边时,它意味着指针所指向的数据是不可修改的,但指针本身可以修改。

const int *ptr; // 指向整型常量的指针
int const *ptr; // 同上,与上一行等价
int value = 5;
ptr = &value; // 合法操作
//*ptr = 10; // 非法操作:不能通过ptr修改value的值

1.2.2 常量指针

const关键字出现在星号*的右边时,它意味着指针本身是常量,即不能指向其他地址,但通过指针指向的数据可以被修改。

int *const ptr; // ptr是一个常量指针
int value1 = 5, value2 = 10;
ptr = &value1; // 非法操作:ptr不能指向其他地址
*ptr = 20; // 合法操作:可以通过ptr修改value1的值

1.2.3 指向常量的常量指针

const关键字同时出现在星号*的左边和右边时,既指针所指向的数据也是常量,指针本身也是常量。

const int *const ptr = &value; // ptr是一个指向整型常量的常量指针
//ptr = &value2; // 非法操作:ptr不能指向其他地址
//*ptr = 10; // 非法操作:不能通过ptr修改value的值

总结

  • 使用const可以定义不可变的常量。
  • const int *ptr表示ptr可以变,但ptr指向的值不能变。
  • int *const ptr表示ptr指向的值可以变,但ptr本身不能变。
  • const int *const ptr表示ptrptr指向的值都不能变。
  • 适当使用const可以增加程序的安全性和可读性。

2. 指针数组

数组指针是指向数组的指针。理解数组指针对于高效地处理数组和执行复杂的内存操作非常重要。

2.1 数组与指针的基本关系

数组名本身就是一个指向数组第一个元素的指针。

int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr; // 等同于 int *ptr = &arr[0];

通过指针,我们可以访问和修改数组中的元素。

2.2 数组指针的声明

数组指针通常指向一个整个数组,而不仅仅是数组的第一个元素。声明数组指针的语法如下:

type (*arrayPtr)[size];

这里,type 是数组元素的类型,size 是数组的大小,arrayPtr 是指向数组的指针变量名。

示例:声明一个指向整型数组的指针

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

2.3 通过数组指针访问数组元素

使用数组指针访问数组元素时,需要使用解引用操作符(*)和下标。

// 假设 ptrToArray 指向一个包含 5 个整数的数组
for (int i = 0; i < 5; i++) {printf("%d ", (*ptrToArray)[i]);
}

在这个例子中,(*ptrToArray) 解引用数组指针,访问整个数组,然后我们使用下标[i]访问数组的具体元素。

2.4 数组指针与多维数组

数组指针对于处理多维数组尤其有用,因为它可以简化对多维数组的访问和操作。

示例:声明一个指向二维整型数组的指针

int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
int (*ptrTo2DArray)[3] = arr; // 或者 &arr[0]

使用数组指针访问二维数组元素:

for (int i = 0; i < 2; i++) {for (int j = 0; j < 3; j++) {printf("%d ", ptrTo2DArray[i][j]);}printf("\n");
}

在这个例子中,我们没有使用(*ptrTo2DArray)来解引用指针,因为当使用数组指针作为多维数组的指针时,可以直接使用下标来访问元素。

总结

  • 数组指针是指向整个数组的指针。
  • 声明数组指针时,需要指定数组的类型和大小。
  • 使用数组指针可以方便地访问和操作数组元素,特别是在处理多维数组时。
  • 数组指针在高级编程、动态内存分配以及函数参数传递中非常有用。

3. 函数指针

3.1 函数指针的声明

函数指针的声明包含了函数的返回类型、指针名称以及函数的参数列表。基本语法如下:

返回类型 (*指针变量名)(参数类型列表);

例如,声明一个指向返回类型为 int,参数为两个 int 类型的函数的指针,可以这样写:

int (*funcPtr)(int, int);

3.2 使用函数指针

一旦声明了函数指针,就可以将它指向具有相应签名的任何函数。例如,如果有一个这样的函数:

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

可以这样将函数 add 赋值给之前声明的 funcPtr

funcPtr = add;

3.3 通过函数指针调用函数

通过函数指针调用函数的语法与直接调用函数类似,只不过函数名被替换为函数指针变量名。例如,使用 funcPtr 调用 add 函数:

int result = funcPtr(3, 5); // 调用add函数,参数为3和5

3.4 函数指针作为参数

函数指针最强大的用途之一是作为其他函数的参数。这允许你在运行时动态地改变函数的行为。例如:

void printOperationResult(int (*operation)(int, int), int a, int b) {int result = operation(a, b);printf("Result: %d\n", result);
}

这个 printOperationResult 函数接受一个函数指针 operation 作为参数,并用 ab 作为参数调用它,然后打印结果。

3.5 返回函数指针的函数

函数也可以返回函数指针。声明这样的函数时,需要在返回类型前加上 (*) 和参数列表。例如:

int (*getOperation(char op))(int, int) {switch(op) {case '+':return add;// 可以添加更多的case来返回不同的函数指针default:return NULL;}
}

这个 getOperation 函数根据传入的操作符返回相应的函数指针。

函数指针数组是C语言中的一个高级特性,它允许你在一个数组中存储多个指向函数的指针。这种技术非常适合于实现函数表、回调函数列表或者状态机等。下面是一个关于如何使用函数指针数组的详细教程。

3.6 函数指针数组

3.6.1 函数指针数组的声明

函数指针数组的声明类似于普通数组的声明,但数组的元素类型是函数指针。基本语法如下:

返回类型 (*数组名[])(参数类型列表);

例如,声明一个指向返回类型为 int,参数为两个 int 类型的函数的函数指针数组:

int (*operationArray[])(int, int);

3.6.2 初始化函数指针数组

在声明函数指针数组的同时,你可以初始化它,将数组中的每个元素指向具体的函数。例如:

int add(int a, int b) {return a + b;
}int subtract(int a, int b) {return a - b;
}// 初始化函数指针数组
int (*operationArray[])(int, int) = {add, subtract};

3.6.3 通过索引调用数组中的函数

你可以通过索引来访问函数指针数组中的元素,并通过这些函数指针调用函数。例如:

int result1 = operationArray[0](5, 3); // 调用add函数
int result2 = operationArray[1](5, 3); // 调用subtract函数

3.6.4. 遍历函数指针数组

你也可以遍历函数指针数组,对数组中的每个函数指针进行操作。例如:

int operations(int a, int b, int (*opsArray[])(int, int), int size) {for (int i = 0; i < size; i++) {printf("Operation %d result: %d\n", i, opsArray[i](a, b));}
}int main() {int (*operationArray[])(int, int) = {add, subtract};int size = sizeof(operationArray) / sizeof(operationArray[0]);operations(10, 5, operationArray, size);return 0;
}

3.6.5 函数指针数组作为函数参数

函数指针数组可以作为参数传递给其他函数,这在实现插件系统、事件处理系统时特别有用。传递函数指针数组作为参数的方法与传递普通数组类似。

3.7 回调函数

回调函数是一种在软件开发中常用的技术,它允许一个函数的行为被另一个函数在特定事件或条件发生时动态指定或“回调”。在C语言中,回调函数通常通过函数指针来实现。这种机制允许编写更通用、更灵活的代码,特别是在事件处理、异步编程和接口设计中非常有用。

3.7.1 定义回调函数

定义一个回调函数就是定义一个普通的函数,然后将这个函数的地址(通过函数名)传递给另一个函数,后者在适当的时刻调用这个回调函数。

例如,我们定义一个回调函数和一个接受这个回调函数作为参数的函数:

// 回调函数
void myCallback(int a) {printf("Callback called with %d\n", a);
}// 接受回调函数作为参数的函数
void performActionWithCallback(void (*callbackFunc)(int), int value) {// 在适当的时候调用回调函数callbackFunc(value);
}
3.7.2 使用回调函数

使用回调函数时,只需要将回调函数作为参数传递给另一个函数即可。例如:

int main() {// 调用performActionWithCallback,传递myCallback作为回调函数performActionWithCallback(myCallback, 5);return 0;
}

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

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

相关文章

风控安全产品系统设计

风控业务架构 我把风控业务架构的分层分为6层,分别是组件层、业务层、决策层、能力层、计算层、可视层。 以下基建为基础安全产品的简称。 组件层 组件层的职责是:数据收集与行为反制。 从接口、设备、行为三个维度进行数据收集,接收决策层的指令进行行为反制。为了保证…

Go语言深度解析:探索 crypto/md5 标准库的强大功能

Go语言深度解析&#xff1a;探索 crypto/md5 标准库的强大功能 引言Go语言和MD5的基础知识MD5算法简介Go语言概述Go中的MD5实现 crypto/md5 库的使用方法基本用法处理大型数据安全注意事项 实际案例分析示例1&#xff1a;文件的MD5校验示例2&#xff1a;网络数据的MD5哈希示例3…

【C++】运算符重载详解

&#x1f497;个人主页&#x1f497; ⭐个人专栏——C学习⭐ &#x1f4ab;点击关注&#x1f929;一起学习C语言&#x1f4af;&#x1f4ab; 目录 导读 1. 为什么需要运算符重载 2. 运算符重载概念 3. 运算符重载示例 3.1 运算符重载 3.2 >或<运算符 4. 运算符重…

面试数据结构与算法总结分类+leetcode目录【基础版】

&#x1f9e1;&#x1f9e1;&#x1f9e1;算法题目总结&#xff1a; 这里为大家总结数据结构与算法的题库目录&#xff0c;如果已经解释过的题目会标注链接更新&#xff0c;方便查看。 数据结构概览 Array & String 大家对这两类肯定比较清楚的&#xff0c;同时这也是面试…

SVDiff: Compact Parameter Space for Diffusion Fine-Tuning——【论文笔记】

本文发表于ICCV 2023 论文地址&#xff1a;ICCV 2023 Open Access Repository (thecvf.com) 官方代码&#xff1a;mkshing/svdiff-pytorch: Implementation of "SVDiff: Compact Parameter Space for Diffusion Fine-Tuning" (github.com) 一、Introduction 最近几…

Vue3中使用tsx文件

1. 安装 npm install vitejs/plugin-vue-jsx -D2. 配置vite.config.ts import { defineConfig } from vite import vue from vitejs/plugin-vue import path from path import vueJsx from "vitejs/plugin-vue-jsx"// https://vitejs.dev/config/ export default d…

11:Servlet中初始化参数的获取与应用-Java Web

目录 11.1 Servlet初始化参数简介11.2 如何在Servlet中获取初始化参数11.3 基于注解的初始化参数&#xff08;Servlet 3.0&#xff09;11.4 区别总结11.5 应用场景总结 在构建Java Web应用程序时&#xff0c;Servlet是核心组件之一&#xff0c;它负责处理HTTP请求并生成响应。而…

五大架构风格之四-虚拟机架构风格

虚拟机架构风格&#xff1a; 虚拟机架构风格是一种软件架构&#xff0c;它通过模拟完整的计算机系统&#xff08;包括硬件&#xff09;来运行程序。这种风格的核心是虚拟机监控器。如最出名的虚拟机VM&#xff0c;在使用虚拟机架构&#xff0c;一个或多个虚拟机可以在单一物理主…

标题:揭秘Java中Thread.sleep(0)的微妙用法与实战解析

引言 在深入研究Java多线程编程时&#xff0c;我们经常会遇到一个看似不起眼但颇具实用价值的方法——Thread.sleep(0)。乍一看&#xff0c;让一个线程“休眠”零毫秒似乎是一个没有意义的操作&#xff0c;但实际上&#xff0c;它在并发编程场景中扮演着重要的角色。本文将详细…

java反射详解

动态代理 什么是动态代理&#xff1f; 特点&#xff1a;无侵入式的给代码增加额外的功能 对象有什么方法想要被代理&#xff0c;代理就一定要有对应的方法 对象和代理需要实现同一个接口&#xff0c;接口中就是被代理的方法 调用者通过代理&#xff0c;调用代理中的方法&#x…

高级FPGA开发之基础协议PCIe

基础协议之PCIe部分 一、TLP包的包头 在PCIe的系统中&#xff0c;tlp包的包头的结构有许多部分是相似的&#xff0c;通过掌握这些常规的包头&#xff0c;能帮助理解在PCIe总线上各个设备之间如何进行数据的收发。 通用的字段 通用字段作用Fmt决定了包头是3DW还是3DW&#xff…

二级C语言笔试2

(总分100,考试时间90分钟) 一、选择题 下列各题A)、B)、C)、D)四个选项中&#xff0c;只有一个选项是正确的。 1. 下列叙述中正确的是( )。 A) 算法的效率只与问题的规模有关&#xff0c;而与数据的存储结构无关 B) 算法的时间复杂度是指执行算法所需要的计算工作量 …

2V2无人机红蓝对抗仿真

两架红方和蓝方无人机分别从不同位置起飞&#xff0c;蓝方无人机跟踪及击毁红方无人机 2020a可正常运行 2V2无人机红蓝对抗仿真资源-CSDN文库

Android电动汽车充电服务vue+uniAPP微信小程序

本系统利用SSM和Uniapp技术进行开发电动汽车充电服务系统是未来的趋势。该系统使用的编程语言是Java&#xff0c;数据库采用的是MySQL数据库&#xff0c;基本完成了系统设定的目标&#xff0c;建立起了一个较为完整的系统。建立的电动汽车充电服务系统用户使用浏览器就可以对其…

Python爬虫urllib详解

前言 学习爬虫&#xff0c;最初的操作便是模拟浏览器向服务器发出请求&#xff0c;那么我们需要从哪个地方做起呢&#xff1f;请求需要我们自己来构造吗&#xff1f;需要关心请求这个数据结构的实现吗&#xff1f;需要了解 HTTP、TCP、IP 层的网络传输通信吗&#xff1f;需要知…

mongodb数据库集合(表)的创建和数据修改

文章目录 前言发现宝藏一、集合的创建二、集合的修改三、数据插入数据库四、清空数据库集合数据 前言 为了巩固所学的知识&#xff0c;作者尝试着开始发布一些学习笔记类的博客&#xff0c;方便日后回顾。当然&#xff0c;如果能帮到一些萌新进行新技术的学习那也是极好的。作…

华清远见嵌入式学习——春节作业——2.4日

作业要求&#xff1a; 编写程序实现二叉树的创建&#xff0c;三种遍历自己销毁 作业答案&#xff1a; 作业代码截图 作业代码效果图 作业代码 #include "myhead.h"// 定义二叉树节点结构体 struct Tree {int value; //编号(值)struct Tree* left; //左子树stru…

C语言代码审查:解析与应对策略

在C语言编程的世界中&#xff0c;代码审查是一项至关重要的任务&#xff0c;它旨在发现并修复潜在的错误、改进代码质量&#xff0c;并强化开发者的编码规范。本文将详尽阐述C语言代码审查过程中常见的错误类型及其深层原因&#xff0c;同时提供针对性的解决策略和最佳实践。 …

idea创建spring项目

一、环境 window10 IDEA 2022.2.3 maven-3.8.6 二、创建spring项目 1、新建Maven项目 File -> New -> Project 然后如下图选中Maven Archetype&#xff0c;在Archetype&#xff0c;选中maven-archetype-webapp&#xff0c;点击Create 2、配置maven 默认是使用IDEA内…

管理类联考-复试-英语-听力

文章目录 准备工作1.如何准备英语听力&#xff1f;2.听力学习注意事项一&#xff1a;培养良好的听音习惯&#xff0c;听读顺序要合理3.听力学习注意事项二&#xff1a;边听边记关键词 训练短期记忆能力4.听力学习注意事项三&#xff1a;熟记语篇衔接词把握信息走向5.听力学习注…