C语言中有关指针的学习

一、指针的概念

      在计算机科学中,指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接指向(points to)存在

脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址

象化的称为指针。意思是通过它能找到以它为地址的内存单元。 

指针的本质:指针其实是一个整数

计算机中的内存都是编址的,每个地址都有一个符号。在C语言的多数实现中,指针值等同于一个无符号整数

(unsigned int,因不致歧义,下简称“整数”),它是一个以当前系统寻址范围为取值范围的整数。声明一个

无符号整数并使它的值等于对象的地址值,实质上也能使之有指针的作用。指针是存放地址才出现的,地址是为

了标示一块地址空间的。指针让地址有地方存放,指针让内存的访问更加方便。

指针的大小在32位平台是4个字节,在64位平台是8个字节 。

char*pc =NULL;

int*pi = NULL;

short*ps =NULL;

long*pl = NULL;

float*pf =NULL;

double*pd =NULL;

这里可以看到,指针是有类型的类型是:type + *的方式。 

其实:

char*类型的指针是为了存放char类型变量的地址。

short*类型的指针是为了存放short类型变量的地址。

int*类型的指针是为了存放int类型变量的地址。 

以此类推

指针分为以下几种:

1、指针数组

指针数组是一种特殊的数组,指针数组的数组元素都是指针变量。指针数组的定义格式为:

类型名称 *数组名称[数组长度];

例如:float *p[3];

因为下标运算符[]的优先级高于指针运算符*,上述定义等价于:float * (p[3]);

说明p是一个含有3个元素的数组,数组元素为指向float型变量的指针变量。

又如: 

int *p[5]; /*定义一个5个元素的指针数组,数组元素为指向int型变量的指针变量*/

char *pc[10]; /*定义一个10个元素的指针数组,元素为指向char型变量的指针变量*/

不论指针数组是什么类型,指针数组的每个数组元素都用来保存一个地址值。  

作用:数组的属性全有。因为成员是指针,这就可以延伸出很多内容。包括:

1)成员是函数指针,整个数组就是一类相关函数的集合,便于代码架构的管理。

2)成员是链表指针啦,char指针,这种就是能做出类似散列表的结构。


2、数组指针

数组指针是指向数组地址的指针,其本质为指针

数组指针(也称行指针)的定义格式:

类型名称 (*数组名称)[数组长度]

例如: int (*p)[n];

说明:()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p

的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。

例如:int a[3]={1,2,3};
int (*pa)[3]= &a;/*pa是指向含有三个都为整形元素的一维数组的一个指针*/
例如二维数组的指针:
    int a[3][4];

int (*p)[4]; /*该语句是定义一个数组指针,指向含4个元素的一维数组。*/

p=a; /*将该二维数组的首地址赋给p,也就是a[0]或&a[0][0]*/

p++; /*该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]*/

所以数组指针也称指向一维数组的指针,亦称行指针。


3、函数指针

     函数的指针包含了函数的地址,可以通过它来调用函数。声明格式如下:

函数类型 (标志符指针变量名) (形参列表);

函数指针包含函数在内存中的地址。数组名实际上就是数组的第一个元素在内存中的地址,类似地,函数名实际


也是执行这个函数任务的代码在内存中的起始地址


函数指针可以传递给函数、从函数返回、保存在数组中、赋予另一个函数指针或者调用底层函数。


注1:“函数类型”说明函数的返回类型,“(标志符指针变量名 )”中的括号不能省,若省略整体则成为一个函

数说明,说明了一个返回的数据类型是指针的函数,后面的“形参列表”表示指针变量指向的函数所带的参数列

表。例如:

int func(int x); /* 声明一个函数 */

void (*f) (int x); /* 声明一个函数指针 */

f=func; /*将func函数的首地址赋给指针f */

赋值时函数func不带括号,也不带参数,由于func代表函数的首地址,因此经过赋值以后,指针f就指向函数

func(x)的代码的首地址。

注2:函数括号中的形参可有可无,视情况而定。


4、函数指针数组:

定义:函数指针数组是一个其元素是函数指针的数组。那么也就是说,此数据结构是是一个数组,且其元素是一

个 指向函数入口地址的指针。 

首先确定这是一个数组:数组名[] 

其次,要说明其元素的数据类型指针:*数组名[]. 

再次,要明确这每一个数组元素是指向函数入口地址的指针:函数返回值类型 (*数组名[])()。

请注意,这里为什么要把“*数组名[]”用括号扩起来呢? 因为圆括号和数组说明符的优先级是等同的,如果不

圆括号把指针数组表达式扩起来,根据圆括号和方括号的结合方向,那么 *数组名 说明的是什么呢?是元素返

值类型为指针的函数数组。有这样的函数数祖吗?不知道。所以必须括起来,以保证数组的每一个元素是指

针。

例如:int (*parr[])(); //声明了一个函数指针数组

   再例如:  void test(char* str);
                  void (*p[5])(char*)//p是一个数组,有五个元素,每个元素是函数指针,这些指针指向的函数参数是             char*,返回类型是void型。


函数名其实就是一个指针,指向函数的入口地址。


既然说函数名是一个指针的话,那么函数的调用就有2种方式:


函数名(参数列表)


*函数名)(参数列表)



必须声明参数表明这是一个函数指针;必须用括号把*和函数名括起来,表明这是函数指针,而不是返回一个


针的函数。既然函数名可以通过函数指针加以保存,那么也一定能定义一个数组来存这些指针,这就是函数指


数组。正确使用函数指针数组的前提条件是,这若干个需要通过函数指针数组保存的函数必须有相同的参数和


回值。使用的时候直接把需要调用的函数名赋给函数指针即可。总之一句话,给函数指针赋值后就把它当作普


函数用就行啦。


5、指向函数指针数组的指针:

      指向函数指针数组的指针是一个指针,指针指向一个数组,数组的元素都是函数指针;它和数组指针类似

      ,只不过它指向的数组元素是函数指针类型。

    例如:int (*arr[3])(int, int) = {NULL,Sub,Add};//三个函数地址

           int (*(*p)[3])(int ,int) = &arr;

            *p[1](1,2);就是调用Sub这个函数

      二、指针有关的区别:

1、数组指针和指针数组的区别:数组指针是指向数组首元素的地址的指针,其本质为指针(这个指针存放的是

首地址的地址,相当于2级指针,这个指针不可移动);指针数组是数组元素为指针的数组,其本质为数组。  

如:int*p[2]是指针数组,实质是一个数组,里面的两个元素都是指针, []的优先级比*的优先级高,p先与[]结

合,  成数组p[2],有两个元素的数组,再与*结合,表示此数组是指针类型的,每个数组元素相当于一个指针变

量。

数组指针只是一个指针变量,似乎是C语言里专门用来指向二维数组的,它占有内存中一个指针的存储空间。指针数

组是多个指针变量,以数组形式存在内存当中,占有多个指针的存储空间。还需要说明的一点就是,同时用来指向二

维数组时,其引用和用数组名引用都是一样的。

比如要表示数组中i行j列一个元素:

*(p[i]+j)、*(*(p+i)+j)、(*(p+i))[j]、p[i][j]

优先级:()>[]>*

指针数组是数组元素为指针的数组(例如 int *p[3],定义了p[1],p[2],p[3]三个指针),其本质为数组。

数组指针的使用在某些情况下与指针数组很相似,要注意区别。

      例如:{int a;int (*p)[5]=a;}这里a是个二维数组的数组名,相当于一个二级指针常量;

p是一个指针变量,它指向包含5个int元素的一维数组,此时p的增量一维数组长度为单位;

*p+i是二维数组a[i]的地址;

*(p+2)+3表示a地址(第一行为0行,第一列为0列),*(*(p+2)+3)表示a的值。





2、函数指针与指针的区别:

1) 二者都是指针
2)函数指针里存放的是一个函数的首地址,而整型指针里放的是一个整型变量的地址;
3)指针本身是引用类型。所以使用时都要解除引用。函数指针与整型指针解除引用的方式不同。整型指针有两种方
式解除引用:
如对整型指针pi:  
   int i = 0; 
   int *pi = &i;
  解除引用方法一:  *pi
  
  解除引用方法二:  pi[0]
  对函数指针pf:     int f(int);
  int (*pf)(int) = f ;
  解除引用方法:  pf(8);

  整型指针解除引用方法二:  pi[0]更像数组。也更像函数指针解除引用的方法,原因是:
数组名、和函数名 的本质都是地址。指针的本质也是地址。
 
4)从以上例子中看到赋值形式不同

  函数指针  pf = f; (不用 &。其实用也一样)

  整型指针   pi = &i;
原因是数组名、和函数名 的本质都是地址,而整型变量的本质(当作为左值【如果允许】或右值时)是地址里的值。
 
5)对函数指针,一般不可以做递增操作 如:pf++  99.9999%会崩溃

   如果要访问函数阵列,需要使用函数指针数组
3、指针与数组的联系和区别:

区别:C语言把内存划分成四个区,它把一般的变量和数组等存在于内存中的栈区,所以数组在C语言的定义中只

是一组同类型的普通变量,即使这个变量有可能是指针。所以他的作用比指针小的很多,而指针可以指向任何区的

任何数据,所以就会觉得指针和数组名很像,但是必须要注意的是,数组名只是指针中的一种,它是指针中只指向

栈区的且指针的移动范围是有限的,即数组长度。而且数组在定义之初就已经有了自己的内存,一般的指针如果未

指向某一个内存块时,它是没有自己的内存的,即所谓的野指针。

联系:如上面所说,数组只是定义在栈区的一个连续变量,它的首地址就是一个指针。
总结:不仅数组有指针,所有变量都有指针,指针说白了就是内存中的地址,就像一个房间必须有一个房间号。在C/C++语言中定
义一个指针,就是在栈区开辟一个内存空间用来存放它指向的内存地址,然后给指针赋值,就是把地址值赋值给刚才开辟的内存
空间,然后通过访问该内存中的地址值来间接访问该地址下存放的数据。如果该地址值指向的是一块静态存储区,如字符串常量
等,当然就不可以修改指向的内容啦。

 


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值