【C++】指针的点运算与箭头运算(->)的奥秘与应用

在这里插入图片描述

在编程的世界里,指针作为连接程序与内存之间的桥梁,扮演着至关重要的角色。对于使用C、C++等语言进行开发的程序员而言,理解并掌握指针的使用技巧是提升编程能力的必经之路。其中,指针的点运算(.)和箭头运算(->)虽然看似简单,但其背后的逻辑和应用场景却十分丰富。本文将深入剖析这两种运算的区别,并通过丰富的示例来说明它们在实际编程中的应用,同时给出相关的编程建议。
在这里插入图片描述

一、引言

在C和C++中,结构体(struct)和类(class)是组织数据和函数(在C++中为成员函数)的基本单位。当我们需要操作这些复合数据类型的成员时,如果直接拥有其实例,我们会使用点运算符(.);而如果手上持有的是指向这些实例的指针,那么箭头运算符(->)则成为我们的首选。这两种运算符虽然功能相似,但使用场景和方式截然不同,理解它们之间的区别对于编写高效、可维护的代码至关重要。

二、点运算(.)详解

2.1 定义与用法

点运算符(.)用于直接访问结构体或类对象的成员变量或成员函数。当你拥有一个结构体或类的实例时,可以通过.运算符来读取或修改其成员变量的值,或者调用其成员函数。

示例:

#include <stdio.h>  
#include <string.h>  typedef struct {  int age;  char name[50];  void introduce() {  printf("Hello, my name is %s and I am %d years old.\n", name, age);  }  
} Person;  int main() {  Person alice;  alice.age = 30;  strcpy(alice.name, "Alice");  alice.introduce(); // 调用成员函数  return 0;  
}

在这个例子中,alice 是一个 Person 类型的实例。我们使用 . 运算符来设置 alice 的 age 和 name 成员,并调用其 introduce 成员函数。

2.2 使用场景

直接操作结构体或类的实例。
访问或修改实例的成员变量。
调用实例的成员函数。

三、箭头运算(->)详解

3.1 定义与用法

箭头运算符(->)是专门为通过指针访问结构体或类成员而设计的。当你拥有一个指向结构体或类实例的指针时,不能直接使用.运算符来访问其成员,因为.运算符期望的是一个具体的实例,而不是一个指向实例的指针。此时,你需要使用->运算符来“解引用”指针,并访问其指向的实例的成员。

示例:

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  typedef struct {  int age;  char name[50];  void introduce() {  printf("Hello, my name is %s and I am %d years old.\n", name, age);  }  
} Person;  int main() {  Person *pAlice = (Person *)malloc(sizeof(Person)); // 分配内存  if (pAlice != NULL) {  pAlice->age = 25;  strcpy(pAlice->name, "Alice");  pAlice->introduce(); // 调用成员函数  free(pAlice); // 释放内存  }  return 0;  
}

在这个例子中,pAlice 是一个指向 Person 类型的指针。我们使用 -> 运算符来设置 pAlice 指向的实例的 age 和 name 成员,并调用其 introduce 成员函数。注意,在使用完动态分配的内存后,我们通过 free 函数来释放它,以避免内存泄漏。

3.2 使用场景

操作通过指针间接访问的结构体或类实例。
在函数间传递结构体或类实例的指针时,用于访问这些实例的成员。
在处理动态分配的内存时,用于访问和修改内存中的数据。

四、点运算与箭头运算的区别

  • 操作对象不同:点运算直接作用于结构体或类的实例,而箭头运算作用于指向这些实例的指针。
  • 使用场景不同:点运算通常用于局部或全局变量中直接操作结构体或类的实例;箭头运算则更多地用于通过指针间接访问结构体或类的成员,特别是在处理函数参数、动态内存分配等场景时。

五、深入比较与应用实例

5.1 深入比较

除了操作对象和使用场景的不同外,点运算和箭头运算在语义上也存在微妙的差别。点运算直接关联于一个具体的对象实例,它告诉我们:“在这个具体的对象上,我找到了某个成员。”而箭头运算则涉及到了指针的间接引用,它说:“在这个指针所指向的地方,我找到了某个成员。”这种间接性使得箭头运算在处理复杂数据结构(如链表、树等)时尤为重要。

此外,从代码可读性的角度来看,正确使用这两种运算符也能帮助其他开发者(或未来的你)更快地理解代码的逻辑。例如,在遍历链表时,使用箭头运算来访问每个节点的成员是非常自然且易于理解的;相反,如果错误地使用了点运算,则可能会导致代码难以阅读和维护。

5.2 应用实例:链表操作

链表是一种常见的数据结构,它由一系列节点组成,每个节点都包含数据部分和指向下一个节点的指针。在C或C++中,我们可以使用结构体来定义链表的节点,并通过指针来连接这些节点。此时,箭头运算就显得尤为重要。

示例:

#include <stdio.h>  
#include <stdlib.h>  typedef struct Node {  int data;  struct Node *next;  
} Node;  void append(Node **head, int newData) {  Node *newNode = (Node *)malloc(sizeof(Node));  if (newNode == NULL) {  printf("Memory allocation failed\n");  return;  }  newNode->data = newData;  newNode->next = NULL;  if (*head == NULL) {  *head = newNode;  return;  }  Node *last = *head;  while (last->next != NULL) {  last = last->next;  }  last->next = newNode;  
}  void printList(Node *head) {  Node *current = head;  while (current != NULL) {  printf("%d ", current->data);  current = current->next;  }  printf("\n");  
}  int main() {  Node *head = NULL;  append(&head, 1);  append(&head, 2);  append(&head, 3);  printList(head); // 输出链表中的元素  // 释放链表内存(略去,以简化示例)  return 0;  
}

在这个例子中,append 函数用于向链表的末尾添加一个新节点。注意,在 append 函数中,我们使用 Node **head 作为参数,这样我们就可以修改链表头指针本身(如果链表为空)。在函数内部,我们使用箭头运算符来访问新节点和链表末尾节点的 data 和 next 成员。同样地,在 printList 函数中,我们也使用箭头运算符来遍历链表并打印每个节点的数据。

六、编程建议

**明确操作对象:**在编写代码时,首先要明确你正在操作的是一个具体的结构体或类实例,还是一个指向这些实例的指针。这将决定你应该使用点运算还是箭头运算。
**保持代码一致性:**在同一代码块中,尽量保持对同一结构体或类成员访问方式的一致性。如果一开始选择了使用箭头运算来访问某个成员,那么在整个代码块中都应该坚持使用箭头运算(除非出于某种特殊原因需要改变)。
**注意内存管理:**当使用动态内存分配(如 malloc 或 new)来创建结构体或类实例的指针时,请务必在适当的时候释放这些内存,以避免内存泄漏。
**提高代码可读性:**合理使用注释和变量命名来提高代码的可读性。良好的代码风格不仅有助于其他开发者理解你的代码,也有助于你自己将来回顾和维护代码。
**理解指针的间接性:**箭头运算的核心在于指针的间接性。要深入理解这一点,你需要对指针和内存管理有深入的了解。通过实践和学习相关的教程和书籍,你可以逐渐掌握这些技能。
总之,点运算和箭头运算是C和C++等语言中不可或缺的一部分。通过深入理解它们的区别和应用场景,并遵循上述编程建议,你可以编写出更加高效、可维护的代码。

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

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

相关文章

Android系统集成和使用FFmpeg

文章目录 前言FFmpeg源码下载交叉编译NDK下载x264编译源码下载编译 FFmpeg编译脚本 AOSP继承FFmpeg 前言 原生AOSP中并未继承FFmpeg&#xff0c;所以要想在android上使用&#xff0c;需要自己编译集成。 FFmpeg源码下载 git clone https://git.ffmpeg.org/ffmpeg.git目前最新…

自动化测试报告pytest-html样式美化

最近我将 pytest-html 样式优化了 一版 先看优化前&#xff1a; 优化后&#xff1a; 优化内容包括&#xff1a; 删除部分多余字段新增echart图表部分字体大小、行间距、颜色做了美化调整运行环境信息移至报告最后部分字段做了汉化处理&#xff08;没全部翻译是因为&#xf…

vue3 引入百度地图的三种方式

本次也是正好写了一个基于VUE3和百度地图的设计&#xff0c;但奈何第一次使用百度地图&#xff0c;在学习的途中遇到了很多问题&#xff0c;也发现网上的材料相对较少&#xff0c;因此做出了一些小总结&#xff0c;后续还会更新。 一、直接引入 直接在public中的index.html中进…

[FreeRTOS 功能应用] 事件组 功能应用

文章目录 一、基础知识点二、代码讲解三、结果演示四、代码下载 一、基础知识点 [FreeRTOS 基础知识] 事件组 概念 [FreeRTOS 内部实现] 事件组 本实验是基于STM32F103开发移植FreeRTOS实时操作系统&#xff0c;事件组实战操作。(当task1和task2同时完成&#xff0c;才执行ta…

二维Gamma分布的激光点云去噪

目录 1、Gamma 分布简介2、实现步骤 1、Gamma 分布简介 Gamma 分布在合成孔径雷达( Synthetic Aperture &#xff32;adar&#xff0c;SA&#xff32;) 图像分割中具有广泛应用&#xff0c;较好的解决了SA&#xff32; 图像中相干斑噪声对图像分割的影响。采用二维Gamma 分布对…

web前端开发——开发环境和基本知识

今天我来针对web前端开发讲解一些开发环境和基本知识 什么是前端 前端通常指的是网站或者Web应用中用户可以直接与之交互的部分&#xff0c;包括网站的结构、设计、内容和功能。它是软件开发中的一个专业术语&#xff0c;特别是指Web开发领域。前端开发涉及的主要技术包括HTML…

昇思25天学习打卡营第15天|linchenfengxue

Pix2Pix实现图像转换 Pix2Pix概述 Pix2Pix是基于条件生成对抗网络&#xff08;cGAN, Condition Generative Adversarial Networks &#xff09;实现的一种深度学习图像转换模型&#xff0c;该模型是由Phillip Isola等作者在2017年CVPR上提出的&#xff0c;可以实现语义/标签到…

Java常用算法集合扩容机制分析

基础篇 基础篇要点&#xff1a;算法、数据结构、基础设计模式 1. 二分查找 要求 能够用自己语言描述二分查找算法能够手写二分查找代码能够解答一些变化后的考法 算法描述 前提&#xff1a;有已排序数组 A&#xff08;假设已经做好&#xff09; 定义左边界 L、右边界 R&…

东芝TB6560AHQ/AFG步进电机驱动IC:解锁卓越的电机控制性能

作为一名工程师&#xff0c;一直在寻找可靠且高效的组件来应用于你的项目中。东芝的TB6560AHQ/AFG步进电机驱动IC能够提供精准且多功能的电机控制&#xff0c;完全符合现代应用的高要求&#xff0c;保证高性能和易用性。在这篇文章中&#xff0c;我们将探讨TB6560AHQ/AFG的主要…

硅纪元视角 | 国内首款鸿蒙人形机器人“夸父”开启应用新篇章

在数字化浪潮的推动下&#xff0c;人工智能&#xff08;AI&#xff09;正成为塑造未来的关键力量。硅纪元视角栏目紧跟AI科技的最新发展&#xff0c;捕捉行业动态&#xff1b;提供深入的新闻解读&#xff0c;助您洞悉技术背后的逻辑&#xff1b;汇聚行业专家的见解&#xff0c;…

es6新语法

es6新语法 1 什么是ES6 JS语法分三块 ECMAScript : 基础语法BOM 浏览器对象 history location windowDOM 文档对象 document 编程语言JavaScript是ECMAScript的实现和扩展 。ECMAScript是由ECMA&#xff08;一个类似W3C的标准组织&#xff09;参与进行标准化的语法规范。ECMAS…

医疗器械企业CRM系统推荐清单(2024版)

近年来&#xff0c;我国医疗器械行业在国家政策支持、医改深入、人口老龄化和消费能力提升等因素推动下&#xff0c;得到了快速发展&#xff0c;正日益成为创新能力增强、市场需求旺盛的朝阳产业。然而&#xff0c;行业也面临价格压力、市场份额重新分配、合规风险以及产品和服…

解决 MEX 文件 ‘xxx.mexw64‘ 无效: 找不到指定的模块。的问题

1.问题描述 在matlab R2021b中运行编译好后的gptoolbox工具箱中的函数[SVtemp,SFtemp,IF] selfintersect(V,F);报错如下 MEX 文件 E:\MATLAB_File\gptoolbox\mex\selfintersect.mexw64 无效: 找不到指定的模块。出错 offset_bunny (第 15 行) [SVtemp,SFtemp,IF] selfinter…

论文略读:Learning and Forgetting Unsafe Examples in Large Language Models

随着发布给公众的大语言模型&#xff08;LLMs&#xff09;数量的增加&#xff0c;迫切需要了解这些模型从第三方定制的微调数据中学习的安全性影响。论文研究了在包含不安全内容的噪声定制数据上微调的LLMs的行为&#xff0c;这些数据集包含偏见、毒性和有害性 发现虽然对齐的L…

3033. 修改矩阵 Easy

给你一个下标从 0 开始、大小为 m x n 的整数矩阵 matrix &#xff0c;新建一个下标从 0 开始、名为 answer 的矩阵。使 answer 与 matrix 相等&#xff0c;接着将其中每个值为 -1 的元素替换为所在列的 最大 元素。 返回矩阵 answer 。 示例 1&#xff1a; 输入&#xff1a;…

查看电脑显卡(NVIDIA)应该匹配什么版本的CUDA Toolkit

被串行计算逼到要吐时&#xff0c;决定重拾CUDa了&#xff0c;想想那光速般的处理感觉&#xff08;夸张了&#xff09;不要太爽&#xff0c;记下我的闯关记录。正好我的电脑配了NVIDIA独显&#xff0c;GTX1650&#xff0c;有菜可以炒呀&#xff0c;没有英伟达的要绕道了。回到正…

【Linux】生物信息学常用命令

参考资料来自生信技能树 先输入echo export PS1"[\033]2;\h:\u \w\007\033[33;1m]\u \033[35;1m\t\033[0m [\033[36;1m]\w[\033[0m]\n[\e[32;1m]$ [\e[0m]" >> ~/.bashrc 再输入source ~/.bashrc就能够让命令字体带上颜色&#xff0c;同时命令将会在下一行开…

软件设计之Java入门视频(12)

软件设计之Java入门视频(12) 视频教程来自B站尚硅谷&#xff1a; 尚硅谷Java入门视频教程&#xff0c;宋红康java基础视频 相关文件资料&#xff08;百度网盘&#xff09; 提取密码&#xff1a;8op3 idea 下载可以关注 软件管家 公众号 学习内容&#xff1a; 该视频共分为1-7…

每日一题~ (判断是否是合法的出栈序列)

大概的题意&#xff1a; 将 1-n 按照顺序进栈&#xff0c;问 输入的序列是否是合法的出栈序列。 遍历序列&#xff0c;如果当前这个值a小于 栈顶的值&#xff0c;说明它还未进栈&#xff08;因为我们是按照顺序进栈的&#xff09;&#xff0c;所以我们将 一些元素进栈&#xff…

nacos源码 nacos注册中心1.4.x 源码 spring cloud alibaba 的discovery做了什么 nacos客户端是如何启动的(二)

spring-cloud-alibaba-nacos-discovery 老版本中如何调用nacos的 1. 整体结构&#xff1a; 2. 思考: 如果你来做&#xff0c;如何做client 向server注册服务&#xff1a; 1.2.1 读yml&#xff0c;或本地文件找到服务器地址&#xff0c;以及其他配置 1.2.2 向server注册服务 1.2…