指针浅析

对于指针的理解一直比较混乱,此处分析一些简单类型的指针加深自己的理解,

指针的理解

指针的定义:
  1. int p; //定义普通整型变量;
    int p; //定义一个指针p,指针类型是 int 型,而指针指向的内容的类型为 int 型;

  2. int p[3]、int *p[3]和int (*p)[3]
     int p[3]定义了一个包含三个int型数据的数组。
     int p[3]与int (*p)[3]应该一起理解,其中int *p[3]定义了一个指针数组,而int (*p)[3]定义的是一个数组指针:从优先级上考虑int *p[3]中,p首先跟[ ]结合,所以,p首先是一个数组,然后再跟结合,说明数组里面的元素是指针类型的,最后是与int结合,说明数组中的指针类型是int 类型,而该指针指向的内容是int 型。指针数组,即存放指针的数组。 还是从优先级考虑int (*p)[3]中*P通过()强制改变优先级,此处p首先跟结合,所以,p首先是一个指针,然后p再与[ ]结合,说明指针p所指向的数据类型是数组,最后再与int结合,所以数组中存放的数据类型是int型数据。因此,int (p)[3]是一个数组指针,即指向数组的指针,其中指针类型是int ()[3] ,即指针指向一个带有3个元素的数组,指针指向的数据类型是int ()[3].

  3. int p( int )和int (*p)( int )
      int p( int )表示的是一个函数,p前面的int表示函数返回类型,括号中的int表示函数参数。int (p)(int )表示的是一个函数指针,首先p与结合,说明p是一个指针,然后再跟(int)结合,说明指针指向的是一个函数,最后与int结合,说明所指向的函数返回类型是int型。对于int (p)(int),指针类型是int ()( int ),指针所指向的数据int ()(int),即带有一个int参数、返回值为int 的函数。

 对于一个指针,需要确定的是,指针类型、指针所指向的数据类型、指针本身的值、存放指针的内存区。

指针类型

 从上面分析来看对于一个简单的指针,其指针类型可以简单地认为就是指针定义中,把所定义的指针的变量名去掉就是指针类型:
如:

int *p;    //p是定义的指针,指针类型是int *
int (*p)[3];     //p是定义的指针,指针类型是int (*)[3]
int (*p)(int);     //p是定义的指针,指针类型是int (*)(3)
指针所指向数据类型

 从定义上来看,指针所指向的数据类型也可以简单的从定义上得到:直接把指针变量名和 * 声明符去掉:
如:

int *p;    //p是定义的指针,指针所指向数据类型是int 
int (*p)[3];     //p是定义的指针,指针所指向数据类型是int ()[3]
int (*p)(int);     //p是定义的指针,指针所指向数据类型是int ()(3) 
指针本身的值

 也就是p本身的值,即p中存放的值。其中存放的值是指针p所指向的数据的存放地址,或者说是指针p所指向的内存区,即p本身的值是一个地址值,该地址中存放着p所指向的数据内容也就是*p,*p操作是取出该地址中的值,也就是指针p所指向的东西。
存放指针的内存区(指针的地址)
 由定义可知,该部分是存放着指针本身,即指针所在的内存区,&p可以取到指针p所在的内存区的地址。当声明一个指针的时候,就意味着给指针本身分配了空间,但是此时指针所指向的空间则可能是无效的。

指针的初始化和赋值

 首先,在对变量进行初始化之前,应该先明确变量是什么。对于指针而言,如上面所介绍的,指针p所存储的是所指向的数据在内存中的地址,而不是数据本身。清除了这一点,那么在指针进行初始化的时候,显然,初始化或者赋值的右值应该是“地址值”。
如:

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

 此处,对于整型变量a,通过操作符&对a进行取地址操作,然后将该地址赋给指针p,这样p中便存储了变量a的地址(首地址)。而实际上的操作是,因为p是指针,所以其右值也应该是指针,也就是说,实际上&a的结果得到的是一个指针,指针类型就是a的类型加上*,而指针所指向的地址就是a的地址,然后用该指针对指针p进行赋值。

指针作为参数

一级指针和二级指针

 当一级指针作为参数传入函数中,其主要目的通常是为了修改指针所指向的内容:

int a = 10;
int b = 20;

void func(int* p)
{   
    *p = 11;
    p = &b;

}

void func2(int** p)
{   
    **p = 12;
    *p = &b;
    **p = 21
}

void main(int argc,char** argv)
{

    int* p = &a;
    printf("&a:%0x,a:%d,&b:%0x,b:%d,&p:%x,p:%0x,*p:%d\n",&a,a,&b,b,&p,p,*p);
    func(p);
    pprintf("&a:%0x,a:%d,&b:%0x,b:%d,&p:%x,p:%0x,*p:%d\n",&a,a,&b,b,&p,p,*p);
    func2(&p);
    printf("&a:%0x,a:%d,&b:%0x,b:%d,&p:%x,p:%0x,*p:%d\n",&a,a,&b,b,&p,p,*p);
}

输出为:
&a:601040,a:10,&b:601044,b:20,&p:d2a19a50,p:601040,*p:10
&a:601040,a:11,&b:601044,b:20,&p:d2a19a50,p:601040,*p:11
&a:601040,a:12,&b:601044,b:21,&p:d2a19a50,p:601044,*p:21

 对与传入一级指针参数而言,在函数中进行了一个拷贝,即func中多了一个指针的拷贝,而该拷贝的指针与传入的指针一样是指向a,但是实际上不是同一个指针,可以通过该指针来改变所指向内存(a)的值,而在func中改变了指针指向(指向b),实际上只是改变了内部指针的指向,但是外部指针指向并没有改变(仍然指向a);
 而二级指针,实际是指向指针的指针,即内部指针实际上是指向外部指针的,因而需要通过双重解引用的方式来获取a的值,也可通过该方式来改变a的值,而通过单层解引用的方式来获取外部指针,同时也能通过该方式来修改外部指针的值,也就是修改了外部指针的指向。在func2中,**p = &b,实际上改变了内部指针所指向内容的值,即外部指针,从而达到修改外部指针指向的目的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

弹指间LDL

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

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

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

打赏作者

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

抵扣说明:

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

余额充值