一、函数指针数组
1、指针数组
指针数组:数组里面放指针的数组
(存储指针的数组)。如果一个数组中的所有元素保存的都是指针,那么我们就称它为指针数组。[ ]的优先级高于*
dataType *arrayName[length]; //int *arr[4]
在打印时,数组长度为32,原因int arr[4]是指针数组,指针长度在64位系统下的长度为8(固定),所以数组长度为:48 = 32.
字符数组 str 中存放的是字符串的首地址,不是字符串本身,字符串本身位于其他的内存区域,和字符数组是分开的。
int a=1,b=2,c=3;
int *A[3]={&a,&b,&c};
int **p=A;
printf("%p\n",&a);
printf("%d\n",**p);
printf("%d\n",A[2][0]);
int a = 10, b = 15, c = 36, d = 100;
int *arr[4] = {&a, &b, &c, &d};
printf("%p\n",&a);
printf("%p\n",*(arr+1));
printf("%p\n",&b);
printf("%d\n",**arr);
printf("%d",*arr[0]);
char *str[3] = {"www.baidu.com","yqkj","C language"};
printf("%s\n",*(str+2));
printf("%c\n",str[0][4]);
printf("%c\n",*(*str+4));
printf("%c",*(str[0]+4));
char str1[] = "www.baidu.com";
char str2[] = "qckj";
char str3[] = "C language";
char *str[3] = {str1, str2, str3};
printf("%s\n",*(str+1));
printf("%c\n",**(str+2));
printf("%c\n", *(str[1] + 1));
printf("%c\n", str[1][2]);
2、数组指针
数组指针:指向数组的指针
//一维数组
int arr[] = { 99, 15, 100, 888, 252 };
int *p = arr;
//二维数组
int a[2][3] = {1,2,3,4,5,6};
int (*p)[3] = a ;
- arr 本身就是一个指针,可以直接赋值给指针变量 p。arr 是数组第 0 个元素的地址,所以int *p = arr;也可以写作int *p = &arr[0];。也就是说,arr、p、&arr[0] 这三种写法都是等价的,它们都指向数组第 0 个元素,或者说指向数组的开头。
- 如果一个指针指向了数组,我们就称它为数组指针(Array Pointer)。数组指针指向的是数组中的一个具体元素,而不是整个数组,所以数组指针的类型和数组元素的类型有关
char ch[] = "helloworld";
char *p = ch;
printf("%s\n",p);
printf("%c\n",*(p+1));
int arr[] = {99, 15, 100, 888, 252};
int *p = arr; // 指向数组的指针
// 数组元素个数
printf("%d\n",*arr);
printf("%d\n",*(p+1));
printf("%d\n",*(p++));
printf("%d\n",*p);
printf("%d\n",*(++p));
printf("%d\n",*p++);
printf("%d\n",*p);
printf("%d\n",++(*p));
printf("%d\n",*++p);
int arr[] = {99, 15, 100, 888, 252};
int i, *p = &arr[2]; // p是不是指向数组第一个元素 p[0] == arr[2]
printf("%d\n",*(p-2));
printf("%d\n",p[-2]);
printf("%d\n",1[p]);
printf("%d",1[arr]);
//二维数组
int a[2][3] = {1,2,3,4,5,6};
//数组指针 arr指向有3个元素的数组(小数组)
int (*arr)[3] = a;
printf("%d\n",(*(arr+1))[0]);
printf("%d\n",*(*(arr+1)+2));
printf("%d\n",arr[0][0]);
printf("%d\n",**arr);
3、函数指针
函数指针:指向函数的指针
一个函数总是占用一段连续的内存区域,函数名在表达式中有时也会被转换为该函数所在内存区域的首地址,这和数组名非常类似。我们可以把函数的这个首地址(或称入口地址)赋予一个指针变量,使指针变量指向函数所在的内存区域,然后通过指针变量就可以找到并调用该函数。这种指针就是函数指针。
returnType (*pointerName)(param list);
int (*pont)(int a, int b);
//point指针变量指向一个返回值为int,有两个参数的函数。 point存放了函数地址
#include <stdio.h>
//函数声明 包含函数指针
void fun_point(int *num, void (*point)(int a), int n);
//函数声明
void add(int a);
int main(void)
{
int a = 10, b = 20, num;
//第二个参数传函数指针(函数名就是地址)
fun_point(&num, add, a);
printf("num:%d\n", num);
return 0;
}
//回调函数
void add(int a)
{
printf("a:%d\n", a);
printf("helloworld\n");
}
//底层
void fun_point(int *num, void (*point)(int a), int n)
{
*num = 100;
point(n);
}
4、指针函数
指针函数:返回指针的函数
C语言允许函数的返回值是一个指针(地址),我们将这样的函数称为指针函数。
用指针作为函数返回值时需要注意的一点是,函数运行结束后会销毁在它内部定义的所有局部数据,包括局部变量、局部数组和形式参数,函数返回的指针请尽量不要指向这些数据,C语言没有任何机制来保证这些数据会一直有效,它们在后续使用过程中可能会引发运行时错误。
5、函数指针数组
函数指针数组:存储函数指针的数组(数组存储指针,指针指向函数)
returnType (*arrname[len])(param list)
returnType:函数返回类型
arrname:数组名
len:数组长度
param list:函数列表
二、总结
- 数组指针、指针数组、函数指针、指针函数、函数指针数组。在理解上,它的重点在后面,比如:函数指针,首先是一个指针,指针指向函数。理解指向函数的指针。
- 数组名做参数进行传递时,传递是指针,此时的指针操作不能与数组操作完全一致。
- 使用指针函数时要特别注意,函数返回的所有变量值(普通变量,指针变量、数组、结构体数组等),在函数执行完成之后,它们的空间将被系统回收。如果想要在其它函数找到之前函数的某个变量、指针、数组、结构体等内存,必须使用malloc方法进行开辟永久保存内存空间的。这样其它函数才能找到变量、指针、数组、结构体等内存。
- 函数名基本就是一个地址,函数调用,就地址解引用。