小工具知识网

当前位置: 首页 > 行业知识 > 【C语言】指针篇-一篇搞定不同类型指针变量-必读指南(3/5)

行业知识

【C语言】指针篇-一篇搞定不同类型指针变量-必读指南(3/5)

2026-11-06 00:03:52 来源:互联网转载
  男儿不展风云志,空负天生八尺躯。——《警世通言·卷四十》

个人主页:是店小二呀

C语言笔记专栏:C语言笔记

C++笔记专栏: C++笔记

喜欢的诗句:无人扶我青云志 我自踏雪至山巅

上篇回顾:上篇我们通过数组名为切入口引出数组与指针间的关系,本篇将介绍不同类型的指针变量在不同场景中的使用

文章目录

  • 一、字符指针变量
  • 二、数组指针变量(指针数组,这里需要注意偏正)
    • 2.1 数组指针的初始化
    • 2.2 二维数组传参的本质
    • 三、函数指针变量
      • 3.1 函数指针变量初始化
      • 四、函数指针数组
      • 五、转移表
      • 六、typedef 关键字

        一、字符指针变量

        对于字符和字符串,C语言统一使用char类型来表达式。对此字符指针变量有两种表示方法:

        1. 第一种: char ch='a'; char *p=&ch;
        2. 第二种: const char *pstr="Hellow world";

        问题:关于const char *pstr="Hellow world"是将整个字符串放到字符指针里面了吗?

        解释:本质是字符串"Hellow world"首字符(H)的地址放到字符指针变量pstr中.

        【面试题:剑指offer】:

        int main(){char str1[] = "hellow world";char str2[] = "hellow world";const char *str3 = "hellow world";const char *str4 = "hellow 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 and str2 are not same str3 and str4 are same

        【解释】:

        str3和str4指向的是一个同一个常量字符串。C/C++会把常量字符串储存到单独的一个内存区域(常量区),当多个指针指向同一个字符串时,实际是指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时就会开辟不同的内存块,更直白说就算将常量字符串从常量区拷贝一份到数组中,那么在数组初始化时就会在栈中开辟不同的内存块。

        使用指针初始化的"hello world"是一个常量字符串,str3指向首字符地址,但该地址在于进程的text段,text段可以保存常量还可以执行代码,是不允许可写权限,只有可读、可执行权限(了解即可)

        char *p="hellow";p[1]='d';//*(p+1)='d';//出现段错误

        二、数组指针变量(指针数组,这里需要注意偏正)

        • 整形指针变量:int *p(存放的是整形变量的地址,能够指向整形数据的指针)
        • 字符指针变量:char *p(存放的是字符或字符串首元素的地址,能够指向字符或者字符串数据的指针)

          依次类推

          数组指针变量:存放的是数组的地址,能够指向数组的指针变量

          那个是数组指针变量?那个是指针数组变量?int *p1[10];int (*p2)[10];

          注:[]的优先级高于*。

          • p1和[]结合形成一个数组,指向数组中int *类型的元素,是指针数组。

          • p2和 *加上了()保证了p2先和 *结合形成一个指针,指向一个大小为10个整形的数组(指向一个多大的数组),是数组指针(存放的是数组的地址)

            2.1 数组指针的初始化

            int (*p) [10] = &arr;|     |    ||     |    ||     |    []:p指向数组的元素个数|     p:数组指针变量名int:p指向的数组的元素类型

            2.2 二维数组传参的本质

            二维数组是由多个一维数组组成的,也是连续存放数据。这样说明:二维数组的每个元素都是一个一维数组,根据数组名是数组首元素的地址这个规则,二维数组的数组名表示是第一行的地址(一维数组的地址)

            对此第一行的地址的类型是数组指针类型int(*)[5]。意味着跟一维数组传参本质一样,也是传递地址,传递的是第一行这个一维数组的地址

            小总结:二维数组传参,形参的部分可以采用数组或者指针形式

            void test1(int nums[][5]);//数组类型void test2(int (*nums)[5]);//指针类型int main(){    int nums[][5]={{1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7}};    test1(nums);    test2(nums);    return 0;}

            三、函数指针变量

            函数指针变量:存放函数地址的,通过函数的地址来调用函数

            问题:那么如何得到函数的地址呢?

            void test();int main(){    printf("&test==%p",&test());    printf("test==%p",test());    return 0;}结果:&test==00991253test==00991253

            通过输出的结果:函数是有地址的,函数名就是函数的地址,&函数名的方式也可以获得函数的地址

            void (*pf1)() = &test;void (*pf2)() = test;

            3.1 函数指针变量初始化

            int    (*pf3)        (int x, int y) |        |           ------------ |        |                 | |        |     pf3指向函数的参数类型和个数的交代 |    函数指针变量名 pf3指向函数的返回类型    int (*) (int x, int y) //pf3函数指针变量的类型

            函数指针变量的使用(通过函数指针调用指针指向的函数)

            int Add(int x,int y){return x+y;}int main(){    int (*p)(int x,int y)=Add;//如果需要存放多个函数地址,需要使用到函数指针数组    printf("%d\n",(*p)(a,b));    printf("%d\n",p(a,b));    return 0;}

            说明:p(a,b)跟(*p)(a,b)效果是相同的,因为函数名本身就是函数指针变量


            四、函数指针数组

            如果我们需要把多个函数的地址存在数组中,函数名是一个函数指针变量,就需要利用到指针数组和函数配合了

            存放函数的地址的指针数组

            int (*)()(类型的函数指针):void (*p[3])(void x,void y)={Add,Sub};方便理解:p[] = x;void (*x)(void x,void y)={Add,Sub};

            说明:p先和[]结合,说明p是数组,数组的内容void (*)()类型的函数指针。


            五、转移表

            函数指针数组的用途:转移表

            比如:使用函数指针数组实现计算器

            实现函数功能

            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 p(int a, int b){return a / b;}
            int main(){int x = 0, y = 0;//操作数int input = 0;//选择功能//前面加个0,方便输入数字得到相对函数功能int (*computer[5])(int x,int y) = {0,add,sub,mul,p };do{mune();scanf("%d", &input);if (0 

上一篇:宝塔面板DNS性能深度解析,表现究竟如何?

下一篇:GitHub发音指南,轻松掌握GitHub正确读音