C语言【指针篇】(四)

打印 上一主题 下一主题

主题 1030|帖子 1030|积分 3090

前言:

这是指针第四篇,主要先容:字符指针变量、数组指针变量、二维数组传参的本质、函数指针变量、函数指针数组以及函数指针数组的应用——转移表
正文

1. 字符指针变量

在指针的类型中有一种指针类型为字符指针char*。
一样平常使用方式如下:
  1. int main()
  2. {
  3.     char ch = 'w';
  4.     char *pc = &ch;
  5.     *pc = 'w';
  6.     return 0;
  7. }
复制代码
还有一种使用方式如下:
  1. int main()
  2. {
  3.     const char* ps = "hello C.";
  4.     printf("%s\n", ps);
  5.     return 0;
  6. }
复制代码
代码const char* ps = "hello C";轻易让人以为是把字符串hello C放到字符指针ps里了,但是本质是把字符串hello C.首字符的地点放到了ps中。实际是把一个常量字符串的首字符h的地点存放到指针变量ps中。
《剑指offer》中又一道与之相干的题目,代码如下:
  1. #include <stdio.h>
  2. int main()
  3. {
  4.     char str1[] = "hello C.";
  5.     char str2[] = "hello C.";
  6.     const char *str3 = "hello C.";
  7.     const char *str4 = "hello C.";
  8.     if(str1 ==str2)
  9.         printf("str1 and str2 are same\n");
  10.     else
  11.         printf("str1 and str2 are not same\n");
  12.     if(str3 ==str4)
  13.         printf("str3 and str4 are same\n");
  14.     else
  15.         printf("str3 and str4 are not same\n");
  16.     return 0;
  17. }
复制代码

为什么会有这样的结果呢?const修饰常量字符串,str3和strr4是指向同一个字符串的,在C语言中会把常量字符串单独存储到一个内存地区,虽然str3和str4变量名不同,但实际上指向同一片内存空间。然而,用同样的字符串初始化不同数组时会形成不同空间,即不同的内存块。所以str1和str2不同,str3和str4雷同。
2. 数组指针变量

2.1 数组指针变量是什么?

先区分一下,之前学过指针数组,它是一种数组,用来存放指针(也就是地点)
而数组指针变量,和·指针数组·不同,它是指针变量
举个栗子:
   int* pint 表示整型指针变量用来存放整型变量的地点
float* pf表示浮点型指针变量 , 用来存放浮点型数据的地点
  数组指针变量存放的是数组的地点,可以或许指向数组的指针变量。
这里用两个代码常常肴杂
  1. int *p1[10];
  2. int(*p2)[10];
复制代码
哪一个是数组指针变量呢?答案是p2即int(*p2)[10];p1是指针数组,p2先和连合,说明p2是一个指针变量,然后指针指向的是一个大小为 10 个整型的数组,所以p2是一个指针,指向一个数组,叫数组指针。
注意:[]的优先级是高于
的,所以必须加上()包管*和p是一起的
2.2 数组指针变量怎么初始化

数组指针变量是用来存放数组地点的,通过&数组名可以获得数组的地点。例如:
  1. int arr[10] = {0};
  2. &arr;
复制代码
如果要存放数组的地点,就得存放在数组指针变量中,如下:
  1. int(*p)[10] = &arr;
复制代码
调试可以看到&arr和p的类型是完全一致的。
数组指针类型解析:

3. 二维数组传参的本质

有了数组指针的底子理解,就可以或许讲一下二维数组传参的本质。
已往二维数组传参给一个函数时,写法如下:
  1. #include <stdio.h>
  2. void test(int a[3][5], int a, int b)
  3. {
  4.     int i = 0;
  5.     int j = 0;
  6.     for(i=0; i<a; i++)
  7.     {
  8.         for(j=0; j<b; j++)
  9.         {
  10.             printf("%d ", a[i][j]);
  11.         }
  12.         printf("\n");
  13.     }
  14. }
  15. int main()
  16. {
  17.     int arr[3][5] = {{1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7}};
  18.     test(arr, 3, 5);
  19.     return 0;
  20. }
复制代码
                                                  0                                          0                           0                                                  1                                          1                           1                                                  2                                          2                           2                                                  3                                          3                           3                                                  4                                          4                           4                                                  0                                          0                           0                                                  1                                          1                           1                                                  2                                          2                           2                                                  3                                          3                           3                                                  4                                          4                           4                                                  5                                          5                           5                                                  1                                          1                           1                                                  2                                          2                           2                                                  3                                          3                           3                                                  4                                          4                           4                                                  5                                          5                           5                                                  6                                          6                           6                                                  2                                          2                           2                                                  3                                          3                           3                                                  4                                          4                           4                                                  5                                          5                           5                                                  6                                          6                           6                                                  7                                          7                           7 arr数组 内容如上
实参是二维数组,形参也是二维数组,但是前面说过二维数组其实是一维数组的数组,二维数组的首元素是第一行,是一维数组,所以我们可以这样理解:二维数组数组名是第一行的地点,是一维数组的地点(指针),第一行的一维数组类型就是int [5],so,第一行的地点类型就是数组指针类型int(*) [5].这表示二维数组传参本质上也是转达了地点,转达的是第一行这个一维数组的地点,那么形参也是可以写成指针情势的,如下:
  1. #include <stdio.h>
  2. void test(int (*p)[5], int r, int c)
  3. {
  4.     int i = 0;
  5.     int j = 0;
  6.     for(i=0; i<r; i++)
  7.     {
  8.         for(j=0; j<c; j++)
  9.         {
  10.             printf("%d ", *(*(p+i)+j));
  11.         }
  12.         printf("\n");
  13.     }
  14. }
  15. int main()
  16. {
  17.     int arr[3][5] = {{1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7}};
  18.     test(arr, 3, 5);
  19.     return 0;
  20. }
复制代码
总结:二维数组传参,形参的部分可以写成数组,也可以写成指针情势。
4. 函数指针变量

4.1 函数指针变量的创建

函数指针变量应该是用来存放函数地点的,未来通过地点可以或许调用函数。
函数是有地点的,通过以下测试可以证实:
  1. #include <stdio.h>
  2. void test()
  3. {
  4.     printf("hehe\n");
  5. }
  6. int main()
  7. {
  8.     printf("test: %p\n", test);
  9.     printf("&test: %p\n", &test);
  10.     return 0;
  11. }
复制代码

输出结果中test和&test的地点雷同,函数名就是函数的地点,也可以通过&函数名的方式获得函数的地点。
如果要将函数的地点存放起来,就得创建函数指针变量,函数指针变量的写法和数组指针非常类似。例如:
  1. void test()
  2. {
  3.     printf("hehe\n");
  4. }
  5. void (*pf1)() = &test;
  6. void (*pf2)()= test;
  7. int Add(int x, int y)
  8. {
  9.     return x+y;
  10. }
  11. int(*pf3)(int x, int y) = &Add;
  12. int(*pf3)(int, int) = Add;
复制代码
函数指针类型解析:
  1. int (*pf3) ( int x, int y)
  2. //( int x, int y)——指向函数的参数类型和个数的交代
  3. //(*pf3)         ——函数指针变量名
  4. //int            ——pf3指向函数的返回类型
  5. int (*) (int x, int y) //pf3函数指针变量的类型
复制代码
4.2 函数指针变量的使用

现在写一个加法的函数,你可能会这样写:
  1. int add(int x,int y)
  2. {
  3.         return x + y;
  4. }
  5. int main()
  6. {
  7.         int r = add(2,5);
  8.         printf("%d",r);
  9.         return 0;
  10. }
复制代码
但我们学过上述内容后,通过函数指针调用指针指向的函数,示例代码如下:
  1. #include <stdio.h>
  2. int Add(int x, int y)
  3. {
  4.     return x+y;
  5. }
  6. int main()
  7. {
  8.     int(*pf3)(int, int) = Add;
  9.     printf("%d\n", (*pf3)(2, 3));
  10.     printf("%d\n", pf3(3, 5));
  11.     return 0;
  12. }
复制代码
4.3 两段有趣的代码

  1. (*(void (*)())0)();
  2. void (*signal(int , void(*)(int)))(int);
复制代码
两段代码均出自《C陷阱和缺陷》这本书。
可以自己写出来理解一下,正常环境我们不会这样写,着实理解不了也没关系,(也可以问问deepseek).
4.3.1 typedef关键字

typedef是用来类型重命名的,可以将复杂的类型简朴化。比如将unsigned int重命名为uint:
  1. typedef unsigned int uint;
复制代码
对于指针类型也能重命名,将int*重命名为ptr_t:
  1. typedef int* ptr_t;
复制代码
对于数组指针和函数指针重命名稍有区别。将数组指针类型int(*)[5]重命名为parr_t:
  1. typedef int(*parr_t)[5];
复制代码
将函数指针类型void(*)(int)重命名为pf_t:
  1. typedef void(*pfun_t)(int);
复制代码
简化代码2可以这样写:
  1. typedef void(*pfun_t)(int);
  2. pfun_t signal(int, pfun_t);
复制代码
5. 函数指针数组

数组是一个存放雷同类型数据的存储空间,已经学习了指针数组,例如int * arr[10];,数组的每个元素是int*。
把函数的地点存到一个数组中,这个数组就叫函数指针数组。函数指针数组定义为int (*parr1[3])();,parr1先和[]连合,说明parr1是数组,数组的内容是int (*)()类型的函数指针。
6. 转移表

函数指针数组的用途之一是转移表。
例如盘算器的一样平常实现代码如下:
  1. #include <stdio.h>
  2. int add(int a, int b)
  3. {
  4.     return a + b;
  5. }
  6. int sub(int a, int b)
  7. {
  8.     return a - b;
  9. }
  10. int mul(int a, int b)
  11. {
  12.     return a * b;
  13. }
  14. int div(int a, int b)
  15. {
  16.     return a / b;
  17. }
  18. int main()
  19. {
  20.     int x, y;
  21.     int input = 1;
  22.     int ret = 0;
  23.     do
  24.     {
  25.         printf("*************************\n");
  26.         printf(" 1:add 2:sub \n");
  27.         printf(" 3:mul 4:div \n");
  28.         printf(" 0:exit \n" );
  29.         printf("*************************\n");
  30.         printf("请选择:");
  31.         scanf("%d", &input);
  32.         switch (input)
  33.         {
  34.         case 1:
  35.             printf("输入操作数:");
  36.             scanf("%d %d", &x, &y);
  37.             ret = add(x, y);
  38.             printf("ret = %d\n", ret);
  39.             break;
  40.         case 2:
  41.             printf("输入操作数:");
  42.             scanf("%d %d", &x, &y);
  43.             ret = sub(x, y);
  44.             printf("ret = %d\n", ret);
  45.             break;
  46.         case 3:
  47.             printf("输入操作数:");
  48.             scanf("%d %d", &x, &y);
  49.             ret = mul(x, y);
  50.             printf("ret = %d\n", ret);
  51.             break;
  52.         case 4:
  53.             printf("输入操作数:");
  54.             scanf("%d %d", &x, &y);
  55.             ret = div(x, y);
  56.             printf("ret = %d\n", ret);
  57.             break;
  58.         case 0:
  59.             printf("退出程序\n");
  60.             break;
  61.         default:
  62.             printf("选择错误\n");
  63.             break;
  64.         }
  65.     } while (input);
  66.     return 0;
  67. }
复制代码
使用函数指针数组的实现:
  1. #include <stdio.h>
  2. int add(int a, int b)
  3. {
  4.     return a + b;
  5. }
  6. int sub(int a, int b)
  7. {
  8.     return a - b;
  9. }
  10. int mul(int a, int b)
  11. {
  12.     return a*b;
  13. }
  14. int div(int a, int b)
  15. {
  16.     return a / b;
  17. }
  18. int main()
  19. {
  20.     int x, y;
  21.     int input = 1;
  22.     int ret=0;
  23.     int(*p[5])(int x, int y) = { 0, add, sub, mul, div };
  24.     do
  25.     {
  26.         printf("*************************\n");
  27.         printf(" 1:add 2:sub \n");
  28.         printf(" 3:mul 4:div \n");
  29.         printf(" 0:exit \n" );
  30.         printf("*************************\n");
  31.         printf("请选择:");
  32.         scanf("%d", &input);
  33.         if ((input <= 4 && input >= 1))
  34.         {
  35.             printf("输入操作数:");
  36.             scanf("%d %d", &x, &y);
  37.             ret = (*p[input])(x, y);
  38.             printf("ret = %d\n", ret);
  39.         }
  40.         else if(input == 0)
  41.         {
  42.             printf("退出计算器\n");
  43.         }
  44.         else
  45.         {
  46.             printf("输入有误,重新选择\n");
  47.         }
  48.     }while (input);
  49.     return 0;
  50. }
复制代码
总结

本文就到这里了,如有误,接待指正,指针很难,但坚持下去,终有收获,朋友,把这件事坚持下去吧。
敬,不完美的明天。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

用户云卷云舒

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表