您的位置:首页 > 编程语言 > C语言/C++

C语言中有关指针的学习

2017-05-27 10:55 225 查看
一、指针的概念:      在计算机科学中,指针(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);说明:()优先级高,首先说明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++语言中定
义一个指针,就是在栈区开辟一个内存空间用来存放它指向的内存地址,然后给指针赋值,就是把地址值赋值给刚才开辟的内存
空间,然后通过访问该内存中的地址值来间接访问该地址下存放的数据。如果该地址值指向的是一块静态存储区,如字符串常量
等,当然就不可以修改指向的内容啦。

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: