指针

指针(what)

指针就是存放地址的变量。(本质)
指针是一个大小固定为4个byte的变量,不管是什么类型的指针大小都是固定的,因为存放是一个地址信息。

通俗易懂的比喻:
一个教室是个变量,这个教室名叫高数教室(变量名a),教室里可以放进学生(赋值内容a=10)。
这个教室的地址为2栋3楼1号房间(指针存放的内容为231)。
当你去到这个学校,你可以问“别人”高数教室在哪里,或者直接查找地址簿(指针)看看这个教室在哪里。
区别是信息的大小,当教室名字很复杂时(xx省xx市xx学校的xx教室),会浪费查找的时间,而地址则不然。

指针的类型

从语法上来看,我们只要把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。

int *ptr;         //指针的类型是 int*
char *ptr;        //指针的类型是 char*
int **ptr;        //指针的类型是 int**
int (*ptr)[3];    //指针的类型是 int(*)[3]
int *(*ptr)[4];   //指针的类型是 int*(*)[4]

指针和p, p+1, *(p+1), *P+1, p[0], &p[0]每一种表达式的含义(看懂下面的代码)

p
void main()  
{
	int a = 1;
	char b = 'a';
	int* i = &a;//指向一个int值变量
	char* c = &b;//指向一个char值变量		
}

在这里插入图片描述
从上面的程序中可以看出来,定义一个int类型的指针和char类型的指针,但它们的大小都是4byte,因为存放的是对应类型变量的地址而不是对应类型变量的内容

指针P与指针P+1
void main()  
{  
      int a[] = {1,2,3,4};
      int* b = (int*)&a;
}

在这里插入图片描述
在上面的程序中定义一个int类型的指针(在这里要重点强调一下,这里是int类型的指针,对后面的内容的理解很重要),指针b的地址为0x0018ff38,指针b+1的地址为0x008ff3c,他们中间相隔了4byte,刚好是一个int类型的大小,而指针b又是一个int类型的指针,所以我们可以得出一个结论:
指针P+1 = 指针P + sizeof(指针的类型) * 1

数组和指针(结合上面)

在上面的运行结果中,我们可以发现a[1]和*(p+1)得到的值是一样的,因为**&a[1]指向的地址和P+1指向的地址是一致**。

在C语言中获得数组的值有两种方法:

第一种:匿名方法 --> a[1]

第二种:具名+匿名方法 --> P + sizeof(数组类型)*1

指针数组

指针变量可以用来存储一个内存地址,数组可以用来存储一组相同类型的数据,那么,如果我们需要存储多个相同类型的变量的地址,应该用什么呢?答案就是指针数组。

顾名思义,指针数组就是每个数据元素都是一个指针的数组,每个数据元素中存储一个指针,他们的基类型必须相同。比如说,一个int *p可以指向一个整数(如int a=5;p=&a;),也可以指向一个一维整型数组中的元素(如 int a[5]={1,2,3,4,5}; p=a+1;),那么由n个int *元素组成的数组int *a[5]就可以指向五个整型变量或者一维整型数组的内存空间,实现类似一个五行若干列的二维整型数组的数据存储,但是每行的元素个数需要存储在一个数组中以便于对数组的正确访问。当类型为char *[]的字符型指针数组在这种应用情景中就比较简单了,由于字符串自带’\0’字符表示字符串的结束,因此一个一维字符指针数组可以实现二维字符数组的数据存储。

多次指针 &a 、a 、*a 、**a 、***a

指针可以指向一份普通类型的数据,例如 int、double、char 等,也可以指向一份指针类型的数据,例如 int * 、double *、char * 等。

如果一个指针指向的是另外一个指针,我们就称它为二级指针,或者指向指针的指针。

假设有一个 int 类型的变量 a,p1是指向 a 的指针变量,p2 又是指向 p1 的指针变量,它们的关系如下图所示:

在这里插入图片描述
将这种关系转换为C语言代码:

int a =100;
int *p1 = &a;
int **p2 = &p1;

指针变量也是一种变量,也会占用存储空间,也可以使用 # 获取它的地址。C语言不限制指针的级数,每增加一级指针,在定义指针变量时就得增加一个星号 * 。p1 是一级指针,指向普通类型的数据,定义时有一个 * ;p2 是二级指针,指向一级指针 p1,定义时有两个 *

如果我们希望再定义一个三级指针 p3,让它指向 p2,那么可以这样写:

int ***p3 = &p2;

四级指针也是类似的道理:

int ****p4 = &p3;

实际开发中会经常使用一级指针和二级指针,几乎用不到高级指针。

想要获取指针指向的数据时,一级指针加一个 * ,二级指针加两个 * ,三级指针加三个 * ,以此类推,请看代码:

#include <stdio.h>
int main(){
    int a =100;
    int *p1 = &a;
    int **p2 = &p1;
    int ***p3 = &p2;
    printf("%d, %d, %d, %d\n", a, *p1, **p2, ***p3);
    printf("&p2 = %#X, p3 = %#X\n", &p2, p3);
    printf("&p1 = %#X, p2 = %#X, *p3 = %#X\n", &p1, p2, *p3);
    printf(" &a = %#X, p1 = %#X, *p2 = %#X, **p3 = %#X\n", &a, p1, *p2, **p3);
    return 0;
}

运行结果:

100, 100, 100, 100
&p2 = 0X28FF3C, p3 = 0X28FF3C
&p1 = 0X28FF40, p2 = 0X28FF40, *p3 = 0X28FF40
&a = 0X28FF44, p1 = 0X28FF44, *p2 = 0X28FF44, **p3 = 0X28FF44

以三级指针 p3 为例来分析上面的代码。***p3等价于 *(*(*p3))。*p3得到的是 p2 的值,也即 p1 的地址;*(*p3) 得到的是 p1 的值,也即 a 的地址;经过三次“取值”操作后,*(*(*p3)) 得到的才是 a 的值。

假设 a、p1、p2、p3 的地址分别是 0X00A0、0X1000、0X2000、0X3000,它们之间的关系可以用下图来描述:
在这里插入图片描述
方框里面是变量本身的值,方框下面是变量的地址。

网上的解惑

指针究竟是什么?是地址?还是类型?

关于指针,分成了两派。
1.地址派:用%p输出,得到的是地址,所以指针是地址。int * p ,p是指针类型的变量,存放的是地址,,所以指针是地址。这就和int型变量存放int型数据是一个道理。
2.非地址派:认为指针是一种类型,无论是我们在编程中的理解,还是国际标准的规定,都是证明指针是类型,尤其是国际标准已经说的很清楚,指针是类型。
所以我有个疑问,他们两派说的都对,所以,指针究竟是什么?

Milo Yip 编辑于 2015-06-12


参考文档:
http://c.biancheng.net/cpp/html/85.html
https://www.zhihu.com/question/31022750
https://blog.csdn.net/m0_37605407/article/details/79198118

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值