电子发烧友网 > 嵌入式技术 > 正文

C语言二级指针的用法与原理

2020年07月02日 14:52 次阅读

提到指针,我们都知道指针是用来存储一个变量的地址。所以,当我们定义了一个指向指针的指针的时候(pointer to pointer),我们也称之为二级指针,那针对于这个二级指针来说,第一级指针存放的是指向的变量的地址,第二级指针存放的是第一级指针的地址。可以用下面这张图表示他们之间的关系。

二级指针关系图

上图所表达的意思也就是,一级指针变量 ptr1 存放的是 var 变量的地址,二级指针变量 ptr2 存放的是一级指针变量的地址。这也就是关于二级指针的相关概念。

一级指针与二级指针关系示例

下图是代码运行的结果:

代码运行结果截图

结果也很明显了,一级指针变量 p 存放的是变量 a 的地址,二级指针变量 q 存放的是一级指针变量 p 的地址,所以根据以上结果也能得出下面的等式:

q = &p;*q = p = &a;**q = *p = a;

在了解了上述一级指针和二级指针的一个关系之后,我们再来看另外一个例子:

现在有如下代码:

int main(void){ int **ipp; int i = 5,j = 6,k = 7; int *ip1 = &i,*ip2 = &j; }

如果这个时候,我们加了这么一句代码:

ipp = &ip1;

那么上述所涉及到的数据之间的关系是这样的:

变量关系图

根据上面这个图我们也可以知道,对于 ipp 的两次解引用的结果是 i 的值,也就是说 **ipp = 5,我想对于这个的理解并不困难,如果我继续在这个基础上添加代码,注意,是在上条代码的基础上添加如下代码:

*ipp = ip2;

在这条代码的作用下,数据关系图就发生了改变,改变如下所示:

数据关系图

对于上述的变化来说,我们增加的代码改变的是 *ipp 的值,也就是说 ipp 的值是不会发生改变的,既然 ipp 的值不会发生改变,那么 ipp 指向 ip1 的关系不会发生改变,我们增加的代码改变了 *ipp 的值,那么也就是说改变了一级指针指向的值,而 ip2 是指向 j 的,所以也就有了上述的变化。

紧接着我们继续在第一条增加的代码的基础上重新增加一条代码,增加的代码如下:

*ipp = &k;

那么这个时候所对应的数据关系图如下图所示:

数据关系图

这个原理和刚才的一样,不在这里赘述了。

二级指针的应用那再讲述了上述的基本概念之后,我们知道二级指针变量是用于存放一级指针变量的地址的,那么在具体的实际应用中,又在什么地方可以用到二级指针呢?下面来看一个 C 语言函数传址调用的例子。

我们在刚学习指针的时候,都会碰到如下这样一个例子:

void swap(int *a,int *b){ int temp; temp = *a; *a = *b; *b = temp;}

之所以在定义函数时,把函数的形参定义为指针,而非如下这样的形式:

void swap(int a,int b);

是因为C 语言在进行函数调用的时候,是将实参的值复制一份,并将其副本传递到函数调用里,如果形参定义的不是指针,那么在函数内部改变数值,不会对实参本来的值发生改变。而将形参定义成了指针的话,那么传到函数里面的值虽然是实参地址的一个副本,但是地址里存的值发生了改变,也就导致实参本来的值也发生了改变。

有了上述分析的基础上,我们知道,如果要在一个函数内改变一个数的值,那么就需要将形参定义为指针。同样的,如果我们要在一个函数内改变一个指针的值,我们就需要将形参定义了二级指针,下面来看这样一个例子:

#include 《stdlib.h》int allocstr(int len,char **retptr){ char *p = malloc(len + 1);/*加 1 是为了 ‘\0’ */ if (p = NULL) return 0; *retptr = p; return 1;}

在调用的时候,是像下面这样子进行调用的:

char *string = “hello world!”char *copystr;if (allostr(strlen(string),©str)) strcpy(copystr,string);else printf(“out of memory!\n”);

上述这个例子就是涉及到字符串拷贝的一个实际的例子,因为我们要在 allostr 里改变指针变量 copystr 的值(要使用 malloc 分配内存),那么就需要把 copystr 的地址传到函数里,那么这个时候,所定义的函数形参也就需要是二级指针了。

二级指针在单链表中的应用首先,我们有这样一个单链表的数据结构:

typedef struct ListNode{ int data; struct ListNode *next;}ListNode;

依据这样一个数据结构,假定我们创建了一个如下所示的一个单链表:

单链表

那么我们如果要删除链表中的一个结点的时候,第一时间采用的可能是如下所示的代码:

ListNode *find_and_delete(ListNode *head,int target){ ListNode *pre = NULL; ListNode *entry; for (entry = head; entry != NULL; entry = entry-》next) { if (entry-》data == target) { /* 判断删除的结点是否是第一个结点*/ if (entry == head) head = entry-》next; else pre-》next = entry-》next; free(entry); break; } pre = entry; } return head;}

上述代码所述的删除结点的思路遵循如下图所示的原理,首先是关于当所要删除的结点是第一个结点的时候,删除结点示意图如下所示:

第一个结点删除原理

如果要删除的结点不是处在第一个结点的位置,那么删除结点的原理示意图如下图所示:

普通结点删除

上述就是一个使用一级指针操作链表的一个简单地例子,自己在理解这个例子的时候,也存在几个对我来说的难点,笔者写下来和大家分享一下,首先,

第一个难点就是头指针,在图中画的头指针指向了第一个结点,图中所示的头指针并没有数据域,只是单单地指向了第一个结点,在代码中的 head 指针变量却有数据域,并且就是第一个结点的数据,这个概念的理解其实是对于指针的理解,head 指向了第一个结点,一定注意在这里的 head 是头指针,并不是头结点。(这是笔者个人的理解,如果大家有不同的看法,欢迎各位朋友添加笔者微信共同探讨)。

第二个难点就是上述函数中,函数有一个返回值,返回了头指针。为什么要返回呢?是因为当前传入函数的形参是一级指针,在函数内部改变 head ,在函数运行结束时,head 值并不会发生改变,所以要返回。

第三个难点,那么为什么链表操作中,又能够删除中间的结点呢?是因为虽然 传进去的 head 是一级指针,但是 head 结构体成员内的 next 是一个指针,那这样的话,对于 next 成员来说它是一个二级指针,对于他的变化,在函数结束时是会产生改变的,所以可以删除中间的结点。

二级指针在单链表结点删除的应用上面的例子中,在删除单链表的结点的时候,我们形参采用的是一级指针的方式,在这个过程中,还需要引入 pre 指针来解决这个问题,还有一种很巧妙的方法,利用了二级指针的特性解决了结点删除的问题,在这个过程中,运用二级指针,不需要进行删除第一个结点的判断。具体代码如下:

void find_and_delete2(ListNode **head,int target){ for (; *head != NULL; head = &(*head)-》next) { if ((*head)-》data == target) { (*head) = (*head)-》next; break; } } }

上述的代码没有创建任何局部变量,直接利用 head 进行遍历链表,因为其是二级指针,这样子进行遍历在函数结束后不会改变其本身的链表结构。然后,在进行删除的时候,(*head) 在函数结束后是会保持其在函数内的变化值的,所以也就完成了结点的删除。

下载发烧友APP

打造属于您的人脉电子圈

关注电子发烧友微信

有趣有料的资讯及技术干货

关注发烧友课堂

锁定最新课程活动及技术直播

电子发烧友观察

一线报道 · 深度观察 · 最新资讯
收藏 人收藏
分享:

评论

相关推荐

嵌入式C语言进阶课程

实际工程经验为蓝本,结合C语言中易错和长期被误解的知识点进行深度讲解。
发烧友学院发表于 2018-12-14 00:00 5263次阅读
嵌入式C语言进阶课程

c语言宏定义的使用方法

当宏作为常量使用时,C程序员习惯在名字中只使用大写字母。但是并没有如何将用于其他目的的宏大写的统一做....
发表于 2020-07-02 15:04 0次阅读
c语言宏定义的使用方法

HW资料华-为硬件(硬件开发C语言PCB设计天线通信)

链接:https://pan.baidu.com/s/1HFxkb4O1jAZvCEccWVcd4w 提取码:stns 回复可见提取码,资源需求可加q1...
发表于 2020-07-01 18:20 50次阅读
HW资料华-为硬件(硬件开发C语言PCB设计天线通信)

C语言和PHP,新手选择哪个比较好?

计科专业从事嵌入式开发多年,从现在的市场行情以及就业的机会上讲php的就业空间还是大于C语言,但并不....
发表于 2020-07-01 16:15 45次阅读
C语言和PHP,新手选择哪个比较好?

Python的发展趋势,未来可期

首先,当前Python作为一门流行程度比较高的全场景编程语言,在IT互联网行业和一部分传统行业已经有....
发表于 2020-07-01 10:19 116次阅读
Python的发展趋势,未来可期

详谈选择排序算法的定义和过程

选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是:第一次从待排序的数....
发表于 2020-06-30 17:06 47次阅读
详谈选择排序算法的定义和过程

C语言模拟实现memmove函数

memmove用于从src拷贝count个字节到dest,如果目标区域和源区域有重叠的话,memmo....
发表于 2020-06-29 17:53 63次阅读
C语言模拟实现memmove函数

C语言模拟实现memcpy函数

memcpy指的是c和c++使用的内存拷贝函数,memcpy函数的功能是从源src所指的内存地址的起....
发表于 2020-06-29 17:29 137次阅读
C语言模拟实现memcpy函数

C语言模拟实现strcmp函数

C语言模拟实现strcmp函数
发表于 2020-06-29 16:51 148次阅读
C语言模拟实现strcmp函数

C语言模拟实现strstr函数

strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。如果是,则该函数....
发表于 2020-06-29 16:36 293次阅读
C语言模拟实现strstr函数

C语言模拟实现strcat函数

C语言模拟实现strcat函数
发表于 2020-06-29 16:18 101次阅读
C语言模拟实现strcat函数

C语言模拟实现strcpy

strcpy是一种C语言的标准库函数,strcpy把从src地址开始且含有’\0’结束符的字符串复制....
发表于 2020-06-29 15:54 98次阅读
C语言模拟实现strcpy

C语言模拟实现strlen的步骤

strlen所作的仅仅是一个计数器的工作,它从内存的某个位置(可以是字符串开头,中间某个位置,甚至是....
发表于 2020-06-29 15:48 119次阅读
C语言模拟实现strlen的步骤

理解函数指针、函数指针数组、函数指针数组的指针

理解函数指针、函数指针数组、函数指针数组的指针
发表于 2020-06-29 15:38 218次阅读
理解函数指针、函数指针数组、函数指针数组的指针

图文详解:数组和指针的传参

数组传参时,会退化为指针,所以我们先来看看什么是退化!
发表于 2020-06-29 15:34 85次阅读
图文详解:数组和指针的传参

指针数组和数组指针的区别

这里我们区分两个重要的概念:指针数组、数组指针。
发表于 2020-06-29 15:30 94次阅读
指针数组和数组指针的区别

详谈数组和指针的区别与联系

详谈数组和指针的区别与联系
发表于 2020-06-29 15:18 47次阅读
详谈数组和指针的区别与联系

C++:常引用的概念和作用

int &a=b 相当于 int const a=b。即引用是一个指针常量(又称常指针,即一个常量,....
发表于 2020-06-29 15:08 59次阅读
C++:常引用的概念和作用

C++:指针和引用的区别与联系

指针:指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元。引用:引用跟原来的变量....
发表于 2020-06-29 15:05 58次阅读
C++:指针和引用的区别与联系

详谈C语言和C++的区别和联系

在学习了C语言和C++之后,这两者之间的区别我们需要仔细的捋一捋!
发表于 2020-06-29 14:56 48次阅读
详谈C语言和C++的区别和联系

C++封装:this指针

C++封装:this指针
发表于 2020-06-29 14:37 133次阅读
C++封装:this指针

单片机程序开发的语言怎么选择

单片机程序的开发可以使用的两种语言,分别是C语言和汇编语言。这里要指出的一件事是,这不是嵌入式单片机....
发表于 2020-06-29 11:22 259次阅读
单片机程序开发的语言怎么选择

C语言精华知识:表驱动法编程实践

根据字典中的部首检字表查找读音未知的汉字就是典型的表驱动法,即以每个字的字形为依据,计算出一个索引值....
发表于 2020-06-28 17:10 124次阅读
C语言精华知识:表驱动法编程实践

聊聊我为什么热爱开源

后面的学习过程中,接触了单片机,我发现这东西也很有趣,能做点小东西,做个时钟、小车、LED小蛮腰。。....
发表于 2020-06-28 17:07 105次阅读
聊聊我为什么热爱开源

Linux TraceEvent - 史上最长宏...

看完了例子,我们就该看代码实现了。讲真,这是我见过的最长的宏展开了。之前在qemu上看到的那个hmp....
发表于 2020-06-28 09:34 155次阅读
Linux TraceEvent - 史上最长宏...

初次接触单片机,你会选择哪款?

其实,模拟电子、数字电子、c语言、汇编这些课程,就是为学单片机课程打下基础。单片机课程涉及到众多专业....
发表于 2020-06-25 17:33 59次阅读
初次接触单片机,你会选择哪款?

在C语言中,全局变量滥用的后果是什么

01 啥是全局变量 说起全局变量,就不得不提到全局变量,局部变量,静态全局变量,静态局部变量,这些都....
发表于 2020-06-24 17:14 57次阅读
在C语言中,全局变量滥用的后果是什么

盘点一些在C语言中比较容易犯的错误

本题中的#运算符可以利用宏参数创建字符串。##运算符和#运算符一样也可以用于类函数宏的替换部分。另外....
发表于 2020-06-24 16:45 25次阅读
盘点一些在C语言中比较容易犯的错误

C语言的策略模式提高了程序的可维护性和扩展性

这里先插一点题外话,在C语言中,实现封装、继承、隐藏、多态等等特性,是完全没有问题的。但是在使用过程....
发表于 2020-06-24 16:29 42次阅读
C语言的策略模式提高了程序的可维护性和扩展性

从技术学习和实际运用的角度来看C/C++和Jav...

关于C语言和C++的学习路线终于梳理完了。当然我也只能从我曾经近3年的通信公司后台开发经历和目之所及....
发表于 2020-06-24 16:16 56次阅读
从技术学习和实际运用的角度来看C/C++和Jav...

c语言入门:c语言的具体结构

变量就是可以变化的量,而每个变量都会有一个名字(标识符)。变量占据内存中一定的存储单元。使用变量之前....
发表于 2020-06-23 15:38 252次阅读
c语言入门:c语言的具体结构

为什么要将C语言作为入门语言?

编程是向计算机发出指令以执行特定任务或执行指令的行为,目前专业行业和学术界使用数百种编程语言。一个人....
发表于 2020-06-23 15:13 110次阅读
为什么要将C语言作为入门语言?

大学生如何学习FPGA初学者怎么学FPGA

无论是从自身的发展,还是从FPGA所拥有的巨大市场来讲,学习FPGA都是一个不错的选择,对大家来说FPGA技术...
发表于 2020-06-23 15:12 240次阅读
大学生如何学习FPGA初学者怎么学FPGA

算法:计算Fibonacci number的六个...

算法:计算Fibonacci number的六个方法
发表于 2020-06-22 17:27 182次阅读
算法:计算Fibonacci number的六个...

C语言算法分析:求最长的递增数列

求最长的递增数列(Longest Increasing sequence, LIS)是一个比较常见的....
发表于 2020-06-22 14:57 142次阅读
C语言算法分析:求最长的递增数列

虚拟机:编译器对C函数的名字修饰

虚拟机:编译器对C函数的名字修饰
发表于 2020-06-22 11:44 238次阅读
虚拟机:编译器对C函数的名字修饰

详解C语言二分查找算法细节

我相信对很多读者朋友来说,编写二分查找的算法代码属于玄学编程,虽然看起来很简单,就是会出错,要么会漏....
发表于 2020-06-22 09:05 166次阅读
详解C语言二分查找算法细节

C语言:LeetCode 153寻找旋转排序数组...

假设按照升序排序的数组在预先未知的某个点上进行了旋转。
发表于 2020-06-22 08:59 118次阅读
C语言:LeetCode 153寻找旋转排序数组...

查找山脉数组最大值的三个方法

何为山脉数组?如果数组 A 是一个山脉数组的话,那它满足如下条件:
发表于 2020-06-22 08:51 133次阅读
查找山脉数组最大值的三个方法

C语言: Leetcode 33搜索旋转排序数组

假设按照升序排序的数组在预先未知的某个点上进行了旋转。
发表于 2020-06-22 08:51 119次阅读
C语言: Leetcode 33搜索旋转排序数组

C语言:leetcode 35搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会....
发表于 2020-06-22 08:40 110次阅读
C语言:leetcode 35搜索插入位置

探讨单片机C语言编程理论知识

编程思路和算法决定一个程序的优劣,是单片机编程的大问题,只有在实际动手编写的时候才会有深切的感悟。一....
发表于 2020-06-18 16:06 254次阅读
探讨单片机C语言编程理论知识

单片机C语言编程:.H文件与.C文件的关系

经过查找资料得知,.H文件就是头文件,估计就是Head的意思吧,这是规范程序结构化设计的需要,既可以....
发表于 2020-06-18 15:18 248次阅读
单片机C语言编程:.H文件与.C文件的关系

有人用过C语言位域吗

typedef struct {u16 b :5; u16 g :6; u16 r :5; } RGB; RGB *rgb; tx=0xf40f;      &n...
发表于 2020-06-16 04:35 34次阅读
有人用过C语言位域吗

知道C语言的用法但是avr里面并没有time这个头文件,是要用中断吗

知道C语言的用法但是avr里面并没有time这个头文件,是要用中断吗, 求大神神助解答 ...
发表于 2020-06-15 05:56 979次阅读
知道C语言的用法但是avr里面并没有time这个头文件,是要用中断吗

GPIOA->CRH&=0xFFFFFFFO什么意思呀?

问一下GPIOA->CRH&=0xFFFFFFFO什么意思呀?因为我是菜鸟刚看这个根本什么都不知道!!!...
发表于 2020-06-13 09:00 183次阅读
GPIOA->CRH&=0xFFFFFFFO什么意思呀?

C语言和ASM语言是怎么建立起来的联系呢?

在HVLLC主程序中,有如下定义 extern volatile long *ADCDRV_1ch_Rlt7; // Vout volatile long Vout; ...
发表于 2020-06-09 14:51 66次阅读
C语言和ASM语言是怎么建立起来的联系呢?

谁有嵌入式C语言入门视频教程

  本套C语言视频教程是星创客精英训练营的基础教程,由华清远见总监级讲师冯利美花了一个月的时间录制。经过后期音...
发表于 2020-06-08 04:35 55次阅读
谁有嵌入式C语言入门视频教程

c语言写代码是怎样组织文件的?

在用c语言写代码是大家是怎样组织文件的?一般都是一个.c配一个.h文件, 并且.c中放函数和变量定义,.h中放宏定义和函...
发表于 2020-06-05 03:20 42次阅读
c语言写代码是怎样组织文件的?

求最值的c语言程序问题

各位广大的坛友好: 先谢谢各位坛友! 本人最近初学c语言程序设计遇到了一个问题,程序如下所示: #include int ...
发表于 2020-06-02 20:52 263次阅读
求最值的c语言程序问题

C语言编程问题

我想问一下论坛的各位: 怎么用按键控制灯 按一下按键,第一个LED灯D1开始闪烁,闪烁5秒后常亮。但是如果在D...
发表于 2020-06-02 14:05 224次阅读
C语言编程问题