目录
1 字符指针变量
2 数组指针变量
2.1 什么是数组指针变量
2.2 数组指针变量的初始化
3 二维数组传参的本质
4 函数指针变量
4.1 两个有趣的代码
4.2 typedef关键字
5 函数指针数组
6 函数指针数组的应用---计算器的实现
6.1 计算器的一般实现
6.2 利用函数指针数组实现
6.3 一般实现的改进
在指针的类型中有一种指针类型为字符指针char*,一般使用:
#include
int main()
{
char ch = 'a';
char* pc = &ch;
*pc = 'a';
return 0;
}
还有一种使用方式如下:
#include
int main()
{
const char* pstr = "hello world";
printf("%s\n", pstr);
return 0;
}
代码const char* pstr = "hello world";一些初学者就会误认为是把字符串hello world放入字符指针pstr里,但其实是把字符串hello world的首字符h的地址放到了pstr中。
#include
int main()
{
char str1[] = "hello bit.";
char str2[] = "hello bit.";
const char* str3 = "hello bit.";
const char* str4 = "hello bit.";
if (str1 == str2)
printf("str1 and str2 are same\n");
else
printf("str1 and str2 are not same\n");
if (str3 == str4)
printf("str3 and str4 are same\n");
else
printf("str3 and str4 are not same\n");
return 0;
}打印出什么结果?
输出结果:
这里的str3和str4指向相同的常量字符串,C语言中把 常量字符串存储到单独的一个内存区域,多个指针指向同一个字符串时,指向的内存是相同的。而相同的常量字符串初始化不同数组时就会申请不同的内存块。所以str1和str2不同,str3和str4相同。
数组指针变量存放的是数组的地址,能够指向数组的指针变量。
1 int *p1[10];//指针数组
2 int (*p2)[10]p;//数组指针
p与*结合,说明p是一个指针变量,然后指向一个大小为10个整型的数组。所以p是一个指针,指向一个数组,叫数组指针。
[]的优先级高于*号,所以必须加上()来保证p与*先结合。
如果要存放数组的地址,就要存放在数组指针变量中。
int(*p)[10]=&arr;
其中p是数组指针变量名,10是p指向数组的元素个数,int是p指向的数组的数据类型。
将p去掉,int(*)[10]就是数组指针变量的数据类型。
有了对数组指针的理解,就可以理解二维数组传参的本质。
如果不利用指针,我们将二维数组传参给一个函数,一般这样写:
#include
void test(int arr[3][5], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { {1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15} };
test(arr, 3, 5);
return 0;
}
二维数组起始可以看做是每个元素是一维数组的数组,也就是二维数组每一个元素是一个一维数组,第一个元素就是第一行。所以,二维数组的数组名就代表第一行的地址,根据上面代码的例子,第一行一维数组的类型是int[5],第一行地址类型就是int(*)[5],意味着二维数组传参本质上也是传递了地址,传递的是第一行一维数组的地址,代码如下:
#include
void test(int (*p)[5], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
printf("%d ",*(*(p+i)+j));
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { {1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15} };
test(arr, 3, 5);
return 0;
}
函数指针变量是用来存放函数地址的,可以通过地址来调用函数。
函数是否有地址呢?可以编写代码测试一下:
void test()
{
printf("hello world");
}
#include
int main()
{
printf("test: %p\n", test);
printf("&test:%p\n", &test);
return 0;
}
输出结果:
所以函数也是有地址的,函数名就是函数的地址。如果要将函数的地址存放起来,就要创建函数指针变量,函数指针变量的创建和数组指针变量的创建类似:
int Add(int x, int y)
{
return x + y;
}
int (*pf)(int, int) = Add;//x和y可以省略
int (*pf)(int x, int y) = Add;
其中pf是函数指针变量名,(int x,int y)是交代指向的函数参数类型,int是pf指向函数的返回类型。pf函数指针的数据类型是int (*) (int x,int y)。
函数指针变量的使用:
#include
int Add(int x, int y)
{
return x + y;
}
int main()
{
int(*pf)(int, int) = Add;
printf("%d", pf(3, 3));
return 0;
}
代码1:(*(( void (*) () )0)) ();
解释:
void (*) () ---函数指针类型
(( void (*) () )---强制类型转换
(( void (*) () )0---将0强制类型转换成为 void (*) ()的函数指针类型,意味着0这个地址放着无参数,返回类型是void的函数。
(*(( void (*) () )0)) ();最终调用0地址存放的函数
代码2:void (*signal(int, void(*)(int)))(int);
解释:
signal(int, void(*)(int))---signal是函数名,int和void(*)(int)是参数,如果把signal(int, void(*)(int))去掉,剩下的void (*)(int)是函数返回值类型。*必须放在名字的旁边。代码的意义是声明一个为signal(int, void(*)(int))的函数,返回类型是void (*)(int)。
typedef是用来类型重命名的,可以将复杂的类型简单化,举例:
1 typedef unsigned int uint
//将unsigned int重命名为uint
指针类型的重命名:
typedef int* ptr_t
数组指针类型的重命名:例如将一个数据类型为int(*)[5]重命名为parr_t:
typedef int(*parr_t)[5];//新的类型名必须在*右边
函数指针类型的重命名:例如将一个数据类型为void(*)(int)重命名为pf_t:
typedef void(*pf_t)(int);//新的类型名必须在*右边
把函数的地址存到一个数组中,那么这个数组就叫函数指针数组。
函数指针数组的定义:
int (*parr)();
数组里的内容是int (*)()类型的函数指针。
编写一个计算器的代码时,一般会这么写:
//计算器实现 普通方法
#include
void menu()
{
printf("*******1.加法*******\n");
printf("*******2.减法*******\n");
printf("*******3.乘法*******\n");
printf("*******4.除法*******\n");
printf("*******0.退出*******\n");
}
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;
}
int main()
{
int input = 1;
int x = 0;
int y = 0;
int ret = 0;
do
{
menu();//菜单
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
printf("请输入两个操作数:>");
scanf("%d%d", &x, &y);
ret = Add(x, y);
printf("结果为:%d\n", ret);
break;
case 2:
printf("请输入两个操作数:>");
scanf("%d%d", &x, &y);
ret = Sub(x, y);
printf("结果为:%d\n", ret);
break;
case 3:
printf("请输入两个操作数:>");
scanf("%d%d", &x, &y);
ret = Mul(x, y);
printf("结果为:%d\n", ret);
break;
case 4:
printf("请输入两个操作数:>");
scanf("%d%d", &x, &y);
ret = Div(x, y);
printf("结果为:%d\n", ret);
break;
case 0:
printf("退出程序\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
int (*p[5])(int, int) = { 0,Add,Sub,Mul,Div };//定义一个函数指针数组
//计算器实现 函数指针数组
#include
void menu()
{
printf("*******1.加法*******\n");
printf("*******2.减法*******\n");
printf("*******3.乘法*******\n");
printf("*******4.除法*******\n");
printf("*******0.退出*******\n");
}
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;
}
int main()
{
int input = 1;
int x = 0;
int y = 0;
int ret = 0;
int (*p[5])(int, int) = { 0,Add,Sub,Mul,Div };
do
{
menu();//菜单
printf("请选择:>");
scanf("%d", &input);
if (input > 0 && input < 5)
{
printf("请输入两个操作数:>");
scanf("%d%d", &x, &y);
ret = (*p[input])(x,y);
printf("结果为:>%d\n", ret);
}
else if (input == 0)
{
printf("退出程序\n");
break;
}
else
{
printf("输入错误,请重新输入:>\n");
break;
}
} while (input);
return 0;
}
当我们使用一般方法写一个计算器时,case后面的代码重复率过高,输入输出操作造成冗余,可以把调用的函数地址以参数形式传递过去,使用函数指针接收,函数指针指向什么函数就调用什么函数,这种方法也叫做利用回调函数:
//计算器实现 普通方法 方法二
#include
void menu()
{
printf("*******1.加法*******\n");
printf("*******2.减法*******\n");
printf("*******3.乘法*******\n");
printf("*******4.除法*******\n");
printf("*******0.退出*******\n");
}
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 calc(int (*p)(int,int))
{
int x, y;
printf("请输入两个操作数:>");
scanf("%d%d", &x, &y);
int ret = p(x, y);
printf("结果为:%d\n", ret);
}
int main()
{
int input = 1;
int x = 0;
int y = 0;
int ret = 0;
do
{
menu();//菜单
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
calc(Add);
break;
case 2:
calc(Sub);
break;
case 3:
calc(Mul);
break;
case 4:
calc(Div);
break;
case 0:
printf("退出程序\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
以上就是有关指针的部分内容了,如果这篇文章对你有用,可以点点赞哦,你的支持就是我写下去的动力,后续会继续更新指针的剩余知识。