指针概念:
指针是程序语言中的一种对象,计算机对数据的访问是通过寻址实现的,而指针就能存放数据的地址,使得程序员能够通过对指针变量的操作来实现对数据(或说变量)的操作。
如图:
这里 p 是一个指针变量,p 里面存放着变量 a 的地址,那么我们找到 p 就可以对变量 a 进行读写等操作了。
普通指针:
声明格式:数据类型 *指针名;
例如:int *p;
这里就声明了一个整数类型的指针 p
对指针变量赋值通过运算符 & 完成(如:p=&a)
对指针变量所指向的变量进行访问通过 * 完成(如:*p)
#include<stdio.h>
int main()
{
int a=10; //声明一个整形变量
int *p; //声明一个整形的指针变量
p=&a; //将变量 a 的地址传给指针变量 p
printf("%d\n",p); //输出 p 存放的内容,即变量 a 的地址
printf("%d",*p); //读取 p 所存放地址对应的变量 a
return 0;
}
当然对于 char , long , float , double 等类型的数据都可以声明指针变量
普通指针的用途:
1、指向单个变量
2、指向单个数组
int a[10]={0}; //声明一个整形数组
int *p; //声明一个整形指针
p=a; //把数组 a 的首地址传给 p
/*当然最后一行还可以写为 p=&a[0] */
3、指向结构体
struct student{
int id;
char name[10];
int grade;
}
struct student *student1; //这里就声明了一个 student 这个结构体的指针变量
4、指向函数(笔者将在后面的“指针函数”板块进行讨论)
指针数组:
上面我们介绍了单个的指针,如果我们现在需要多个指针呢,那怎么办?
当然,我们就应该多声明一些指针变量,例如:int *p1,*p2,*p3 … …
读者必想,这样写是不是太麻烦了,有没有简洁点的办法就可以声明多个同类型的指针变量呢?当然有的,那就是指针数组。其实,指针数组就是由多个同类型指针组合而成的数组。
定义形式:数据类型 *p[N];
说明:N为指针数组元素个数
例如:
#include<stdio.h>
int main()
{
int a=1;
int b=10;
int c=100;
int *p[3]; //定义一个整形指针数组
p[0]=&a; // 对指针数组元素逐个赋值
p[1]=&b;
p[2]=&c;
printf("%d\n",p[0]);
printf("%d\n",p[1]);
printf("%d\n",p[2]);
return 0;
}
指针数组的用途
1、指向多个单一的同类型变量
2、指向多个数组
//以指向一个二维数组为例
#include<stdio.h>
int main()
{
int a[3][4]; //声明一个二维数组
int *p[3]; //声明一个指针数组
int i;
for(i=0;i<3;i++)
p[i]=a[i]
//将二维数组拆分成3个一维数组,并把每一个一维数组首地址赋值给指针数组的元素
/*事实上这条语句还有其它写法,例如 p[i]=&a[i][0]*/
printf("%d\n",p[0]);
printf("%d\n",p[1]);
printf("%d\n",p[2]);
return 0;
}
3、指向多个同类型结构体
数组指针:
数组指针是指向数组地址的指针。
以二维数组为例
定义形式:数据类型 (*p)[N];
说明:这里的括号不可少,N为该数组指针的一维子数组的元素个数(可以省略,看不懂的话看例子)。同时,这里涉及到运算符的优先级(() 和 [] 从左往右结合):() = [] > *
p 是一个指针变量,它指向包含N个所声明数据类型元素的一维数组,此时 p 的增量以它所指向的一维数组长度为单位;
*(p+i) 是二维数组a[i][0]的地址;
(p+i)+j 表示a[i][j]元素的地址,(*(p+i)+j) 表示 a[i][j] 的值。
例如:
#include<stdio.h>
{
int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11}; //声明一个二维数组
int (*p)[4]; //声明一个数组指针
int i;
p=a; //让数组指针指向该二维数组
for(i=0;i<3;i++) //输出每个一维数组的首地址
printf("%d\n",*(p+i));
printf("\n%d\t %d\n",a[2][0],&a[2][0]);
printf("%d\t %d",*(*(p+2)+0),*(p+2)+0);
return 0;
}
运行结果:
指针函数:
指针函数本身是一个函数,只不过这个函数的返回值为某一类型的指针。
定义形式:返回值类型 *函数名(函数参数列表)
说明:指针函数常用于寻找并返回数组中某个元素的地址。
例如:
#include<stdio.h>
int *Test(int *p,int a);
int main()
{
int score[3]={100,60,20};
printf("需寻找的目标值(100),其地址为:%d\n",&score[0]);
printf("已找到目标值(100),其地址为:%d",Test(score,100));
return 0;
}
int *Test(int *p,int a)
{
int i=0;
while(p[i]!=a)
i++;
return &p[i];
}
运行结果:
函数指针:
概念:函数指针是指向函数的指针变量。因而“函数指针”本身首先应该是指针变量,只不过该指针变量指向函数。这正如指针变量可指向整型变量、字符型、数组一样,这里是指向函数。如前所述,C在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。有了指向函数的指针变量后,可用该指针变量调用函数,就如同用指针变量可引用其他类型变量一样。函数指针有两个用途:调用函数和做函数的参数。
定义形式:返回值类型 (*指针变量名)(函数形参列表)
说明:同样,这里的括号不可少,也是要考虑运算符的优先级
用函数指针调用函数:
#include<stdio.h>
void Test();
int main()
{
void (*p)(); //声明一个函数指针(无返回值,无形参)
p=Test; //或者用 p = &Test; 将函数的入口地址传给 p
p();
return 0;
void Test()
{
printf("我被调用了!\n");
}
用函数指针作函数的参数:
#include<stdio.h>
void Fun(int i);
void useFun(void (*p)(int m),int i);
//这里将 void (*p)(int m) 作为useFun函数的一个形参
int main()
{
void (*p)(int m); //声明一个函数指针
p=Fun;
useFun(p,10); //调用函数,注意这里将一个函数指针作为了形参
return 0;
}
void Fun(int i)
{
printf("我被调用于输出:%d",i);
}
void useFun(void (*p)(int m),int i)
{
p(i); //调用函数
}
二级指针:
概念:二级指针既是指针的指针。一级指针 *p 是用于存放一个变量 a 的地址的,即是通过这个一级指针我们可以对变量 a 进行操作;一级指针 *p 事实上也是变量,我们也需要对它进行一些操作,那么就用另一个指针变量来保存这个一级指针的地址,这就是二级指针 **p
如图:
这里存在一个变量 C ,B 为一级指针,A 为二级指针。C 中存放了一个数据,而 B 存放着 C 的地址,A 又存放着B的地址。
二级指针可分为:指向指针变量的指针、指向数组的指针
前者不再举例,下面给出一个指向数组的指针实例
#include<stdio.h>
int main()
{
int i,a[5]={1,2,3,4,5};
int *p,**pp; //定义一个一级指针 p 和一个二级指针 pp
p=a;
pp=&p;
for(i=0;i<5;i++) //用二级指针变量输出方式一
printf("%d\t",*(*pp+i));
printf("\n");
for(i=0;i<5;i++,p++) //用二级指针变量输出方式二
printf("%d\t",**pp);
return 0;
}
至此,笔者能写的就这么多,下面再进行一下总结。
1、普通指针用于存放某变量的地址
2、指针数组是一系列同类型指针构成的一个数组
3、数组指针用于指向数组地址。以二维数组指针为例,数组指针就是用于存放二维数组一行所构成的一个一维数组的首地址。
4、指针函数是函数,其函数返回值为某一类型的指针
5、函数指针是函数,其指向某个函数,存放某个函数的入口地址值
6、二级指针是指针的指针,是用于存放某个指针变量的地址的。