年末再看指针。看来搞C/C++,如影随形的指针就得门清~~~
创始人
2024-05-03 18:22:16
0

继上篇博文因内核页表引出的指针问题,后来又研究了一番,这次应该比较清楚了,这里再总结一下。

目录

0 前言

1 普通指针:

2 指针的指针:

3 普通指针参数:

4 指针的指针参数:

5 函数指针:

6 指针函数:

7 指针数组:

8 数组指针:

9 其他:


0 前言

对于C/C++的学习和使用者而言,指针的重要性不言而喻。这不仅是初学者比较难理解的概念,也是很多老手容易犯错的地方。甚至因为过于灵活,容易引发问题,而发明了许多其他规避指针的语言。这从另一个角度说明,要掌握C/C++,指针是绕不过的。

C/C++里与指针有关的概念比较多,这里简单总结几个:

1 普通指针

定义一个指针变量,让其指向一个对应类型的变量。比如:

int *p;
int a;
p = &a;

这里定义了一个int指针变量和一个int的变量a,然后将a的地址给指针变量p,如此,就表示指针变量p指向了变量a。

 

2 指针的指针

定义一个指针变量,让其指向一个指针变量。比如:

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

这样,指针变量pp指向一个指针变量p,p又指向一个变量a。这是二级结构。当然还可以定义三级、四级等等,道理是一样的,不过会显得更加绕一些,使用和理解都比较费劲,实际中用的不多。

 

3 普通指针参数

在函数的参数传递中,使用指针变量。比如:

void func(int *pointer);
int *p;
int a;
p = &a;func(p);

定义一个指针变量,指向a,定义一个带指针变量参数的函数func,调用时,传递p。我们知道,函数的参数传递是通过栈结构完成的,通过拷贝进行,这种传值方式可以分为两种,普通变量,传变量值本身,指针变量,传地址值。对于上面的函数,效果如下图:

 函数参数相当于是函数里定义的一个新变量,所以如上图,pointer跟p并不是一个变量,p传递给函数后,就是将p指向的变量a的地址给了函数参数变量pointer。这样,pointer也就指向了变量a。

4 指针的指针参数

在函数参数传递时,使用指针的指针变量。如下:

void func(int **ppointer) {int *p = (int *)malloc(1024);/*p[0] = xx;p[1] = yy;...*/*ppointer = p;
}int *p;
func(&p);

从前面函数传参的原理可以看出,使用指针变量,虽然可以在函数里修改函数外面的内存,但是不能将函数里的内存传递出去。要做到这点,就需要使用指针的指针变量做参数。效果如下图:

参数ppointer获得了p的地址,也就是指向了p。而在函数里,可以对ppointer的内容做处理,也就是操作了p。这样,函数执行结束后,p指向了我们需要的地方。

5 函数指针

是一个指针,只不过这个指针指向一个函数。如下:

int (*pfunc)(int a);int func (int a) {return a+1;
}pfunc = func;pfunc(1); //return 2;

函数名可以理解为函数所表示的一串汇编代码的开始地址。上面代码定义了一个函数指针pfunc,指向拥有一个int参数,返回int类型的函数。另外,实际定义了一个函数func,然后让上述函数指针pfunc指向func,也就是指向了这个函数的开始位置。最终,调用pfunc,执行func函数代码。效果如下图:

6 指针函数

是一个函数,只不过返回值是一个指针。如下:

int *func(int a) {int *p = (int *)malloc(a);return p;
}

我们可以将内存分配函数本身也看做是一个指针函数,返回分配内存的首地址。

7 指针数组

是一个数组,数组的每一个元素是指针。如下:

int* parray[10];
int *p;
int a;
p = &a;parray[0] = p;
...

代码定义了一个指针数组,效果如下图:

8 数组指针

是一个指针,指向数组。代码如下:

int (*p) [2];
int array0[2];
int array1[2];
p[0] = array0;
p[1] = array1;

代码中定义了一个数组指针,指针指向含有两个int类型元素的数组。效果如下图:

9 其他:

大家可能觉得函数指针、指针函数,数组指针、指针数组不容易记住,不容易区分。这里有一个技巧,就是谁在后面,就是谁前面是一个修饰。比如,指针函数,函数在后面,就说这是一个函数,前面的指针是修改其返回值为指针。再比如,数组指针,指针在后面,就说明这是一个指针,前面用数组修饰,那么说明指针指向的是数组。

对于普通的指针,有三个与其相关的元素:指针的地址,指针本身和指针的内容。它们的关系如下图:

比如,如上图,一个指针变量p,其地址为123,123地址所在内存内容为456,是p本身的地址。p的内容为789,是所指向变量的地址,789地址内存处就是具体变量的值。

但是这处不能钻牛角尖。因为,对于指针和数组,有一些变通之处。我们知道,数组名是数组的首元素的地址,那么对于一个数组变量array, array 的值等于 &array[0]。进一步的,&array的值是什么呢?从含义上来讲,编译器会将其解释为数组的地址,这样看,其值本身跟array和&array[0]是相等的,但是含义不同。同样的,对于数组指针变量p, p指向数组,p的值就是数组的地址,自然也是数组首元素的地址。&p同样代表了数组的地址,自然跟p的值是相同的。*p同样代表了其指向的数组的值,自然也是数组的地址,所以跟p的值仍然是相同的。也就是这种情况下,p和&p和*p的内容是相同的。如果非要找出他们的不同,我们要从其含义上来理解其不同。

上面所述,最本质的理解是要注意:指针和数组并不同,即使在某些情况下值相同,但是表达的含义很可能不同。

关于上面的指针、数组、数组指针的取地址&和取内容*操作的值,可以通过下面的代码验证:

#include 
#include typedef int pgd_t[2];int main(int argc, char**argv) {int s[4];s[0] = 0x87654321;s[1] = 0x12345678;s[2] = 0x11112222;s[3] = 0x33334444;int testMem[4];testMem[0] = (unsigned int)s[0];testMem[1] = (unsigned int)s[1];testMem[2] = (unsigned int)s[2];testMem[3] = (unsigned int)s[3];pgd_t *pgd = NULL;pgd = (pgd_t *)testMem;//pgd = (pgd_t *)&testMem;int (*arrayPointer)[2];arrayPointer = pgd;int *p = NULL;p = &s[1];printf("\n");printf("Test pgd  : pgd is %lx,        pgd content is %lx,           pgd1 is %lx,          pgd1 content is %lx \n", (unsigned long)pgd, (unsigned long)(*pgd), (unsigned long)pgd[1], (unsigned long)(*(pgd+1)));printf("\n");printf("Test pgd  : pgd0 content is %lx,        pgd1 content is %lx ,          pgd0 addr is %lx,       pgd1 addr is %lx\n", (unsigned long)pgd[0], (unsigned long)pgd[1], (unsigned long)&pgd[0], (unsigned long)&pgd[1]);printf("\n\n");printf("Test mem  : array is %lx,      addr is %lx,      elem 0 addr is %lx,     elem 0 content is %x \n", (unsigned long)testMem, (unsigned long)(&testMem), (unsigned long)&testMem[0], (unsigned int)testMem[0]);printf("\n");printf("Test mem  : array is %lx,      addr is %lx,      elem 1 addr is %lx,     elem 1 content is %x \n", (unsigned long)testMem, (unsigned long)(&testMem), (unsigned long)&testMem[1], (unsigned int)testMem[1]);printf("\n");printf("Test mem  : array is %lx,      addr is %lx,      elem 2 addr is %lx,     elem 2 content is %x \n", (unsigned long)testMem, (unsigned long)(&testMem), (unsigned long)&testMem[2], (unsigned int)testMem[2]);printf("\n");printf("Test mem  : array is %lx,      addr is %lx,      elem 3 addr is %lx,     elem 3 content is %x \n", (unsigned long)testMem, (unsigned long)(&testMem), (unsigned long)&testMem[3], (unsigned int)testMem[3]);printf("\n\n");printf("Test local: local s0 is %lx,         local s1 is %lx,        local s2 is %lx,        local s3 is %lx,        local s is %lx \n", (unsigned long)&s[0], (unsigned long)&s[1], (unsigned long)&s[2], (unsigned long)&s[3], (unsigned long)&s);printf("\n\n");printf("Test normal pointer, p is %lx,       p addr is %lx,          p content is %lx \n",(unsigned long)p, (unsigned long)&p, (unsigned long)(*p));printf("\n");return 0;
}

执行结果为:

这其中的差异,相信读者可以从中找到答案。

相关内容

热门资讯

安卓系统8.0镜像下载,轻松打... 你有没有想过,想要给你的安卓手机升级到最新的系统,却不知道从哪里下载那个神秘的安卓系统8.0镜像呢?...
安卓系统修改大全,全方位修改大... 你有没有想过,你的安卓手机其实是个大宝藏,里面藏着无数可以让你手机焕然一新的秘密?没错,今天就要来个...
安卓刷miui系统教程,安卓刷... 你有没有想过给你的安卓手机换换口味?别看它现在用得挺顺手的,偶尔来点新鲜感也是不错的。今天,就让我来...
超星学系统安卓版,便捷学习新体... 你有没有发现,学习生活越来越离不开电子设备了?手机、平板,这些小玩意儿简直就是我们的学习小助手。今天...
安卓平板6.0系统安装,轻松上... 你有没有想过,你的安卓平板6.0系统是不是该升级一下了呢?别看它现在看起来还挺精神的,但谁知道背后隐...
安卓系统屏幕显示文字,探索个性... 你有没有发现,手机屏幕上的文字有时候会变得模糊不清,或者颜色暗淡,让人看得很费劲?这可真是让人头疼的...
快递扫描系统下载安卓,便捷物流... 你有没有想过,每次快递员来送快递,他们是怎么快速找到你的包裹的呢?是不是觉得他们有超能力?其实,这背...
安卓系统能打开zip,操作指南... 你有没有想过,你的安卓手机里那些神秘的zip文件到底怎么打开呢?别急,今天就来给你揭秘这个小小的技术...
塞班怎么查找安卓系统,塞班系统... 你有没有想过,你的塞班手机里竟然也能装上安卓系统?听起来是不是有点神奇?别急,今天我就来手把手教你如...
安卓系统短消息提醒,安卓系统短... 你有没有发现,手机里的短消息提醒功能有时候就像一个贴心的管家,有时候又像个爱闹腾的小孩子?今天,咱们...
安卓系统如何跳过密码,安卓系统... 你是不是也和我一样,有时候手机锁屏密码设置得太复杂,每次解锁都要费好大一番力气?别急,今天就来教你怎...
鸿蒙系统功能与安卓,功能对比与... 你知道吗?最近手机圈里可是热闹非凡呢!华为的新操作系统鸿蒙系统(HarmonyOS)一经推出,就引发...
安卓系统卡苹果系统不卡,揭秘两... 你有没有发现,身边的朋友都在争论安卓系统和苹果系统哪个更好?其实,这个问题就像是在问谁家的孩子更聪明...
安卓系统卡解决了吗,安卓系统卡... 你有没有遇到过安卓手机卡顿的问题?是不是每次打开应用都感觉像蜗牛爬行?别急,今天就来聊聊这个让人头疼...
华为安卓系统下载软件,畅享海量... 你有没有想过,手机里的系统就像是我们的大脑,而下载的软件就像是大脑里的各种功能?今天,就让我带你一起...
平板安卓7系统好吗,体验流畅与... 你有没有想过,你的平板电脑的安卓7系统到底怎么样呢?是不是觉得它既熟悉又有点陌生?别急,今天咱们就来...
鸿蒙系统和安卓10,跨时代操作... 你知道吗?最近科技圈可是炸开了锅,因为华为的新操作系统鸿蒙系统横空出世,而且它竟然和安卓10杠上了!...
苹果安卓和鸿蒙系统,三大操作系... 你有没有发现,现在的手机市场就像是一场精彩纷呈的武林大会,各路英雄齐聚一堂,各显神通?没错,说的就是...
鸿蒙怎么还原安卓系统,系统还原... 你是不是也和我一样,对鸿蒙系统里的安卓应用情有独钟呢?最近,不少小伙伴都在问,鸿蒙怎么还原安卓系统?...
荣耀10改回安卓系统,重拾纯净... 你有没有想过,你的荣耀10手机,曾经那般风光无限,如今却想要改回安卓系统呢?这可不是一件小事,得好好...