C语言:数组指针、指针数组、指针的指针、函数指针

来源:互联网 发布:淘宝客 编辑:程序博客网 时间:2024/05/22 06:50

说到C语言的指针,可能大家都比较熟悉,基本上的都知道,指针就是存放地址的,无论是普通变量的地址,还是函数的地址都可以用指针表示。如果该指针用一个变量表示,那么这就是一个指针变量。所为指针变量就是这个指针所存放的地址是可以发生变化的,例如

int i = 6;int j = 7;int* p;p = &i;p = &j;
由上面的代码可以看出,首先int类型的指针p是指向变量i的地址的,但是后来指针p又指向了变量j的地址,因此我们就说p是一个int类型的指针变量。

现在我们知道了什么是指针变量了,那什么又是指针类型呢?像我们上面讲的p是一个int类型的指针变量,还有char型指针变量、函数指针等等。这都说明了指针也是有类型的。可能我们会想,指针不就是存放地址吗,地址的长度不都是一样吗,要么16位,要么就是32位,或者是64位。那既然不同类型的变量其地址都是一样的,为什么还要给指针划分类型呢?

给指针划分类型主要有如下几点好处,我们都知道char型变量其大小都是一个字节的,即用一个字节就可以表示一个char类型的变量。如果我们定义一个char类型的指针,那么该指针就是指向一个字节的地址。指针加一指向的地址便是下一个字节的地址。

char a = 'b';char* p ;p=&a;//若a的地址是:0x01,那么p+1所指向的地址就是0x02。
同样,如果是int类型的话,那么指针p就是指向两个字节的地址。


理解好了上面的概念之后,这里我想着重的讲解一下几个指针中难以理解的知识点。

数组指针

表示一个指向数组的指针。
//int类型数组指针int (*p) [5];//char类数组指针char (*p) [7];

首先,由于指针*p被括号括起来了,说明这是一个指针,只不过该指针指向一个一维数组,同时改一维数组的长度为5或7,若int (*p)[5];

则p指向的是0x00;那么p+1则指向的是0x0a;因为int类型由两个字节表示,同时由于p表示指向一个int类型的一维数组,该一维数组的长度为5。那么p+1则表示向后推移的第10个字节。一般数组指针用来指向一个二维数组的。例如:

int a[3][4]={1,2,3,4,5,6,7,8,9,11,1,2};int (*p)[4],i=2,j=3;p=a;printf("a[%d,%d]=%d\n",i,j, *(*(p+i)+j));//输出为a[2,3]=2
注意:*(p+i)表示a[i][0]的地址,而不是a[ i ][ 0 ]的值。这是C语言规定的表示方式。


指针数组

表示一个存放指针的数组。 表示方式为:指针类型 * 指针名字[ 指针个数 ]

//int类型指针数组int* p[5];//char类型指针数组char* p[7]; 或者 char* p [ ];

由于[ ]比*的优先级要高,因此 会先于 [ ] 结合,形成一个数组,然后才会与 结合表示数组类型为指针类型。指针数组广泛应用于C语言编写的程序当中,我们经常会在代码中看到这样一个程序。就拿一个非常简单的C语言的main函数来说。

int mian (int argc, char *argv[]){     //代码}
我们在mian函数的参数里面就使用了指针数组,这个指针数组的作用就是存放我们输入给mian函数的各个字符串的指针,因为main函数并不知道我们会输入多少个字符串给mian函数,所以在定义指针数组的时候,采用了不定义指针数组的个数的方式。

指针的指针

下面讲解C语言指针里面一个比较难以理解的概念,也就是指针的指针。何为指针的指针呢,顾名思义就是一个存放另一个指针地址的指针。表示方法是

指针类型  * * 指针名称 ;

例如:

int **p;//定义一个int类型的指针的指针。
在这里我想要说明的是,指针的指针与数组指针是有区别的,不能将二者混为一谈。我们为什么要提出指针的指针这一概念呢,回答这一问题,我首先要向大家举一个例子,例如当我们把一个指针作为参数传给一个方法时,其实只是将指针的副本传递给了方法,如果我们在方法中重新制定该参数的指向,并不能改变原来指针的指向。

int m_value  = 1;void func(int *p){     p = &m_value;}int main(int argc , char *argv [ ]){    int n = 2;    int *pn = &n;    cout<<*pn<<end1;    func(pn);    cout<<*pn<<end1;    return 0;}//结果为/**22*/
之所以结果是2 ,2 而不是2,1,是因为我们在mian函数中,虽然将指针作为*pn作为参数,传入func函数,但实际上是的传入过程是这样的

int *p  = pn;
也就是说我们只是将pn所指向的地址赋给了指针p,但是由于指针p在func函数中又运行了
p = &m_value;
所以这个时候p的指向发生了变化,开始指向m_value了。但是pn的指针指向并不会因为p发生改变而改变,所以pn仍然是指向n。接下来我们看看如果将指针的指针作为函数参数的话,又会发生什么变化。

int m_value  = 1;void func(int **p){     *p = &m_value;}int main(int argc , char *argv [ ]){    int n = 2;    int *pn = &n;    cout<<*pn<<end1;    func(&pn);    cout<<*pn<<end1;    return 0;}/**结果为:21*/
这个时候我们是将pn指针的地址作为参数传给了指针的指针p,这个时候p是指向指针pn。而*p存放的是pn所指向值的地址,在传入的时候,应该是指向变量n的地址的。为了能够形象表示这三者之间的关系,我用一个图来表示。



这里需要注意的是*pn和*p并不是一回事,*pn和p才是一回事,都表示指向变量的地址,而**pn和*p才是一回事,表示所指向的变量的值。

函数指针

函数指针,也就是指向函数的指针,函数指针在定义的时候会与上面讲的指针有一些区别,因为函数指针在定义的时候,需要定义返回值类型和函数参数类型。
定义格式是:返回值类型 (* 指针名称)(参数一、参数二)。
我们在使用函数指针时必须得满足所指向的函数其返回值类型和参数类型与函数指针定义的时候一样。
例如下面的函数指针:
int (*p)(int,int);
只能指向返回值为int类型的,并且带有两个int参数的函数。

注意以下两种定义方式的区别。
int (*p)(int, int );//...............int * p (int,int);
上面一种表示定义的是一个函数指针。而后面一种表示定义的是一个函数,其返回值为int类型的指针。其根本原因是由于()的优先级比*的优先级要高,所以p会先于右边的()先结合,表示一个函数。后面的int * 便表示返回值的类型了。





0 0