- 作 用
- 为了获取指针的存放地址。
- 分 类
- 按指向的数据类型分类
- 指 针
- 表现形式是地址
- 中文名
- 二级指针
-
2021-12-26 11:15:43
今天带大家了解一下什么是一级指针、二级指针、三级指针
1、一级指针
一级指针其实就是我们平时常见的普通指针
如:int a = 12; int * b = &a; //一级指针,定义一个指针变量b,将整型变量a的地址(指针)赋值给b
所以首先我们介绍一下什么是指针?
指针其实是一个内存地址,对于一个内存单元来说,单元的地址即为指针。而我们平时常用的指针则是指针变量。
指针变量从字面意思上可以看出是存储指针的一种变量类型。
在C语言中,允许用一个变量来存放指针,这种变量称为指针变量。也就是,指针是一个地址,是一个常量。而指针变量却可以赋予不同的指针(指针也就是地址),是变量。但我们常把指针变量简称为指针。
现在大家明白了吧,指针其实就是地址的别称,而指针变量就是存放这个地址的,所以我们平时说的定义一个指针,就是定义一个指针变量,我们可以给这个指针赋上变量的地址、数组首地址、结构体首地址等等。
!!!另外注意一下指针变量的赋值只能赋予地址。
另外这里介绍两个指针有关的运算符,在下面会用到
(1) &:取地址运算符,一般形式为: &变量名
(2) *:指针运算符(也就是获取该指针所指向的数据),一般形式为: *指针变量了解什么是指针后,我们来了解什么是二级指针,三级指针。
2.二级指针
二级指针则是指向一级指针的指针,也就是说如果一个指针指向的是另外一个指针,我们就称它为二级指针,或者指向指针的指针。如:
int a = 12; int * b = &a; //一级指针 int **c = &b; //二级指针,指针c指向的是指针b,也就是说二级指针c存储的是一级指针b的地址。
这里要说明的是指针变量也是一种变量,也会占用存储空间,也可以使用&获取它的地址,所以二级指针才可以指向一级指针的地址。
3.三级指针
三级指正则是指向二级指针的指针。所以规律就是n 级指针就是 指向 n-1 级指针的 指针
如:int a = 12; int * b = &a; //一级指针 int **c = &b; //二级指针,指针c指向的是指针b,也就是说二级指针c存储的是一级指针b的地址。 int ***d = &c; //三级指针,指针d指向的是指针c的地址
因此我们如果在三级指针前面加一个取地址运算符,也就是&d,则取出的是其自身的存储地址。
而”*d”则是取到指针c的地址,而”**d”则是取到指针b的地址,而”***d”则是取到a地址上的数据。想要获取指针指向的数据时,一级指针加一个*,二级指针加两个*,三级指针加三个*
因为指针相关的知识内容比较多,因此这里只介绍部分~
本人水平有限,上述信息仅供学习参考,如有错误和不妥之处,请多多指教。
另外创作不易,请勿抄袭,如果有帮助到大家的话希望大家可以点个赞,谢谢~更多相关内容 -
c++ 二级指针与二维数组之间值操作
2021-04-18 18:35:17只有6行代码,非常简洁,这是char二级指针给char二维数组赋值的逻辑。二级指针需要先赋值操作,加断点就可以看见二维数组里的值了。 -
C语言中二级指针的实例详解
2020-12-31 08:36:25C语言中二级指针的实例详解 用图说明 示例代码: #include int main(int argc, const char * argv[]) { // int a = 5; int *p1 = &a; //-打印地址-----地址相同--------------- printf(&a = %p\n, &a);//... -
C语言 一级指针与二级指针详细介绍
2021-01-01 03:15:05指针的概念 指针就是地址, 利用这个地址可以找到指定的数据 指针就是地址, 那么在使用的时候, 常常会简单的说 指针变量为指针 指针变量就是存储地址的变量 int *p1;// 申请了一个变量, 即在内存中开辟了一块... -
C语言 二级指针详解及示例代码
2020-09-01 18:59:02本文主要介绍C语言 二级指针,这里整理了C语言中二级指针的基础资料并附有示例代码和实现结果,帮助大家学习理解相关知识,有学习的朋友可以参考下 -
c语言指针之二级指针示例
2021-01-20 06:37:48二级指针的概念 首先任何值都有地址,一级指针的值虽然是地址,但这个地址做为一个值亦需要空间来存放,是空间就具有地址,这就是存放地址这一值的空间所具有的地址,二级指针就是为了获取这个地址,一级指针所关联... -
二级指针
2021-02-01 17:43:08二级指针 二级指针也是一个普通的指针变量,只是它里面保存的值是另外一个一级指针的地址 定义: int guizi1 = 888; int *guizi2 = &guizi1; //1 级指针,保存 guizi1 的地址 int **liujian = &guizi2; //2 ...二级指针
二级指针也是一个普通的指针变量,只是它里面保存的值是另外一个一级指针的地址
定义:
int guizi1 = 888;
int *guizi2 = &guizi1; //1 级指针,保存 guizi1 的地址
int **liujian = &guizi2; //2 级指针,保存 guizi2 的地址,guizi2 本身是一个一级指针变量
#include <stdio.h> #include <stdlib.h> int main(void){ int guizi2 = 888; //存枪的第 2 个柜子 int *guizi1 = &guizi2; //存第 2 个柜子地址的第一个柜子 int **liujian = &guizi1; //手握第一个柜子地址的刘建 printf("刘建打开第一个柜子,获得第二个柜子的地址:0x%p\n", *liujian); printf("guizi2 的地址:0x%p\n", &guizi2); int *tmp; tmp = *liujian; printf("访问第二个柜子的地址,拿到枪:%d\n", *tmp); printf("刘建一步到位拿到枪:%d\n", **liujian); //缩写成 **liujian system("pause"); return 0; }
二级指针的用途
- 普通指针可以将变量通过参数“带入”函数内部,但没办法将内部变量“带出”函数
- 二级指针可以不但可以将变量通过参数函数内部,也可以将函数内部变量 “带出”到函数外部。
#include <stdio.h> #include <stdlib.h> void swap(int *a, int *b){ int tmp =*a; *a= *b; *b= tmp; } void boy_home(int **meipo){ static int boy = 23; *meipo = &boy; } int main(void){ //int x=10, y=100; //swap(&x, &y); //printf("x=%d, y=%d\n", x, y); int *meipo = NULL; boy_home(&meipo); printf("boy: %d\n", *meipo); system("pause"); return 0; }
可以定义多级指针指向次一级指针
比如:
int guizi1 = 888;
int *guizi2 = &guizi1;
//普通指针
int **guizi3 = &guizi2;
//二级指向一级
int ***guizi4 = &guizi3;
//三级指向二级
int ****guizi5 = &guizi4; //四级指向三级
//
有完没完。。。 -
为什么要使用二级指针?
2021-05-19 06:24:17所以,当我们定义了一个指向指针的指针的时候(pointer to pointer),我们也称之为二级指针,那针对于这个二级指针来说,第一级指针存放的是指向的变量的地址,第二级指针存放的是第一级指针的地址。可以用下面这张图...概念
提到指针,我们都知道指针是用来存储一个变量的地址。所以,当我们定义了一个指向指针的指针的时候(pointer to pointer),我们也称之为二级指针,那针对于这个二级指针来说,第一级指针存放的是指向的变量的地址,第二级指针存放的是第一级指针的地址。可以用下面这张图表示他们之间的关系。
上图所表达的意思也就是,一级指针变量 ptr1 存放的是 var 变量的地址,二级指针变量 ptr2 存放的是一级指针变量的地址。这也就是关于二级指针的相关概念。
一级指针与二级指针关系示例
#include
int main(void)
{
int a = 10;
int *p = &a;
int **q = &p;
printf("a = %d\n",a);
printf("&a = %p\n",&a);
printf("p = %p\n",p);
printf("&p = %p\n",&p);
printf("*p = %d\n",*p);
printf("q = %p\n",q);
printf("&q = %p\n",&q);
printf("*q = %p\n",*q);
printf("**q = %d\n",**q);
}
下图是代码运行的结果:
结果也很明显了,一级指针变量 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
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 成员来说它是一个二级指针,对于他的变化,在函数结束时是会产生改变的,所以可以删除中间的结点。
二级指针在单链表结点删除的应用
上面的例子中,在删除单链表的结点的时候吗,我们形参采用的是一级指针的方式,在这个过程中,还需要引入 prv 指针来解决这个问题,还有一种很巧妙的方法,利用了二级指针的特性解决了结点删除的问题,在这个过程中,运用二级指针,不需要进行删除第一个结点的判断。具体代码如下:
void find_and_delete2(ListNode **head,int target)
{
for (; *head != NULL; head = &(*head)->next)
{
if ((*head)->data == target)
{
(*head) = (*head)->next;
break;
}
}
}
上述的代码没有创建任何局部变量,直接利用 head 进行遍历链表,因为其是二级指针,这样子进行遍历在函数结束后不会改变其本身的链表结构。然后,在进行删除的时候,(*head) 在函数结束后是会保持其在函数内的变化值的,所以也就完成了结点的删除。
结论
上述就是关于二级指针的相关内容,总体来说,二级指针也是指针,用指针的思想来处理这个问题就好,区别只是在于一级指针是由于存放普通变量的地址的,二级指针是由于存放指针变量的地址的。另外需要注意的就是 C 语言在进行函数调用时,实参的传递采用的是实参值的一份拷贝。如果要在函数内部改变变量的值,就要传入指针,如果要在函数内部改变指针的值,就需要传入二级指针。
-
c++ 二级指针与二维数组之间值操作升级版
2018-08-28 17:37:24比上一个版本添加二级指针size获取函数,有需要的朋友可以看一下 -
详解C语言-二级指针三种内存模型
2021-01-19 23:55:57二级指针相对于一级指针,显得更难,难在于指针和数组的混合,定义不同类型的二级指针,在使用的时候有着很大的区别 第一种内存模型char *arr[] 若有如下定义 char *arr[] = {abc, def, ghi}; 这种模型为二级指针的... -
c语言初级指针详解,一级指针,二级指针。n级指针
2022-04-04 21:10:281:1级指针 首先在对指针进行理解之前,我们要清楚下面这几个个概念: 1.1:内存的使用 和现实生活对空间的分别方式相似,给不同的地域不同的名称。例如,北京,上海等 而内存也是一块空间,所以对这块空间的...1:1级指针
首先在对指针进行理解之前,我们要清楚下面这几个个概念:
1.1:内存的使用
和现实生活对空间的分别方式相似,给不同的地域不同的名称。例如,北京,上海等
而内存也是一块空间,所以对这块空间的不同位置进行不同的编号,用起来也会更加方便。
这些编号就是我们常说的地址了。
我们都知道 ,内存里最小的内存单元就是一个bit位 ,那多大的内存空间可以分配一块地址呢,在
c语言的标准中规定,给每个字节大小的空间(8个比特位)配置一个专门的地址。
1.2:c语言内存中数据的访问
在c语言中创建一个变量a,那么我们通常是用变量名来访问这个数据,但是也可以用地址来访问这个数据 。那么要怎么通过地址来访问数据呢?????
这里就需要指针了。
1.3:一级指针的定义方式
#include<stdio.h> int main() { //一级指针 int a = 10; int* pa = &a; printf("%d\n", a); printf("%d\n", *pa); return 0; }
int a = 10;//定义一个整形变量,变量中存储的数据是10
int* pa = &a;//* 代表pa是一个指针 最前面的int代表pa指向的变量类型是整形类型1.4:通过指针访问数据。
*pa=1;//代表对pa中的数据(也就是刚才拿到的a的地址)进行解引用,来访问a中的数据。
总结:指针里只能存放地址,地址也只能放置在指针中,对一级指针进行解引用就能通过他里面的地址来访问原变量a中存储的数据
但是要注意 这两种访问的方式并不相同,原因我之前的博客有:
2:二级指针
通过前面的了解我们知道,指针变量里面放置的是地址,而只要是变量,那肯定就有它自己的地址
所以我们来看下面这个例子
2.1二级指针的创建和访问
**ppa也可以看成 *(*ppa) 首先*ppa表示对ppa中的数据进行解引用,就能访问pa中存储的数据 所以*ppa就想当于pa,而对pa进行解引用就能访问a了(在上面的例子我们可以看到这两钟形式打印出的数据一样)
所以 * *ppa 也就相当于 a 了(还是要注意,只是二者的用法类似,为了好理解我们说他们两个相当,但是他们确实还是有区别的)
总结:
一级指针pa里存的是整形变量a的地址,二级指针ppa里存的是一级指针变量pa的地址。
以此类推n级指针的定义和访问方式相同。
-
二级指针传参(函数形参是二级指针)
2021-11-23 21:19:20函数形参是二级指针,可以传入的参数——二级指针变量本身/一级指针变量的地址 #include<iostream> using namespace std; void test1(int **ptr) { cout << **ptr << endl; } void test2(char *... -
浅析一级指针和二级指针、一维数组和二维数组
2020-12-27 21:38:341、说起指针之前,先来看看下面这个例子。 #include <stdio.h> #include <stdlib.h> int malloc_pointer(char *p) { if(p == NULL) { p = (char *)malloc(10); } return 0; } int free_pointer... -
指针详解2:二级指针与指针数组
2022-01-05 11:30:56二级指针,顾名思义,是个二次的指针,也就是指向指针的指针 基本类型如下: int** p; 我们来看一段代码: void d_pointer() { int a = 10; int* pa = &a;//pa是一个指针变量,变量有地址,所以有&pa ... -
二级指针、指针数组
2022-01-30 11:48:39二级指针、指针数组 -
1.二级指针
2022-03-07 21:35:18如果一个指针指向的是另一个指针,我们就称它为二级指针,或者指向指针的指针。 二级指针存放的是一级指针的地址,一级指针存放的是变量的地址,变量存放的是数值。 只要是指针,均占4个字节 2.举一反三 ... -
链表中为何使用二级指针
2020-06-06 00:12:02本篇目录前言参数的调用方式传值调用传址调用传引用调用示例说明使用二级指针/一级指针创建链表时的对比主函数中作此调用使用二级指针创建链表使用一级指针创建链表会成功吗销毁链表时二级指针和一级指针的对比使用... -
一级指针与二级指针
2019-08-17 23:34:36一、一级指针 如下图所示,整型指针xptr指向变量x的地址。 int *xptr; int x=10; xptr = &x; 源码: #include <stdio.h> int main() { int *xptr = NULL; int x = 10; xptr = &x; printf... -
指针数组与数组指针与二级指针
2010-12-14 20:58:59指针与二维数组 数组指针 指针数组 多级指针 -
【C语言】深入理解二级指针
2021-11-15 16:29:31文章目录(一)指针的定义(二)引入二级指针(三)深入理解二级指针(1)下面举个例子:(2)在(1)的前提下,那要是把所有的类型换成char、short、double类型呢(四)总结 (一)指针的定义 一级指针:是一个... -
C语言学习之二级指针与指针数组的关系
2020-10-19 15:22:05一、引言 指针,对于C语言学习者,... 二级指针:存储一级指针地址的指针 数组:包含给定类型的一些对象,并将这些对象依次存储在连续的内存空间中。 一维数组:相对于多维数组,只有一维,用数学的思维,可以... -
利用二级指针进行链表操作
2018-10-19 10:27:38常规的链表删除除了当前的遍历指针还需要维护一个prev指针,用来连接被删除节点的下一个节点,但实际上利用二级指针就可以避免多维护一个指针,使代码更加简洁。Linus的吐槽没错,到目前为止,我几乎没有在实际工作... -
如图,为什么单链表初始化需要二级指针,而单链表的插入操作不用二级指针?
2020-03-04 11:38:16# 而单链表的插入操作同样需要改变指针指向,为什么不需要用二级指针? # 是因为不需要改变头指针指向所以不用传址吗? # 下面... -
C:一级指针与二级指针的详解
2019-10-29 15:04:431.指针和数组 指针是个用来存放地址的变量; &arr表示整个数组; arr数组名表示首元素的地址;...一级指针就是指指针,里面放的就是元素的地址,我们可以通过访问元素的地址来找到该地址里存放的内... -
一级指针和二级指针的区别与应用
2021-06-04 14:05:56一级指针:就是指针,即一个指向一块内存的地址,有了这个地址,我们就可以对这块内存进行读写操作 ...二级指针:指针的指针,也就是指向一块内存的指针的地址,因为指针本身也有自己的存储地址 ...