C语言:指针进阶(上)

目录

一、字符指针

二、数组指针

1).概念

2).应用(二维数组)

三、函数指针

1).概念

2).函数指针数组

3).应用

1. 通过函数指针调用函数

2. 转移表(函数指针数组)


先来回忆一下指针概念:
       1. 指针就是变量,用来存放地址,地址唯一标识一块内存空间。

       2. 指针的大小是固定的4/8个字节(32位平台/64位平台)。

       3. 指针有类型,指针的类型决定了指针的+-整数的步长,指针解引用操作时的权限。

一、字符指针

字符指针类型————char*

存放字符地址:

char ch = 'w';
char* pc = &ch;

存放字符串首字符地址:

char* p = "abcdef";

加上const:

const char* p = "abcdef";

此时*p不能作任何修改。

《剑指offer》中的一道和字符串相关的题:

#include <stdio.h>
 int main()
 {
     char str1[] = "hello world.";
     char str2[] = "hello world.";
     const char *str3 = "hello world.";
     const char *str4 = "hello world.";

     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;
 }

打印结果为:

 

原因:

所以str1 != str2,str3 == str4。

二、数组指针

1).概念

字符指针——存放字符地址——指向字符——char*

整型指针——存放整型地址——指向整型——int*

浮点型指针——存放浮点型地址——指向浮点型——float*,double*

数组指针——存放数组地址——指向数组

int main()
{
	char ch = 'w';
	char* pc = &ch;

	int a = 10;
	int* pi = &a;

	int arr[10] = { 0 };
	int (*pa)[10] = &arr;
	return 0;
}

注意:1. []的优先级高于*号,必须加上()来保证p先和*结合。 

           2. 指针接收的是&arr,不能直接写arr。
因为:

数组的地址(&arr)和数组首元素地址(arr/&arr[0])从值的角度来看相同,但是意义不同。 

2).应用(二维数组)

有一个二维数组的需要传参给一个函数的时候,可以这样写的:

这里实参,形参都是二维数组的形式。

还可以这样写:


二维数组的数组名表示的就是第一行的地址,是一维数组的地址。根据上面的例子,第一行的一维数组的类型就是型就是数组指针类型 int [5],所以第一行的地址的类型 int(*)[5] 。那就意味着二维数组传参本质上也是传递了地址,传递的是第一行这个一维数组的地址

总结:二维数组传参,形参的部分可以写成数组,也可以写成指针

三、函数指针

1).概念

函数指针——存放函数地址——指向函

函数指针变量用来存放函数地址,未来通过地址能够调用函数

pf就是函数指针,存放函数地址 。同时,也可以通过函数地址来调用函数:

所以函数是有地址的,函数名就是函数的地址,也可以通过&函数名的方式获得函数的地址。 

函数指针类型解析: 

再来看两句代码(出自:《C陷阱和缺陷》):

1  (*(void (*) () )0)();

该代码是一次函数调用,首先将0强制类型转换为void ( * ) ( )的函数指针,然后*解引用调用0地址处的函数

2  void (*signal(int , void(*)(int) ) )(int);

该代码是一次函数声明,声明的函数名是signal,该函数的参数类型分别为int,void (*) (int),返回类型是函数指针类型,为void (*) (int)

该代码还可以这样写,便于理解:

2).函数指针数组

数组是一个存放相同类型数据的存储空间,我们已经学习了指针数组, 比如:

  int * arr[10];
//数组的每个元素是int*

那要把函数的地址存到一个数组中,那这个数组就叫函数指针数组,如何定义函数指针数组?

  int (*parr1[3])();
  int *parr2[3]();

其中parr1表示函数指针数组,parr1 先和 [] 结合,说明parr1是数组,元素类型为int (*) ( )。

指向函数指针数组的指针:

拆解一下: (参考数组指针)

3).应用

1. 通过函数指针调用函数

int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int(*pf3)(int, int) = Add;
	printf("%d\n", (*pf3)(2, 3));
	printf("%d\n", pf3(2, 3));
	return 0;
}

2. 转移表(函数指针数组)

以计算器为例,一般实现:

int add(int a, int b)
{
    return a + b;
}
int sub(int a, int b)
{
    return a - b;
}
int mul(int a, int b)
{
    return a * b;
}
int div(int a, int b)
{
    return a / b;
}

int main()
{
    int x, y;
    int input = 1;
    int ret = 0;
    do
    {
        printf("*************************\n");
        printf("  1:add           2:sub  \n");
        printf("  3:mul           4:div  \n");
        printf("  0:exit                 \n");
        printf("*************************\n");
        printf("请选择:");
        scanf("%d", &input);
        switch (input)
        {
        case 1:
            printf("输入操作数:");
            scanf("%d %d", &x, &y);
            ret = add(x, y);
            printf("ret = %d\n", ret);
            break;
        case 2:
            printf("输入操作数:");
            scanf("%d %d", &x, &y);
            ret = sub(x, y);
            printf("ret = %d\n", ret);
            break;
        case 3:
            printf("输入操作数:");
            scanf("%d %d", &x, &y);
            ret = mul(x, y);
            printf("ret = %d\n", ret);
            break;
        case 4:
            printf("输入操作数:");
            scanf("%d %d", &x, &y);
            ret = div(x, y);
            printf("ret = %d\n", ret);
            break;
        case 0:
            printf("退出程序\n");
            break;
        default:
            printf("选择错误\n");
            break;
        }
    } while (input);

    return 0;
 }

使用函数指针数组的实现:

int main()
{
    int x, y;
    int input = 1;
    int ret = 0;
    int(*p[5])(int x, int y) = { 0, add, sub, mul, div };
    do
    {
        printf("*************************\n");
        printf("  1:add           2:sub  \n");
        printf("  3:mul           4:div  \n");
        printf("  0:exit                 \n");
        printf("*************************\n");
        printf("请选择:");
        scanf("%d", &input);
        if ((input <= 4 && input >= 1))
        {
            printf("输⼊操作数:");
            scanf("%d %d", &x, &y);
            ret = (*p[input])(x, y);
            printf("ret = %d\n", ret);
        }
        else if (input == 0)
        {
            printf("退出计算器\n");
        }
        else
        {
            printf("输⼊有误\n" );        
        }
    } while (input);
    return 0;
}

p数组里有5个元素,每个元素都是int(*)(int, int)类型,通过修改input的值来访问p数组中的元素,也就是调用函数,(修改下标)。

完,感谢阅读。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值