C语言——详解二级指针及其与二维数组的误区、指针定义大全

C语言中的二级指针(也称为指针的指针)是指一个指针变量,它存储的不是普通的值,而是另一个指针的地址。这意味着你可以通过二级指针来访问和修改另一个指针的值。这种结构在C语言中非常有用,尤其是在处理动态内存分配、数组、链表等复杂数据结构时。

指针变量本质上也是一个变量,包含变量类型,变量值,变量地址,变量名四个要点。指针变量与其他变量不同的地方是,指针变量的值是一个地址,我们把指针变量称为指向其保存的地址的指针。而指针变量本身也有一个地址,此时如果有另一个变量b保存的是这个指针a的的地址,那么这个变量b也是指针变量,且是二级指针。

定义二级指针

在C语言中,定义一个二级指针的语法如下:

int **ptr;

这里,ptr 是一个指向 int* 类型的指针的指针,即它是一个指向指针的指针,而这个指针又指向一个整型值。

使用二级指针

示例1:通过二级指针修改指针的值
#include <stdio.h>  
  
int main() {  
    int a = 5;  
    int *p = &a;  // p 是一个指向 int 的指针  
    int **pp = &p; // pp 是一个指向 p(也就是指向 int* 的指针)的指针  
  
    printf("原始值: %d\n", *p); // 通过 p 访问 a 的值  
    p = &a + 1; // 假设这样做只是为了演示(实际上这样做是危险的,因为可能越界)  
    printf("修改 p 后的值(但尚未通过 pp 修改): %d\n", *p); // 此时 p 指向未知的内存  
  
    *pp = &a; // 通过 pp 修改 p 的值,使其重新指向 a  
              //pp存放的是p的地址。*pp即对pp值=p的地址解引用,得到p的值=a的地址
    printf("通过 pp 修改 p 后,p 指向的值: %d\n", *p);  
  
    return 0;  
}

注意:在实际编程中,直接修改指针使其指向未知的内存(如示例中的 p = &a + 1;)是非常危险的,因为它可能导致未定义行为。

示例2:二级指针与指针函数的转换

当一个指针函数即这个函数会返回一个指针变量的时候,我们可以在main函数中定义一个指针代替需要返回的指针,在被调用的指针函数中定义一个二级指针的形参,将需要修改的指针变量的地址传递过去,在调用的函数中对这个指针进行修改以实现指针函数的目的,这是就不需要指针函数了,使用普通的 void 函数即可。

这是一个指针函数的示例:

#include<stdio.h>

int* getPose(int stu,int (*pstu)[4]) //因为需要将存储学生分数的数组score传过来,因此我们定义了一个数组指针pstu
{
	int *p;
	
	p = (int *)(pstu + stu);  //pstu代表的是二维数组score的数组名首地址,因此他是按行偏移的,偏移地址为stu*N
	                 //而定义的p为整型指针4个字节,因此会有警告。使用(int *)强制转换可解决,因为我们在这里关心的是首地址,警告不影响我们程序结果
	return p;
}

int main()
{
	int score[3][4] = {{98,99,97,100},      //每行代表一个学生的四项成绩
		               {56,58,59,59},
					   {85,89,87,88}};
	int *pstu;
	int stu;
	
	printf("请输入你要查询的学生序号:0、1、2\n");
	scanf("%d",&stu);

	pstu = getPose(stu,score);  
	for(int i=0;i<4;i++){
		printf("%d ",*pstu++);
	}
	return 0;
}

在上述示例中,我们使用了一个指针函数用来返回一个指针变量pstu,他代表着查询到的学生的成绩的那一行的首地址。接下来我们使用二级指针代替指针函数:

#include<stdio.h>
#include<stdlib.h>

void getPose(int stu,int (*pscore)[4], int **ppos) 
{
	*ppos = (int *)(pscore + stu);  
}

int main()
{
	int score[3][4] = {{98,99,97,100},      //每行代表一个学生的四项成绩
		               {56,58,59,59},
					   {85,89,87,88}};
	int *pstu;
	int stu;
	
	printf("请输入你要查询的学生序号:0、1、2\n");
	scanf("%d",&stu);

	getPose(stu,score,&pstu);  
	for(int i=0;i<4;i++){
		printf("%d ",*pstu++);
	}
	return 0;
}

在这段代码里边,我们将main函数中的指针pstu的地址传递给函数getPose,因此getPose函数的形参中是一个二级指针,用来接收指针pstu的地址,在getPose函数中,我们 *ppos即对ppos的值= pstu的地址解引用,获得指针pstu的值并将查询到的学生的成绩的那一行的首地址赋给他,就将getPose函数中的操作保留到了main函数中。

这个操作有点类似局部变量的概念,在 a 函数中对变量的操作如果想保留到 b 函数中时,就需要将这个变量的地址作为实参传递给 a 函数,因此指针变量也是同理,需要将指针的地址传递过去,那就需要一个保存指针变量地址的变量 = 一个指向指针的指针 = 二级指针。

二级指针与二维数组的误区:

示例:

#include<stdio.h>

int main()
{
	int score[3][4] = {{98,99,97,100},      
		               {56,58,59,59},
					   {85,89,87,88}};
	int **p;
	
	p = score;
	printf("score=%p\n",score);
	printf("p=%p\n",p);
	printf("*p=%p\n",*p);  //*p是一个野指针
	return 0;
}

输出:

score=000000000061FDE0
p=000000000061FDE0
*p=0000006300000062

 从概念上来讲,p的值是score,是数组的行首地址,*p应该是一个指针指向数组的首列地址。但是从输出来看*p是一个野指针,同时也没办法通过这种方式对数组的数据进行操作,也就是说C语言不允许我们这么使用二级指针对二维数组进行访问与操作。我们可以先将二维数组定义为一个数组指针,再将数组指针的地址赋给二级指针,再进行操作即可,但是一般不这么做,更改二维数组数据直接使用数组指针即可。示例:

#include<stdio.h>

int main()
{
	int score[3][4] = {{98,99,97,100},      
		               {56,58,59,59},
					   {85,89,87,88}};
	int (*p)[4] = score;
	int **p2;
	
	p2 = &p;
	**p2 = 100;  //能用但一般不这么用
	printf("score=%p\n",score);
	printf("*p2=%p\n",*p2);
	printf("**p2=%d\n",score[0][0]);
	return 0;
}

输出:

score=000000000061FDE0
*p2=000000000061FDE0
**p2=100

指针定义大全:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hardStudy_h

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值