指针数组、数组指针、指针函数、函数指针的区别,四个概念最本质的区别在后面,从后往前去理解比较好区分和认识。
指针数组是一个数组,装着指针的数组,也就是指针的数组。
数组指针是一个指针,指向数组的指针,也就是数组的指针。
指针函数是一个函数,函数的返回值是指针,也就是返回值是指针的函数。
函数指针是一个指针,指向函数的指针,也就是函数的指针。
-------------------------------------------------------------------------------------------------------------------------
定义一个数组变量和一个指针变量,补充一下基础概念,理解!很重要!
int arr[5] = {1,2,3,4,5};//定义了一个int类型的数组arr,并且初始化数组。
int *px = arr;//定义了一个int类型的指针px,初始化指针指向数组。
数组名(或者叫数组变量,数组的指针)是特殊的指针,数组的指针是指数组在内存中的起始地址,即第一个元素的地址,代表了整个数组空间,数组名本身表达地址,地址是常量,所以将数组赋给指针变量不需要用&取地址,只需要两个变量的类型匹配即可,但是数组中的某个具体的元素就是变量,赋值给指针的时候需要用&取地址。
指针就是内存单元的地址,用来存放地址的变量,称为指针变量。在不影响理解的情况下,有时对地址、指针和指针变量不做区分,通称指针。
如果数组的数据类型和指针的数据类型相同,那么arr[i]、px[i]、*(arr+i)、*(px+i)在功能上完全相同,都是访问数组第i+1个元素。
数组名和指针变量在访问数组中元素的时候,一定条件下,具有相同的形式,相同的功能,但是在本质上有区别,数组名是一个地址常量,而指针变量是一个地址变量。
在定义和区分需要明确在这里常用三个运算符的优先级关系: ()> [ ] > *
-------------------------------------------------------------------------------------------------------------------------
1、指针数组
是什么?是一个数组,数组存放的是指针。
******************指针数组******************
//定义了一个指针变量,将字符串赋给指针变量,其实赋的是第一个字符的地址,这时的字符串被称为常量字符串,不可通过指针修改该常量的值。
char *p1 = "zzzzz";
char *p2 = "xxxxx";
char *p3 = "ccccc";
//定义了一个指针数组,将三个指针变量赋值给这个数组的三个元素
char *arr[3] = {p1,p2,p3};
也就是:
arr[0] == p1
arr[1] == p2
arr[2] == p3
也等价于:
char *arr[3] = {"zzzzz","xxxxx","ccccc"};
//arr是一个四个元素的数组,每个元素都是一个char *类型的指针,这些指针都指向常量字符串的首地址
******************指针数组******************
指针数组比较适用于指向若干个字符串,使字符串的处理更加灵活。
2、数组指针
是什么?是一个指针,指向数组的指针。
******************数组指针******************
char arr[3] = {'a','b','c'};//定义一个一维数组
char (*p)[3];//定义一个数组指针
******************数组指针******************
在这里,arr是一个数组,这个数组中的每个元素都是char类型,每个元素在内存空间占一个字节,arr是数组的首元素的地址。
p是一个指针,这个指针的数据类型是char[4]类型的(可以理解为一个新的类型,这个类型就是4个char类型组成的数组,组成了一个整体)。
如果像一维数组那样把数组名赋值给指针变量,p = arr,很明显,它们的类型不匹配,但是数组名代表的是整片地址,如果对整片地址空间取地址,p = &arr,这时类型相匹配。
数组指针常用于指向二维数组,此时也称为行指针。
//定义一个三行四列的整形数组,并初始化数组的每个元素
int arr[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
//定义一个数组指针,这个指针指向数组的第一行
int (*p)[4] = a; //a == &a[0]
p[i][j] == a[i][j];
3、指针函数
是什么?是一个函数,函数的返回值是指针。
******************指针函数******************
//定义了一个指针函数
//这个函数的返回值的类型是char*型,也就是返回的是一个指针,这个函数叫fun,有两个char*类型的参数。
char* fun(char* a,char* b)
{
语句块;
}
******************指针函数******************
//自定义一个mystrcpy指针函数
char* mystrcpy(char* dest,char* src)
{
char* temp = dest;
while(*src != '\0')
{
*dest++ = *src++;
}
*dest = '\0';
return temp;
}
int main()
{
char str[10] = {0};
char* p = "hello";
mystrcpy(str,p);
printf("%s\n",str);
return 0;
}
用一个字符串操作函数strcpy来举例子,在这里自定义了一个指针函数,函数有两个参数,两个参数都是char*类型的指针,函数体的内容,先定义了一个指针保存了参数传入的地址,通过循环,把后面的指针指向的内容赋值给前面指针的指向,从而实现了字符串copy操作,最终返回之前保存的那个地址,也就是返回值是指针的函数,即指针函数。
指针函数常用于返回数组,字符串等数据结构指针等,最典型的就是可以使用man查看字符串操作函数如strcpy,strcat,strstr看到函数原型。
4、函数指针
是什么?是一个指针,指向函数的指针。
当一个函数指针指向一个函数,就可以通过这个指针来调用函数。
//定义一个函数
int Fun(int n,int m)
{
return m+n;
}
//定义一个函数指针并赋值
//这里将上一个函数的入口地址赋值给这个函数指针
int (*p)(int ,int ) = Fun;
//通过函数指针可以直接调用这个函数
printf("%d\n",fun(10,11));
或者
printf("%d\n",(*fun)(10,11));
函数指针最典型的应用就是回调函数,就是一个作为参数传递的函数,即在一个函数中通过函数指针调用其他函数。