C语言入门系列:探秘二级指针与多级指针的奇妙世界

2024-06-24 12:20

本文主要是介绍C语言入门系列:探秘二级指针与多级指针的奇妙世界,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 一,指针的回忆杀
    • 1,指针的概念
    • 2,指针的声明和赋值
    • 3,指针的使用
      • 3.1 直接给指针变量赋值
      • 3.2 通过*运算符读写指针指向的内存
        • 3.2.1 读
        • 3.2.2 写
  • 二,二级指针详解
    • 1,定义
    • 2,示例说明
    • 3,二级指针与一级指针、普通变量的关系
      • 3.1,与一级指针的关系
      • 3.2,与普通变量的关系,
      • 示例说明
    • 4,二级指针的常见用途
    • 5,二级指针扩展到多级指针
  • 小结

C语言的学习之旅中,二级指针乃至多级指针往往是初学者感到“恶心”却又不得不面对的重要概念。

不过,一旦掌握了它们的精髓,你会发现它们其实并不那么可怕,反而在某些高级应用中显得尤为强大和灵活。

一,指针的回忆杀

1,指针的概念

指针就是内存地址,内存地址指向内存中的一个单元,这个单元就像一个个小房间,里面住着某种数据,可能是整数,可能是浮点数,可能是字符,也可能是另一个指针。

为了方便理解和记忆,可以把指针当作酒店房间号。

指针作为一种特殊的数据,也需要存储在内存中。

2,指针的声明和赋值

C语言通过指针变量为指针开辟一块内存。

int num = 10;
int* p;
p = #

如上代码,定义了指针变量p,声明变量时如果带有*号,说明这个变量是指针变量。

这个*号的作用是告诉编译器,这个指针变量p要存储的是变量num的值的内存地址,这个内存地址从形式上看也没什么特别,就是一个整数。

上面的代码中p = #,通过地址运算符&取出变量num的地址,赋给指针变量p

在这里插入图片描述

3,指针的使用

3.1 直接给指针变量赋值

上面的代码中p = # 所示,可以和普通变量一样,直接给指针变量赋值,只是这个值代表的是内存地址而已。

3.2 通过*运算符读写指针指向的内存

3.2.1 读

我们还可以通过* 运算符操作指针指向的内存中的值。

int num = 10;
int* p;
p = #int num2 = *p;

如上代码最后一行int num2 = *p;,运算符*的作用是告诉编译器,找到指针p指向的地址,从中读取数据。

3.2.2 写

当然,可以修改指针指向的内存中的数据。

int num = 10;
int* p;
p = #*p = 100;

上述代码*p = 100;,将指针p指向的内存中数据的值修改为100。注意,此时num的值也变为100了,原因是修改的就是num的内存中的值。

二,二级指针详解

1,定义

二级指针,顾名思义,是指向指针的指针,即一个变量,其类型是指向指针的地址。在C语言中,声明一个二级指针的基本形式如下:

数据类型** pointerName;

这里,**pointerName表示pointerName是一个指向指针的指针,它存储的是一个指针变量的地址。

int num = 10;
int* p;
p = #int** pp = &p;

如上,二级指针变量pp指向的是指针变量p的地址。
在这里插入图片描述

如上图所示,发现二级指针需要跳2级才能获取普通变量内存中的值,这也是二级指针名称的来源。

2,示例说明

以一个整型变量为例:

int a = 12;
int *p = &a;
int **pp = &p;

根据上述定义,我们可以得出以下计算结果:

p == &a
*p == 12
pp == &p
*pp == p
**pp == a

**pp就是获取a变量的值,因为pp指向的是p的地址,而p指向的又是a的地址,所以 **pp 就相当于a

3,二级指针与一级指针、普通变量的关系

3.1,与一级指针的关系

一级指针存储的是普通变量的地址,而二级指针存储的是一级指针的地址。
通过二级指针,我们可以间接访问到一级指针所指向的数据,实现更深层次的间接访问。

3.2,与普通变量的关系,

普通变量是数据存储的最直接形式,通过一级指针,我们增加了一层间接访问;二级指针则在此基础上再增加一层间接性,使得对普通变量的操作更为灵活。

示例说明

#include <stdio.h>
#include <stdlib.h>int main() {int value = 10;int *p = &value; // 一级指针,指向valueint **pp = &p;   // 二级指针,指向一级指针pprintf("Value: %d\n", value);      // 直接访问printf("Value via *p: %d\n", *p);  // 通过一级指针访问printf("Value via **pp: %d\n", **pp); // 通过二级指针访问return 0;
}

此例中,value是一个普通整型变量,p是一级指针指向value,而pp作为二级指针,则指向p。通过**pp,我们依然能最终访问到value的值,展示了指针间接访问的层级关系。

4,二级指针的常见用途

  • 动态内存管理:在动态分配数组时,可以使用二级指针来存储数组的首地址,便于管理和释放内存。
  • 函数参数传递:当希望函数能够修改外部指针变量(而非指针所指向的内容)时,需使用二级指针作为函数参数。
  • 指向指针的指针运算:在复杂数据结构操作中,二级指针提供了对指针进行指针运算的能力,如链表的节点交换、树结构的遍历等。

5,二级指针扩展到多级指针

多级指针的概念基于二级指针进一步扩展,即指针的指针的指针……依此类推。

一句话,多级指针存储的是上一级指针的地址。

虽然在日常编程中较为罕见,但在特定场景下,如复杂的内存管理、高度抽象的数据结构设计或底层系统编程中,多级指针可以提供极大的灵活性。

示例:三级指针

#include <stdio.h>void printViaTriplePointer(int ***triplePtr) {printf("Value via ***triplePtr: %d\n", ***triplePtr);
}int main() {int value = 7;int *p = &value;int **pp = &p;int ***triplePtr = &pp;printViaTriplePointer(triplePtr);return 0;
}

这个例子中,triplePtr是一个三级指针,通过它我们依然能够最终访问到最初定义的value。虽然看起来繁琐,但在特定逻辑或系统级操作中,这样的间接访问机制可能非常有用。

小结

总之,二级指针乃至多级指针虽初看复杂,实则是C语言中处理复杂数据结构和内存管理的强大工具。通过实践和理解,你将逐步揭开它们的神秘面纱,发现其背后的逻辑之美。

这篇关于C语言入门系列:探秘二级指针与多级指针的奇妙世界的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1090131

相关文章

C语言逗号运算符和逗号表达式的使用小结

《C语言逗号运算符和逗号表达式的使用小结》本文详细介绍了C语言中的逗号运算符和逗号表达式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习... 在C语言中逗号“,”也是一种运算符,称为逗号运算符。 其功能是把两个表达式连接其一般形式为:表达

Go语言实现桥接模式

《Go语言实现桥接模式》桥接模式是一种结构型设计模式,它将抽象部分与实现部分分离,使它们可以独立地变化,本文就来介绍一下了Go语言实现桥接模式,感兴趣的可以了解一下... 目录简介核心概念为什么使用桥接模式?应用场景案例分析步骤一:定义实现接口步骤二:创建具体实现类步骤三:定义抽象类步骤四:创建扩展抽象类步

GO语言实现串口简单通讯

《GO语言实现串口简单通讯》本文分享了使用Go语言进行串口通讯的实践过程,详细介绍了串口配置、数据发送与接收的代码实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 目录背景串口通讯代码代码块分解解析完整代码运行结果背景最近再学习 go 语言,在某宝用5块钱买了个

SpringCloud Stream 快速入门实例教程

《SpringCloudStream快速入门实例教程》本文介绍了SpringCloudStream(SCS)组件在分布式系统中的作用,以及如何集成到SpringBoot项目中,通过SCS,可... 目录1.SCS 组件的出现的背景和作用2.SCS 集成srping Boot项目3.Yml 配置4.Sprin

GO语言zap日志库理解和使用方法示例

《GO语言zap日志库理解和使用方法示例》Zap是一个高性能、结构化日志库,专为Go语言设计,它由Uber开源,并且在Go社区中非常受欢迎,:本文主要介绍GO语言zap日志库理解和使用方法的相关资... 目录1. zap日志库介绍2.安装zap库3.配置日志记录器3.1 Logger3.2 Sugared

Go语言中如何进行数据库查询操作

《Go语言中如何进行数据库查询操作》在Go语言中,与数据库交互通常通过使用数据库驱动来实现,Go语言支持多种数据库,如MySQL、PostgreSQL、SQLite等,每种数据库都有其对应的官方或第三... 查询函数QueryRow和Query详细对比特性QueryRowQuery返回值数量1个:*sql

SpringMVC配置、映射与参数处理​入门案例详解

《SpringMVC配置、映射与参数处理​入门案例详解》文章介绍了SpringMVC框架的基本概念和使用方法,包括如何配置和编写Controller、设置请求映射规则、使用RestFul风格、获取请求... 目录1.SpringMVC概述2.入门案例①导入相关依赖②配置web.XML③配置SpringMVC

GO语言中gox交叉编译的实现

《GO语言中gox交叉编译的实现》本文主要介绍了GO语言中gox交叉编译的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录一、安装二、使用三、遇到的问题1、开启CGO2、修改环境变量最近在工作中使用GO语言进行编码开发,因

MySQL索引踩坑合集从入门到精通

《MySQL索引踩坑合集从入门到精通》本文详细介绍了MySQL索引的使用,包括索引的类型、创建、使用、优化技巧及最佳实践,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友... 目录mysql索引完整教程:从入门到入土(附实战踩坑指南)一、索引是什么?为什么需要它?1.1 什么

Java Lettuce 客户端入门到生产的实现步骤

《JavaLettuce客户端入门到生产的实现步骤》本文主要介绍了JavaLettuce客户端入门到生产的实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 目录1 安装依赖MavenGradle2 最小化连接示例3 核心特性速览4 生产环境配置建议5 常见问题