指向指针的指针(二级指针)理解

news/2024/7/4 8:27:30

指向指针的指针(二级指针)理解

    • 在子函数中修改主函数传过来的指针的指向
    • 二维数组数和指针操作
    • 转载链接

在子函数中修改主函数传过来的指针的指向

#include<stdio.h>
void F1(int *pp)
{
	pp++;
	*pp = 9;
}
 
void F2(int **pp)
{
	(*pp)++;
}
//以上函数中,接收数据的参量都是pp,而不会是*pp或者**pp
 
int* F3(int *pp)
{
	pp++;
	return pp;
}
 
 
int main(void)
{
	int *p;
	int a[2] = { 4,5 };
	p = a;
	printf("1--------%d\n", *p);//开始值为4
 
	F1(p);
	printf("2--------%d\n", *p);//4
	//由于只是传值,在子函数F1的内部改变复制品的值,并不会改变原品p的值
	//可以理解为用两个变量指向同一个地址,即形参pp和实参p指向同一个地址
	//其中形参pp++,另外一个实参p并不会受影响
	//但是可以修改指针所指的值,如F1代码中将a[1]的值改为9;
	printf("2`-------%d\n", a[1]);//9
 
 
	F2(&p);
	printf("3--------%d\n", *p);//9
	//传址,pp=&p(指针的地址,即pp是指向指针的指针),*pp=*(&p)=p;
	//如果要修改指针p,则应该传入指针p的地址(&p),此时进行*pp++操作,其实是对实参指针p进行操作
 
	getchar(); getchar();
	return 0;
}
 
//这个例子说明:如果要在子函数中修改主函数传过来的指针的指向,那么主函数应该向子函数传入指针的地址(而非指针本身);
//此时在子函数中进行*操作后可以获得原来指针,而不是原来指针的复制品,之后可以根据需要修改指针。
//或者,将返回值类型改为指针类型,然后返回修改后的指针,给原来主函数的指针,如F3函数,此时在主函数中需要添加p=F3(p)代码。

    这个例子说明:如果要在子函数中修改主函数传过来的指针的指向,那么主函数应该向子函数传入指针的地址(而非指针本身);此时在子函数中进行*操作后可以获得原来指针,而不是原来指针的复制品,之后可以根据需要修改指针。或者,将返回值类型改为指针类型,然后返回修改后的指针,给原来主函数的指针,如F3函数,此时在主函数中需要添加p=F3(p)代码。
在这里插入图片描述

二维数组数和指针操作

#include<string.h>
#include <stdio.h> 
int main(void)
{
	int a[4][2] = { { 2,4 },{ 6,8 },{ 1,3 },{ 5,7 } };
	char *p[5] = { "acvsadf", "cwerqwenn", "tttttt" };//字符串指针数组
	int c[4] = { 0,1,2,3 };
	int *ptr = c;
	/*
	这个正确,说明a[0]是一个地址,而且只指向一个int类型;
	也说明它是一维数组(这个数组有两个元素,即2和4)的首元素(这里是2)的地址;
	+1会加上4个字节,即一个int类型的大小;
	*/
	int *p1 = a[0];
	//int (*p2)[2] = a[0];//error
	
 
	/*
	这个正确,说明&a[0]是一个地址,而且指向一个包含两个int元素的数组;
	也说明它是数组(这个数组有4个元素,分别{ 2,4 },{ 6,8 },{ 1,3 },{ 5,7 })首元素(这里是{2,4})的地址;
	+1会加上8个字节,即两个int类型的大小;
	*/
	int(*p3)[2] = &a[0];//[]表示的是该指针指向数组,而数组里面有[?]个元素
	int(*p4)[2] = a;//这个说明&a[0]和a性质是一样的。
	//int (*p5)[8] = &a;//error
	//int (*p6)[4] = &a;//error
	
	
	//int* p7 = &a;//怎样指向整个数组?
	int* p8 = (int*)a;//这样就达到了对整个数组的访问,这种访问方式和访问一维数组无异。
 
	printf("数组名操作:\n");
	printf("1------------\n");//这些地址是一样的
	printf("%p\n", a);
	printf("%p\n", &a[0]);
	printf("%p\n", a[0]);	
	printf("%p\n", &a);
	
	printf("2------------\n");//a,&a[0]
	printf("%p\n", a + 1);//a表示数组(退化为1维数组,看做有4个元素)的首元素地址,这里的元素指{2,4},+1会加上8个字节
	printf("%p\n", &a[0] + 1);//这里&a[0]和a的性质一样
	printf("%p\n", &a[1][0]);
	
	printf("3------------\n");//a[0]
	printf("%p\n", a[0] + 1);//这里a[0]表示一维数组(这个数组有两个元素,即2和4)的首元素的地址,+1会加上4个字节
	printf("%p\n", &a[0][1]);
	
	printf("4------------\n");//&a
	printf("%p\n", &a + 1);//这里&a表示整个数组的首地址,+1会加上8*4=32个字节
 
	printf("5------------\n");
	printf("%d\n", a[0]); //a[0]为啥不是a[0][0]的值?因为它仅是指针,是a[0][0]的地址
	printf("%d\n", *a[0]);//*a[0]表示的是a[0][0]
	printf("%d\n", **a);  //*a表示a[0](因为从前面可知a表示&a[0]),**a表示a[0][0]
	printf("%d\n", a[0][0]);
 
	printf("\n指针操作:\n");
	printf("%p\n", p1 + 1);//和3一样
	printf("%p\n", p3 + 1);//和2一样
	printf("%p\n", p4 + 1);//和2一样
 
	//char *p[5] = { "acvsadf", "cwerqwenn", "tttttt" };//字符串指针数组
	printf("\n字符串指针数组操作:\n");
	
	/*
	首先明确这里的p和&p[0]性质一样,则*p即为p[0];
	p+1即为&p[0]+1,也就是&p[1],则*(p+1)即为p[1];
    &p[0]可以看做是一个指向一个数组的指针,+1要加上整个数组的大小。
	*/
	printf("p               = %s\n", p); //乱码
	printf("*p              = %s\n", *p); //"acvsadf"
	printf("(*p)+1          = %s\n", (*p) + 1);//"cvsadf",*p即为p[0],p[0]是指向char类型的指针,因此+1是移动一个char长度单位
    printf("p[0]+1          = %s\n",  p[0]+1); //"cvsadf",和上面一个应该一样
	printf("*(p+1)+1        = %s\n",  *(p+1)+1);//“werqwenn”
	printf("*(p + 1)        = %s\n", *(p + 1));//“cwerqwenn”,注意这里是一个指针,因此是%s打印
	printf("**(p + 1)       = %c\n", **(p + 1)); //‘c’,注意这里已经是完全解引用了,因此是%c打印得到一个字符
	printf("*(p[1] + 1)     = %c\n", *(p[1] + 1)); //‘w’
	printf("*(*(p + 1) + 1) = %c\n", *(*(p + 1) + 1));//'w',注意这里已经是完全解引用了,因此是%c打印得到一个字符
 
 
	/*
	int c[4] = { 0,1,2,3 };
	int *ptr = c;
	*/
	printf("\n一维数组的操作:\n");
	printf("1-------------\n");//地址都一样
	printf("&c   = %p\n", &c); 
	printf("c     = %p\n", c);
	printf("&c[0] = %p\n", &c[0]);
 
	printf("2-------------\n");
	printf("&c    = %d\n", &c);
	printf("c     = %d\n", c);
	printf("&c[0] = %d\n", &c[0]);
 
	printf("3-------------\n");
	printf("&c+1    = %p\n", &c+1);//&c表示整个数组的开始地址,+1的话,会跨越整个数组
	printf("c+1     = %p\n", c+1);//c和&c[0]性质一样,都表示首元素的地址
	printf("&c[0]+1 = %p\n", &c[0]+1);//后两个应该一样
 
	printf("4-------------\n");
	printf("*ptr     = %d\n", *ptr);//0
	printf("*(ptr+1) = %d\n", *(ptr+1));//1
	printf("c[0]     = %d\n", c[0]);//0
 
	getchar();
	return 0;
	
}

转载链接

函数参数的值传递和地址传递
二维数组数和指针操作的理解
C语言二级指针(指向指针的指针)详解


http://www.niftyadmin.cn/n/1339343.html

相关文章

Node环境下运用grunt合并、压缩js文件

2019独角兽企业重金招聘Python工程师标准>>> 打开cmd命令行 输入 node - v 显示当前版本号 npm - v 显示npm版本号 Node.js中npm怎么通过淘宝镜像安装模块&#xff1f; #先安装 npm install cnpm -g完了以后直接通过 cnpm 来替换 npm 使用即可 $ npm install -g …

【python标准库学习】re模块

2019独角兽企业重金招聘Python工程师标准>>> 1.什么是re 正则表达式一门相对通用的语言&#xff0c;在python中也有对正则表达式的支持&#xff0c;那就是的内置re模块。正则表达式就是一系列的规则去匹配字符串然后进行相应的操作&#xff0c;这些规则网上一搜一大…

C++函数后面加“:”的含义

C函数后面加“&#xff1a;”的含义在成员函数后面在构造函数后对父类进行初始化对类成员进行初始化对类的const成员变量进行初始化参考链接在成员函数后面 c成员函数后面跟“&#xff1a;”表示的是赋值&#xff0c;这是c的特性&#xff1a; A( int aa, int bb ):a(aa),b(bb…

C++ 互斥锁std::mutex的使用

mutex&#xff08;互斥量&#xff09;是一个可以处于两态之一的变量:解锁和加锁。这样&#xff0c;只需要一个二进制位表示它&#xff0c;不过实际上&#xff0c;常常使用一个整型量&#xff0c;0表示解锁&#xff0c;而其他所有的值则表示加锁。互斥量使用两个过程。当一个线程…

Spring透过ApplicationListener来触发contextrefreshedevent事件

Spring通过ApplicationListener接口来触发contextrefreshedevent事件在开发时有时候需要在整个应用开始运行时执行一些特定代码&#xff0c;比如初始化环境&#xff0c;准备测试数据、加载一些数据到内存等等。在Spring中可以通过ApplicationListener来实现相关的功能&#xff…

C++函数默认参数(函数传入实参个数比形参个数少)

C函数默认参数定义参数添加顺序注意事项转载链接定义 在C中&#xff0c;定义函数时可以给形参指定一个默认的值&#xff0c;这样调用函数时如果没有给这个形参赋值&#xff08;没有对应的实参&#xff09;&#xff0c;那么就使用这个默认的值。也就是说&#xff0c;调用函数时可…

期权有哪些坑,你知道吗?

本文为纯原创文章,应朋友邀请而编写。文章花费了笔者大量的精力投入。琢磨着如何行文&#xff0c;怎么样通俗点&#xff0c;提炼出有用的观点来&#xff0c;放在标题中。目标的解决广大求职者的最关心的问题。 转载请注明来源地址。 一、概念理解篇 1、理解A股、B股、C股等 2、…

Django 过滤器 实例

实例&#xff11; safe让Html标签以及一些特殊符号&#xff08;如<&#xff09;生效&#xff0c;下面以例子说明&#xff1a; # value <b>CPT</b># 那么输出的时候&#xff0c;CPT就是加粗的&#xff0c;如果不加safe那么显示出来的就是纯文本<b>CPT<…