C语言 指针进阶

news2024/11/24 15:45:50

目录

数组指针

指针数组访问数组元素

再次讨论数组名

数组指针访问一维数组(但是这样会很别扭)

访问二维数组元素

非数组指针访问

数组指针访问

 数组传参Demo

一维数组传参

二维数组传参

指针数组指针

字符指针

函数指针

函数指针调用时可以不用写*解引用

函数作为回调传参

解释: (*(void (*)())0)();

解释: void (*signal(int, void (*)(int)))(int);

函数指针数组指针


 

数组指针

数组指针——>指向数组的指针

    int ary[10] = {0};
    int p = ary;
    int *p1[10];         // p1是指针数组
    int(*p2)[10] = &ary; // p2是数组指针,(&ary取的是整个数组的地址)p2可以指向一个数组,该数组有10个元素,每个元素是int类型,数组指针的类型是int (*)[10]

指针数组访问数组元素

    int arr1[] = {1, 2, 3, 4, 5};
    int arr2[] = {2, 3, 4, 5, 6};
    int arr3[] = {3, 4, 5, 6, 7};
    int *parr[3] = {arr1, arr2, arr3}; // 指针数组
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 5; j++)
        {
            /* *(p+i) ——> p[i] */
            // printf("%d ", *(parr[i] + j));
            printf("%d ", parr[i][j]);
        }
        printf("\n");
    }

再次讨论数组名

数组名通常表示的都是数组首元素的地址
但是有2个例外:
   1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小
   2. &数组名,这里的数组名表示的依然是整个数组,所以&数组名取出的是整个数组的地址

 例

    int arr[10] = {0};
    printf("%p\n", arr);     // 0000003199fff960
    printf("%p\n", arr + 1); // 0000003199fff964 加4个字节

    printf("%p\n", &arr[0]);     // 0000003199fff960
    printf("%p\n", &arr[0] + 1); // 0000003199fff964 加4个字节

    printf("%p\n", &arr);     // 0000003199fff960
    printf("%p\n", &arr + 1); // 0000003199fff988 加40个字节

数组指针访问一维数组(但是这样会很别扭)

    int ARR[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int(*P)[10] = &ARR;
    int SZ = sizeof(ARR) / sizeof(ARR[0]);
    for (int i = 0; i < SZ; i++)
    {
        /* 1 2 3 4 5 6 7 8 9 10 */
        printf("%d", *(*P + i)); // P指向数组的人,*P其实就相当于数组名,数组名又是数组首元素的地址。所以*p本质上就是数组首元素的地址
    }
    printf("\n");

思考一下:与其 int(*P)[10] = &ARR 这么麻烦,为什么不直接使用 int *p = arr 呢?这是因为数组指针的更适合和二维数组相结合,如下

访问二维数组元素

非数组指针访问

    int ARRAY[3][5] = {
        1, 2, 3, 4, 5,
        2, 3, 4, 5, 6,
        3, 4, 5, 6, 7};

    void printf1(int arr[3][5], int r, int c)
    {
        for (int i = 0; i < r; i++)
        {
            for (int j = 0; j < c; j++)
            {
                printf("%d", arr[i][j]);
            }
            printf("\n");
        }
    }
    printf1(ARRAY, 3, 5);

数组指针访问

    int ARRAY[3][5] = {
        1, 2, 3, 4, 5,
        2, 3, 4, 5, 6,
        3, 4, 5, 6, 7};

    void printf2(int (*p)[5], int r, int c) // p指向第一个数组的地址
    {
        for (int i = 0; i < r; i++)
        {
            for (int j = 0; j < c; j++)
            {
                /*
                p+i 是每个一维数组的地址,*(p + i)解引用得到每个数组arr,arr又是每个数组的首元素    地址,进一步找到每个数组的每个元素的地址arr+j ——>  *(p + i) + j
             */
            // printf("%d", *(*(p + i) + j)); // p每次加1,跳过 20个字节,即以每个数组为单位,每次加1跳过 5 个int
                printf("%d", p[i][j]); // 同上面一致
            }
            printf("\n");
        }
    }

 数组传参Demo

一维数组传参

        void test(int arr[])//ok
        {}
        void test(int arr[10])//ok
        {}
        void test(int *arr)//ok
        {}
        void test2(int *arr[20])//ok
        {}
        void test2(int **arr)//ok
        {}
        int main()
        {
            int arr[10] = {0};
            int *arr2[20] = {0};
            test(arr);
            test2(arr2);
        }

二维数组传参

        void test(int arr[3][5]) ok
        {}
        void test(int arr[][]) err 形参的二维数组,行可以省略,列不能省略
        {}
        void test(int arr[][5]) ok
        {}
        总结:二维数组传参,函数形参的设计只能省略第一个,因为对一个二维数组,可以不知道有多少行,但是必须知道多少列

        void test(int *arr) err 传过来的是arr第一个数组的地址,不是一个整形的地址
        {}
        void test(int *arr[5]) err 这里表示指针数组,arr是五个指针的数组
        {}
        void test(int (*arr)[5]) ok
        {}
        void test(int **arr) ok
        {}

        int arr[3][5] = {0};
        test(arr);

指针数组指针

指向用于存放指针的数组的

    char *Arr[5] = {0};    // 指针数组
    char *(*Pc)[5] = &Arr; // Pc可以指向一个数组,该数组有5个元素,每个元素是char*类型,数组指针的类型是char* (*)[5]

字符指针

字符指针——>指向字符的指针

    char *p = "abcdef"; // 把字符串首字符a的地址,赋值给了p
    printf("%c\n", *p); // a
    char *p1 = "abcdef";
    char *p2 = "abcdef";
    char arr1[] = "abcdef";
    char arr2[] = "abcdef";
    if (p1 == p2)
    {
        printf("p1 == p2\n"); // p1 == p2
    }
    else
    {
        printf("p1 != p2\n");
    }
    if (arr1 == arr2)
    {
        printf("arr1 == arr2\n");
    }
    else
    {
        printf("arr1 != arr2\n"); // arr1 != arr2
    }

函数指针

函数指针是指向函数的指针变量。函数指针可以让你像普通变量一样操作函数,也可以将函数作为参数传递给其他函数

 函数也有地址

int Add(int x, int y)
{
    return x + y;
}
printf("%p\n", &Add);       // 00007ff7f9ff1591
printf("%p\n", Add);        // 00007ff7f9ff1591

函数指针调用时可以不用写*解引用

    int (*pf)(int, int) = &Add; //  pf是一个函数指针,参数类型是(int, int) 返回类型为int的函数
    int res = (*pf)(2, 3);      // 调用函数指针所指向的函数
    /*
		函数指针调用时可以不用写*解引用
        int (*pf)(int, int) = Add 等同于 int *p = &num; p == &num
        int res = Add(2, 3);
        int res = pf(2, 3);
     */
    int resp = pf(2, 3); // 可以不用写*
    printf("%d\n", res); // 5

函数作为回调传参

void calc(int (*pf)(int, int))
{
    int a = 3;
    int b = 5;
    int res = (*pf)(a, b);
    // int res = pf(a, b);
    printf("%d\n", res); // 8
}
/*
调用calc函数
 */
calc(Add);

解释: (*(void (*)())0)();

  •     void (*)() 表示一个函数指针,指向一个无返回值的函数,并且该函数没有参数。
  •     (void (*)())0 将整数 0 强制转换为一个函数指针
  •     将这个函数指针解引用,这意味着它试图调用指向地址 0 的函数。

解释: void (*signal(int, void (*)(int)))(int);

    typedef unsigned int uint;
    typedef void (*pf_t)(int);
    void (*signal(int, void (*)(int)))(int);
    pf_t signal(int, pf_t); // 和上式相同
  • typedef unsigned int uint; 这句代码定义了一个新的数据类型 uint,它是无符号整型的别名,方便在程序中使用无符号整型时进行声明。
  • typedef void (*pf_t)(int); 这句代码定义了一个新的数据类型 pf_t,它是一个指向参数为整型、无返回值的函数指针类型。这样的定义可以方便地声明类似这种类型的函数指针变量。
  • void (*signal(int, void (*)(int)))(int); 这行代码声明了一个名为 signal 的函数,它接受两个参数:一个整型和一个指向参数为整型、无返回值的函数指针。它的返回类型是一个指向参数为整型、无返回值的函数指针。这种类型的函数通常用于信号处理。
  • pf_t signal(int, pf_t); 这行代码是函数 signal 的声明,它使用了之前定义的 pf_t 类型。它表明函数 signal 接受两个参数,一个整型和一个指向参数为整型、无返回值的函数指针,然后返回一个指向参数为整型、无返回值的函数指针。

函数指针数组指针

指向函数指针数组的指针

&先看函数指针数组:函数指针也是指针,把函数和指针放在数组中,其实就是函数指针数组

    int (*pf)(int, int) = Add;                      // pf是函数指针
    int (*arr[4])(int, int) = {Add, Sub, Mul, Div}; // arr就是函数指针的数组
    for (int i = 0; i < 4; i++)
    {
        // int res = arr[i](2, 1); // 可以直接用arr[i]是因为,比如int (*pf)(int, int) = Add; 指针函数pf的类型是int (*)(int, int) 那么Add == pf
        int res = (*arr[i])(2, 1); // 也可以解引用,因为arr[i]指向的是函数地址 Add等函数地址
        printf("%d\n", res);       // 3, 1, 2, 2
    }

&指向函数指针数组的指针

    int (*pArr[])(int, int) = {0, Add, Sub, Mul, Div}; // 函数指针数组
    int (*(*pArr)[5])(int, int) = &pArr;               // *pArr是指针,指向数组个数为5的 函数指针类型 数组的地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1184831.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言迭代法求一个数的平方根。迭代公式:Xn+1=(Xn+a/Xn)/2,其中a是输入的数字

完整代码&#xff1a; // 迭代法求一个数的平方根。迭代公式&#xff1a;Xn1(Xna/Xn)/2&#xff0c;其中 a 是输入的数字。 #include<stdio.h> #include<math.h> int main() {double x1, x2;double a;//a是要求的数printf("请输入一个数&#xff1a;")…

优化AI机器人外呼体验二

优化体验一的时候分享了影响语音机器人效果的五大因素&#xff1a;交互流程设计、语音质量、交互速度、用户反馈机制和数据隐私保护。本篇我就其中的话术制作来做一些分享&#xff0c;其实也就是把上次的交互流程设计分享的更详细。 先说一下话术制作流程。一般是由语音机器人厂…

【Git】安装和常用命令的使用与讲解及项目搭建和团队开发的出现的问题并且给予解决

目录 一、概述 1. 介绍 2. Git与SVN区别 3. 使用流程 二、命令讲解 1. 文件状态 2. 工作区域 三、命令使用 1. 安装 2. 使用前准备 3. 搭建项目环境 4. 团队开发 一、概述 1. 介绍 Git是一个开源的分布式版本控制系统&#xff0c;最初由Linus Torvalds于2005年创…

美国阿里海外仓地址

随着跨境电商的发展&#xff0c;越来越多的消费者开始关注海外购物。而在美国&#xff0c;有一个名为阿里海外仓的地方&#xff0c;为消费者提供了便捷的购物体验。本文将详细介绍美国阿里海外仓的地址、服务内容以及如何下单等相关信息。 一、美国阿里海外仓地址 美国阿里海外…

米软科技 | 推进医院智慧管理分级评估体系建立、提升评级

国家卫生健康委办公厅于2021年3月15日发布了“关于印发医院智慧管理分级评估标准体系&#xff08;试行&#xff09;的通知”&#xff08;国卫办医函〔2021〕86 号&#xff09;&#xff0c;该评估体系用于指导医疗机构科学、规范开展智慧医院建设&#xff0c;提升医院管理精细化…

IP 地址冲突检测工具

IP 冲突是一个术语&#xff0c;用于表示同一网络或子网中尝试使用相同 IP 地址的两个或多个设备的状态&#xff0c;这可能会导致发往特定主机的通信与其他主机混淆&#xff0c;因为两者都使用相同的 IP&#xff0c;为了避免这种情况&#xff0c;某些主机在发生 IP 冲突时会失去…

目前为止看过最帅气的一篇论文YOLOv3: An Incremental Improvement(2018.4)

文章目录 AbstractIntroductionThe DealBounding Box PredictionClass PredictionPredictions Across ScalesFeature ExtractorTraining How We DoThings We Tried That Didn’t WorkAnchor box x, y offset predictionsLinear x, y predictions instead of logisticFocal loss…

2010年09月06日 Go生态洞察:Go语言荣获2010年度Bossie奖

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

双11专场直播,最高抽200元现金红包!

虽然我们把这场直播的主题定为“老用户必须观看的直播”&#xff0c;但估计也有不少新朋友。 因此&#xff0c;本文除了为大家预告双11专场直播内容外&#xff0c;还会为大家介绍一下我们水经注是做什么的&#xff0c;以及公布直播间都有哪些福利好礼&#xff01; 观看双11专…

VS2010配置gdal1.10.0 gdal1.10.1编译

1.gdal1100编译 正文&#xff1a; 重要&#xff1a;gdal编译完是release版本的&#xff0c;工程中加载使用时release模式才能用&#xff0c;debug模式使用报错“错误LNK2038&#xff1a;检测到“_ITERATOR_DEBUG_LEVEL”的不匹配&#xff1a;值“0”与main.obj中的值“2”不匹…

基于安卓android微信小程序的在线考试系统

项目介绍 微信在线考试系统的设计主要是对系统所要实现的功能进行详细考虑&#xff0c;确定所要实现的功能后进行界面的设计&#xff0c;在这中间还要考虑如何可以更好的将功能及页面进行很好的结合&#xff0c;方便学生可以很容易明了的找到自己所需要的信息&#xff0c;还有…

一个数组实现两个栈

一个数组实现两个栈 基本思路&#xff1a; 1.定义两个栈顶top1-1&#xff0c;top2maxsize 2.栈满&#xff0c;当top1与top2相差1时栈满 package 例题; //一个数组实现两个栈 public class TwoStack {private int[] arr;private int maxSize;//定义栈顶private int top1;private…

Kotlin(十) 空指针检查、字符串内嵌表达式以及函数默认值

空指针检查 我们在之前的章节里&#xff0c;有定义一个Study的类&#xff0c;它有两个函数&#xff0c;一个doHomework(),一个readBooks()。然后我们定义个doStudy函数&#xff0c;来调用它们&#xff0c;代码如下&#xff1a; fun doStudy(study: Study) {study.doHomework(…

SecureCRT安装、注册教程

SecureCRT保姆级安装教程&#xff01;&#xff01;&#xff01; 安装包与注册机自取。 链接&#xff1a;https://pan.baidu.com/s/1IrFkHlrtCoc67QnQ_z1TWQ?pwdt25m 提取码&#xff1a;t25m 一 前期准备 1.1 关闭病毒查杀&#xff08;如果有其他杀毒软件也要关闭&#xff0…

小明和完美序列(HashMap、Map、Entry)

小明和完美序列 知识点&#xff1a; //导包&#xff1a;HashMap、Map、Entry import java.util.HashMap; import java.util.Map; import java.util.Map.Entry;public class Main {public static void main(String [] args) { //创建Map&#xff08;HashMap&#xff09;对象 M…

基于Kinect 动捕XR直播解决方案 - 硬件篇

Kinect-V2 硬件设备 一、Kinect介绍 1、Kinect for Windows 的开发配置 Kinect V2 操作系统&#xff1a;Windows 10&#xff08;必须&#xff09; Windows Surface Windows Surface 2 开发环境&#xff1a;Visual Studio 2017 .NET Framework 4.5 (.NET Framework 4.5) 硬…

【Ubuntu 语音控制安卓设备刷短视频 orangePi zero2 H616 (已开源) 】.md uptada:23/11/07

文章目录 H616_实现Ubuntu语音控制安卓设备刷短视频小美效果展示H616 ubuntu系统 安装adb智能公元 SU-03T 离线语音模组 固件制作配合串口实现 小美_控制安卓刷抖音 H616_实现Ubuntu语音控制安卓设备刷短视频 注意&#xff1a;orangePi zero2 H616 安装系统为ubuntu 小美效果…

信创加速,美创科技加入UOS主动安全防护计划(UAPP)

近日&#xff0c;统信UOS主动安全防护计划 (UAPP) 技术沙龙暨新老会员交流活动在北京召开。 美创科技作为信创产业的重要参与者受邀参加。在2023年度UAPP合作伙伴授牌发布仪式上&#xff0c;美创科技获得统信软件授牌&#xff0c;正式成为UAPP成员单位&#xff0c;将与统信软件…

日防夜防,家贼难防?企业防泄密为什么这么难?

企业经营保密就是保生命&#xff0c;你知道吗&#xff1f; 案例分析 根据国家信息部门的报告显示&#xff0c;高达85%的数据泄密不是因为黑客工资有多厉害&#xff0c;而是由公司员工造成的。 而且现在移动办公环境&#xff0c;大家都用手机在线办公软件的工作激励外泄更容易…

使用python快速搭建接口自动化测试脚本实战总结

导读 本文将介绍如何使用python快速进行http/https接口自动化测试脚本搭建&#xff0c;实现自动请求、获取结果、数据对比分析&#xff0c;导出结果到Excel等功能&#xff0c;包括python的requests、pandas、openpyxl等库的基本使用方法。 测试需求介绍 通常&#xff0c;在我…