目录
字符指针变量
字符指针变量是指向字符的,储存的是字符的地址。
int main()
{
char ch = 'w';
char* p = &ch;
printf("%c ", *p);
}
int main()
{
char arr[10] = "abcdefg";
char* p = arr;
printf("%s ", p);
printf("%s ", arr);
return 0;
}
#include<stdio.h>
int main()
{
const char* p = "abcdef";//字符串"abcdef"为常量字符串,不能被修改
printf("%c ", *p);//这次赋值是将字符串首字符a的地址赋给p
//*p='w';
//不被允许,原因是"abcdef"为常量字符串不能修改,否则程序会崩溃。
return 0;
}
数组指针变量
指向数组的指针,存放的是数组的地址。
要跟 指针数组 做好区分。
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int (*p)[10] = &arr;
//p的类型,去掉p,即int (*)[10]
}
既然有数组指针变量,那是否能利用数组指针变量来打印数组内容呢?
答案是肯定的。
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int (*p)[10] = &arr;
for (int i = 0; i < 10; i++)
{
printf("%d ", (*p)[i]);
//*p=arr
}
return 0;
}
但是这样用大家是不是会觉得太麻烦?远远不如用数组来得简单?
这是因为很少人会这样用数组指针类型 ,那更为常见的方法是什么呢?
这就要谈谈二维数组传参的本质了。
二维数组传参的本质
我们先来用函数打印一下二维数组。
#include<stdio.h>
void Printf(int arr[4][6],int r,int c)
{
for (int i = 0; i < r; i++)
{
for (int j = 0; j < c; j++)
{
printf("%2d ", arr[i][j]);
}
printf("\n");
}
}
int main()
{
int arr[4][6] = { {1,2,3,4,5,6},{7,8,9,10,11,12},{13,14,15,16,17,18},{19,20,21,22,23,24} };
//打印数组元素
Printf(arr,4,6);
}
这里实参是二维数组,形参也写成二维数组形式,还有其他写法吗?
二维数组的每一行其实是一个一维数组,那么二维数组其实可以理解为是一维数组的数组。
也就是说,二维数组的每个元素其实是一个一维数组。
按照这样的逻辑,二维数组的数组名代表的就是第一行的地址,是一维数组的地址。
那就意味着,二维数组传参本质上也是传递了地址,传递的是第一行这个一维数组的地址。
那么形参也是可以写成指针形式的:
void Printf(int(*arr)[6], int r, int c)
{
for (int i = 0; i < r; i++)
{
for (int j = 0; j < c; j++)
{
printf("%2d ", *(*(arr+i)+j));//用arr[i][j]也一样。
}
printf("\n");
}
}
int main()
{
int arr[4][6] = { {1,2,3,4,5,6},{7,8,9,10,11,12},{13,14,15,16,17,18},{19,20,21,22,23,24} };
//打印数组元素
Printf(arr,4,6);
}
函数指针变量
函数指针变量的创建
函数指针是指向函数的,储存的是函数的地址。
函数名是函数的地址,&函数名也是函数的地址。
注意:
在数组中,arr!=&arr.
而在函数中,例:add == &add.
#include<stdio.h>
int add(int a, int b)
{
return a + b;
}
int main()
{
int a = 1;
int b = 4;
int r = add(a, b);
printf("%p\n", add);
printf("%p", &add);
return 0;
}
如果我们要把函数的地址存放起来,当然就需要函数指针变量 。
int main()
{
int (*p)(int a, int b) = &add;
int (*p)(int , int ) = &add;
return 0;
}
上面的代码,变量省不省略都是可以的 。
函数指针类型就是:int(*)(int ,int)
函数指针类型解析:
int :代表指针指向函数的返回类型
* :代表指针。
p :函数指针变量名。
(int ,int) :指针指向函数的参数类型和个数的。
函数指针变量的使用
通过函数指针调用指针指向的函数
#include<stdio.h>
int add(int a, int b)
{
return a + b;
}
int main()
{
int(*p)(int, int) = &add;
int r = p(3, 4);//p=&add=add
printf("%d ", r);
return 0;
}
ge用*p/p都是可以的。
两个有趣的代码
大家可以思考一下它代表的含义,再看我给的解释哦~
(*(void(*)())0)();
这个代码看着是不是很让人头疼?让我们来找一个切入点吧。
从0开始看,0前面的()中是一个函数指针类型,例如:int r=(int)3.14。你是否可以猜出来这是强制类型转换呢?然后把这个指针解引用再使用这个函数。这就是这段代码的意义了。
void(*signal(int, void(*)(int)))(int);
切入点 signal(int,void(*)(int))从这里我们可以看出来它是一个函数,一个参数类型为int,另一个为void(*)(int)。然后看剩余的一部分,void(*)(int)你是否可以看出它是一个函数指针类型呢?
结论:这串代码是一个函数声明!!!你看出来了吗?
其实 void(*signal(int,void(*)(int)))(int)==void(*)(int) signal(int,void(*)(int)),为了体现它指针的性质,我们把它放在*附近。
typedef 关键字
typedef是用来类型重命名的,可以将复杂的类型简单化。
如果我们觉得 unsigned int不方便,我们可以把它重命名为 unin
typedef unsigned int unin;
unin a = 10;
同样,我们也可以命名指针类型
typedef int* nin;
但是,函数指针跟数组指针稍微有点区别。
typedef int(*as)[6];
typedef int(*ds)(int, int);
将 int(*)[6] 类型重命名为 as。
最后,我再告诉大家一个小细节,
int*p1,p2;类型是否相同呢?
答案是否定的,p1的类型为 int*,p2则为int。正确的写法是:int*p1,*p2;
而用typedef重命名的类型则不一样,nin p3,p4; 类型都为int*。
函数指针数组
前边我们已经学习了指针数组,我们把函数的地址放在数组中,就叫函数指针数组。
函数指针数组的创建:
int(*arr[6])(int, int);
转移表
函数指针数组的用途:转移表
使用函数来实现计算机,大家会不会感觉这有点过于繁琐,冗余呢?
void menu()
{
printf("***********************\n");
printf("***1.add*****2.sub*****\n");
printf("***3.mul*****4.div*****\n");
printf("********0.exit*********\n");
printf("***********************\n");
}
void add(int x, int y)
{
printf("%d\n", x + y);
}
void sub(int x, int y)
{
printf("%d\n", x - y);
}
void mul(int x, int y)
{
printf("%d\n", x * y);
}
void div(int x, int y)
{
printf("%d\n", x / y);
}
int main()
{
int a = 0;
int x = 0,y=0;
do
{
menu();
printf("请选择:");
scanf("%d", &a);
switch (a)
{
case 1:
printf("您已进入游戏\n");
scanf("%d %d", &x, &y);
add(x,y);
break;
case 2:
printf("您已进入游戏\n");
scanf("%d %d", &x, &y);
sub(x,y);
break;
case 3:
printf("您已进入游戏\n");
scanf("%d %d", &x, &y);
mul(x,y);
break;
case 4:
printf("您已进入游戏\n");
scanf("%d %d", &x, &y);
div(x,y);
break;
case 0:
printf("您已退出游戏\n");
break;
default:
break;
}
} while (a);
return 0;
}
接下来让我们看看用函数指针数组代码的实现吧。
#include<stdio.h>
void menu()
{
printf("***********************\n");
printf("***1.add*****2.sub*****\n");
printf("***3.mul*****4.div*****\n");
printf("********0.exit*********\n");
printf("***********************\n");
}
void add(int x, int y)
{
printf("%d\n", x + y);
}
void sub(int x, int y)
{
printf("%d\n", x - y);
}
void mul(int x, int y)
{
printf("%d\n", x * y);
}
void div(int x, int y)
{
printf("%d\n", x / y);
}
int main()
{
int a = 0;
void(*arr[5])(int, int) = { 0, add,sub,mul,div };//多加一个0,使得case 数值后的数字与选择的函数相匹配。
do
{
menu();
printf("请选择:");
scanf("%d", &a);
if ((a > 0) && (a < 5))
{
int x = 0, y = 0;
printf("您已进入游戏\n");
scanf("%d %d", &x, &y);
arr[a](x, y);
}
else if (a == 0)
printf("退出");
else
printf("你输错了");
} while (a);
return 0;
}
今天的内容到此结束,下一个博客再见~