指针真指

    指针到底是什么?或许初学者会有这样的疑惑,有些书上可能会说指针就是地址,那么指针真的就就是地址吗?小博的答案是:指针是一种映射关系,是可以映射一段或大或小的地址区域的特殊变量。

 1.基本数据类型指针

  因为比较简单,小博就直接上代码了

int i = 8;
int * p = &i;  //p就是指向了一个四字节大小的指针

char c = 's';
char * pc =&c;
printf("%c",*pc);  //这里的pc就是指向字符的指针

short si = 8;
short * ps = &si; //ps就是指向了短整型数据的指针,它映射了两个字节

  其余的基本数据类型与之类似,小博就不一一列举了。那么既然指针是一种映射关系,既可以映射小块区域,是不是也可以映射大一点的区域呢? 下面我们就来看一下结构体指针。

2. 结构体指针

说到结构体指针,那就必须要说一下什么是结构体了。结构体(struct)是由一系列具有相同类型或不同类型的数据构成的数据集合,也叫结构。上段代码:

struct  {
 char  sex;
 int  id;
 double mon;
}stu;

好了,这就是一个集合了字符型、整型、双精度浮点型的数据集合,这样来看,数组其实也是特殊的结构体,不过是每个元素的数据类型相同而已。扯远了,我们来看结构体指针

typedef struct node{
	int date ;
	char c ;
}ElamSN, * ElamList;

ElamSN h ;
h.c='s';   h.date=8;
ElamList p = &h;  //让一个结构体指针指向了一个struct node类型的元素,此时映射了8个字节的地址空间                                             
//为什么是8个字节小博就不详述了,有兴趣的朋友可以查阅相关资料
 printf("%5d",p->data);

以上就是结构体指针,以及对它的使用。

3.数组指针

有了结构体指针,数组指针就不难理解了吧,数组指针,也叫行指针 因为它指向一维数组 ,下面是它的简单使用

	int  (*pp)[6];      //数组指针的定义
	int a[2][6]={5,6,7,8,9,10,11,12,13,14,15,16};
	    pp=a;
	pp++;   //数组指针pp即指向了一维数组,那么它的++操作就指向了二维数组的第二行
	for(int i = 0 ; i < 6; i++)
	printf("%d   ",pp[0][i]);
	 

数组指针的定义还是蛮特殊的,int (*pp)[6]  可以这样理解,他是一个指针pp指向了int  *  [ 6 ]类型的指向关系,^-^但编译器上不能这样写哦。

3.2指针数组

说到数组指针,在这里小博也顺便说一下指针数组,顾名思义,指针数组是数组,而不是指针,但数组元素确实指针,下面来让我们看一个例子。

int  saw[4][5]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,22,33,44};
	 int * ps[4];   //指针数组 
	 for(int i=0;i<4;i++)
	    ps[i]=saw[i];
    for(int i=0;i<5;i++)
	printf("%5d",ps[3][i]);

在此代码中,对于指针数组而言,指针数组的元素个数必须等于二维数组的行数,让一个指针指向一行数组。

同样的有数组指针,指针可以映射一块区域,那么如果指针映射一个链表,那么这个数组链表就是哈希表的一种存储方式------拉链法,数组中存放链表的首地址,例如下图,有兴趣的朋友们可以实现一下。

                                                              

                                                                  

4.函数指针

既然指针可以指向数组,结构体,那么指向函数好像也不是很大不了。先来一段简单的代码吧。

void  func()
{
	puts("func函数被调用!!!");
 } 
int  main (void)
{
   void (*x)();    //函数指针的定义
    x=&func;   //给指针指向
     (*x)();  //通过函数指针调用函数
}

这里的指针x就是指向了一个无参无返回值类型的函数func,而(*x)()就是对函数的的调用。那么在稍微复杂一下

(*(void(*) ())0)();

哎?这是个什么东西?  此代码出自《C Traps and Pitfalls》

让我们来分析一下   1 : void(*) ()   这是一个函数指针,这个指针指向的函数无参,无返回值

2 :(void(*) ())0  0强制转换为函数指针类型,0是一个地址,也就是说一个函数存在首地址为0的一段区域内。

3 :(*(void(*) ())0)  取0地址开始的一段内存里面的内容,其内容就是保存在首地址为0的一段区域内的函数。

4 :(*(void(*) ())0)()  函数调用。

4.2函数指针数组

 既然函数指针也是指针,那么也可以存于数组,结构体当中

 int  proa(int c)
 {
 	 c*=c;
 	 printf("%5d",c);
 	 return c;
 }
 int  prob(int c)
 {
 	 c*=c;
 	 printf("%5d",c);
 	 return c;
 }
 int  proc(int c)
 {
 	 c*=c;
 	 printf("%5d",c);
 	 return c;
 }
int main (void)
{
   int (*pa[3])(int c);
   pa[0]=&proa;
   pa[1]=&prob;
   pa[2]=&proc;
   pa[0](3);
   pa[1](2);
   pa[2](7);
}

  既然有函数指针数组,那就可以有函数指针结构体函数指针数组的指针函数指针数组的指针数组等等,小博就不一一列举了,有兴趣的朋友们可以尝试一下。

5.类指针

  或许有一些没有接触c++的朋友就纳闷了,类我咋没听过?当然对于c++小博也学习的很浅,在这里就浅尝辄止的说说类指针。其实最开始类的概念就是从C语言结构体结构体扩展来的,相当于结构体的plus版本,除了数据外还添加方法的实现,不说闲话了,上代码

class  Adaptor{
	public :
        int  x = 0;
		void adeptpro()
		{
			cout<<"Adapetor "<<endl;
		}
};

int main (void)
{
	Adaptor * sda=new Adaptor();  //类指针sda
	sda->adeptpro(); 
	cout<<sda->x;
	delete sda;
}

可以通过类指针访问类的方法或数据。

是不是很简单,其实在面向对象语言中很多概念都是互通的,比如在java中没有了指针,但其实还存在着引用,和指针也是“猫”和“咪” 的关系,就不在这里赘述了。那么为什么不用对象而要用指针,因为在传参时如果传对象,那就太浪费空间了,但如果传的是指针,在32位系统上都只有4个字节大小。来一段伪代码,即: sizeof(不管什么类型指针)=4   byte 

6. 二级指针

二级指针,即指针的指针。先来一段非常简单的代码

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

     同样的,pp是指向了整型地址类型(int * )的指针,可以说是最简单二级指针。那么和本文前面的结合起来,就可以实现一个指向数组元素的指针parray,而每个数组元素的类型可以是结构体指针类型,即每个元素可以指向一个结构体,这个指针parray就是一个二级指针。具体代码有兴趣的朋友可以去尝试,以此类推二级指针的种类更加繁多。那么正确的理解指针就可以以不变应万变。

而二级指针的好处在于改变指针的值时使用二级指针比较方便。

综上所述,指针就是一个映射关系,它可以映射不同大小的内存空间,如果映射4字节就是整型指针,映射一个函数就是函数指针,映射一个数组就是数组指针,映射一块地址就可能是一个二级指针,等等。同样的发散一下思维,如果以后还出现了新的数据结构,它的指针相信读者们也能快速理解。

PS:这是博主小子的第一篇博客,还请各位大佬“键”下留情,有不对的请指出,希望各位多给小子信心。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值