字符指针
写法1
char a = 'w';
char*p = &a;
*代表p为指针,char代表指针指向的内容类型是char类型
写法2
#include <stdio.h>
int main()
{
char arr[] = "abcdef";
char* p1 = arr;
*p1 = 'w';
char* p2 = "abcdef";
*p2 = 'w';
return 0;
}
仔细观察写法二,我们把字符串放入p2中实际上是将字符串的首元素地址放入p2中,而这样写代表着字符串是一个常量字符串,不能被修改,若想修改要将它放入数组中来修改
指针数组
指针数组是一个存放指针的数组
例如
int a = 10;
int b = 20;
int* arr[] = { &a,&b };
arr[] 放入的就是两个一级指针
利用指针数组实现类似的二维数组
int main()
{
int arr1[] = {
1,2,3,4,5 };
int arr2[] = {
2,3,4,5,6 };
int arr3[] = {
3,4,5,6,7 };
int* arr[] = {
arr1,arr2,arr3 };
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("%d ", *(arr[i] + j));
}
printf("\n");
}
return 0;
}
数组指针
数组指针是指向数组的指针
例1
int arr[10] = {
1,2,3,4,5 };
int(*p)[10] = &arr;
//但一般很少会这样写
二维数组传参
void print(int(*p)[5], int a, int b)
{
int i = 0;
for (i = 0; i < 2; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("%d ", *(*(p+i)+j));
}
printf("\n");
}
}
int main()
{
int arr[2][5] = {
0,1,2,3,4,5,6,7,8,9 };
print(arr, 2, 5);
}
void print(int(*p)[5], int a, int b)
{
int i = 0;
for (i = 0; i < 2; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("%d", p[i][j]);
}
printf("\n");
}
}
int main()
{
int arr[2][5] = {
0,1,2,3,4,5,6,7,8,9 };
print(arr, 2, 5);
}
二维数组的数组名是首元素的地址
二维数组的首元素是第一行
即二维数组数组名是第一行的地址
既然是第一行的地址,而二维数组可以看作是一行一行的一维数组累加在一起,那么可以把第一行的地址看作是一个一维数组的地址,那么传入数组的地址,我们就要拿一个数组指针接收
至于* (* (p+i)+j),假设把二维数组的第一行看作一维数组arr,那么二维数组名即为&arr, p即 * &arr,得到arr, (arr+j)即访问第一行的每一元素,(p+i)即(&arr+i),也就是跳过一行
那么判断一下**int( * arr[10])[5]**是什么
由于优先级的原因,arr先与[10]结合,说明arr是一个数组,我们除去arr[10]那么剩下的就是数组元素类型,所以数组元素类型为int(*)[5], 代表是一个指针,从往外看,看到[],说明指针指向的内容是数组,数组的元素是int类型,并且元素个数为5,我们不难看出,它是一个数组指针,即arr是一个可以存放10数组指针的数组
一级指针传参
#include <stdio.h>
void print(int *p, int sz)
{
int i = 0;
for(i=0; i<sz; i++)
{
printf("%d\n", *(p+i));
}
}
int main()
{
int arr[10] = {
1,2,3,4,5,6,7,8,9};
int *p = arr;
int sz = sizeof(arr)/sizeof(arr[0]);
//一级指针p,传给函数
print(p, sz);
return 0;
}
一级指针传参用一级指针接收,因为一级指针传过去的是arr,所以用一个一级指针接收,除此之外,若有一个整形数组,传数组名,也可以用一级指针接收
二级指针传参
二级指针传参用二级指针接收,除此之外,若有一个一级指针数组数组名,也可用用二级指针接收
函数指针
int Add(int x, int y)
{
return x + y;
}
int main()
{
int a = 10;
int b = 20;
int (*p)(int, int) = Add;
//int ret = (*p)(a, b);
int ret = p(a, b);
printf("%d", ret);
return 0;
}
Add就是函数的地址,&Add与Add是一回事
(*p)代表p为指针,往外看,看到(),说明指针指向的内容一个函数,函数的参数类型(int,int),函数的返回值int,所以p为一个函数指针
当我们想用Add()时,只需要 *p 就找到了Add,之后再加上要传入的实参,就可以使用函数了,Add(a,b)
,其实p里存放的是Add,那么就可以把p看作Add,所以不用 加 *也可以,只不过为了方便理解,加上了 *
有趣的代码
代码1
( * (void ( * )())0)()
从0下手,0前边的(void ( * )()仔细看的话,可以看出它是一个函数指针,只是这个函数没有参数,返回类型是void,在(void ( )()的基础上又加一个(),意思就是将0强制类型转换为(void ( )()类型,那么0就是一个函数指针,在0这个地址处存放着一个函数,这个函数返回类型是void,无参数, (void (* )())0前面又有一个* ,解引用这个函数指针,即调用这个函数,调用这个函数,函数无参数,直接在(* (void (* )())0)基础上加()
代码2
void ( * signal(int , void( * )(int)))(int)
由于优先级的原因,signal先与()结合,说明signal是一个函数,函数的参数是(int , void( * )(int)),有了函数名,又有了函数参数,现在缺一个返回类型,void ( * signal(int , void( * )(int)))(int),去掉函数名,与函数参数,即为返回类型,void( * )(int),返回类型是一个函数指针,参数是int,返回类型是void
函数指针数组
**void(*p)(int)**是一个函数指针,在它的基础上给p后面加上[],p先与[]结合形成数组,即void( * p[5])(int),除去数组名与[5]即数组元素类型,可以看出元素类型为函数指针
指向函数指针数组的指针
在函数指针数组void( * p[5])(int)基础上,改为void ( * (*p)[5]) (int)
函数指针数组的应用
int Add(int x, int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x - y;
}
int Mul(int x, int y)
{
return x * y;
}
int Div(int x, int y)
{
return x / y;
}
void menu()
{
printf("****************************\n");
printf("*****1.乘法***2.除法*********\n");
printf("*****3.加法***4.减法*********\n");
printf("*****0.退出*****************\n");
}
int main()
{
int a = 20;
int b = 10;
int(*arr[5])(int, int) = {
0,Mul,Div,Add,Sub };
int input = 0;
do
{
menu();
scanf("%d", &input);
if (input == 0)
{
printf("退出计算机\n");
}
else if (input >= 1 && input <= 4)
{
printf("请输入两个值");
scanf("%d %d", &a, &b);
int ret = arr[input](a, b);
printf("%d\n", ret);
}
else
printf("输入错误\n");
} while (input);
return 0;
}