C语言 指针进阶

目录

数组指针

指针数组访问数组元素

再次讨论数组名

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

访问二维数组元素

非数组指针访问

数组指针访问

 数组传参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);     // 0000003199fff960printf("%p\n", arr + 1); // 0000003199fff964 加4个字节printf("%p\n", &arr[0]);     // 0000003199fff960printf("%p\n", &arr[0] + 1); // 0000003199fff964 加4个字节printf("%p\n", &arr);     // 0000003199fff960printf("%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 个intprintf("%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的地址,赋值给了pprintf("%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 == &numint 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 == pfint 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.mzph.cn/news/135424.shtml

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

相关文章

校园安防监控系统升级改造方案:如何实现设备利旧上云与AI视频识别感知?

一、背景与需求分析 随着现代安防监控科技的兴起和在各行各业的广泛应用&#xff0c;监控摄像头成为众所周知的产品&#xff0c;也为人类的工作生活提供了很大的便利。由于科技的发达&#xff0c;监控摄像头的升级换代也日益频繁。每年都有不计其数的摄像头被拆掉闲置&#xf…

2023年云计算的发展趋势如何?

混合云的持续发展&#xff1a;混合云指的是将公有云和私有云进行结合&#xff0c;形成一种统一的云计算环境。随着企业对数据隐私和安全性的要求越来越高&#xff0c;以及在数据存储和处理方面的需求不断增长&#xff0c;混合云正在逐渐成为主流。预计未来混合云将会继续保持高…

搜索引擎Elasticsearch基础与实践

倒排索引 将文档中的内容分词&#xff0c;然后形成词条。记录每条词条与数据的唯一表示如id的对应关系&#xff0c;形成的产物就是倒排索引&#xff0c;如下图&#xff1a; ElasticSearch数据的存储和搜索原理 这里的索引库相当于mysql中的database。一个文档&#xff08;do…

微服务架构——笔记(3)Eureka

微服务架构——笔记&#xff08;3&#xff09; 基于分布式的微服务架构 本次笔记为 此次项目的记录&#xff0c;便于整理思路&#xff0c;仅供参考&#xff0c;笔者也将会让程序更加完善 内容包括&#xff1a;1.支付模块、2.消费者订单模块、支付微服务入驻Eureka、Eureka集群…

计网----数据库(一)

计网----数据库&#xff08;一&#xff09; 一.什么是数据库 数据库是”按照数据结构来组织、存储和管理数据的仓库“。是一个长期储存在计算机内的、有组织的、可共享的、统一管理的大量数据的集合。 二.数据库的特点 1.规范化的本地存储 2.加密 3.共享 三.数据库的好处…

ChatGPT如何管理对话历史?

问题 由于现在开始大量使用ChatGPT对话功能&#xff0c;认识到他在提供启发方面具有一定价值。比如昨天我问他关于一个微习惯的想法&#xff0c;回答的内容还是很实在&#xff0c;而且能够通过他的表达理解自己的问题涉及到的领域是什么。 此外&#xff0c;ChatGPT能够总结对话…

华为eNSP实验-三层交换机的不同网段通信(通过OSPF路由方式)

1.拓扑图 2.过程如下 2.1 首先PC1和PC2配置好IP地址 2.2 在SW1上配置虚拟网关及VLAN <Huawei>system-view [Huawei]sysname SW1 [SW1]undo info-center enable [SW1] [SW1]vlan batch 10 20 [SW1]interface GigabitEthernet 0/0/1 [SW1-GigabitEthernet0/0/1]port li…

2023 全栈工程师 Node.Js 服务器端 web 框架 Express.js 详细教程(更新中)

Express 框架概述 Express 是一个基于 Node.js 平台的快速、开放、极简的Web开发框架。它本身仅仅提供了 web 开发的基础功能&#xff0c;但是通过中间件的方式集成了外部插件来处理HTTP请求&#xff0c;例如 body-parser 用于解析 HTTP 请求体&#xff0c;compression 用于压…

@ControllerAdvice + @ExceptionHandler 定义全局异常

创建Spring Boot项目&#xff1a;使用Spring Initializr创建一个新的Spring Boot项目。依赖配置&#xff1a;在pom.xml 文件中(方便起见使用的是thymeleaf模板引擎)&#xff1a; <dependencies><dependency><groupId>org.springframework.boot</groupId&…

【Unity之UI编程】在Unity中如何打图集,来降低DrowCall

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;UI_…

C++常用格式化输出转换

在C语言中可以用printf以一定的格式打印字符&#xff0c;C当然也可以。 输入输出及命名空间还不太了解的小伙伴可以看一看C入门讲解第一篇。  在C中&#xff0c;可以用流操作符&#xff08;stream manipulators&#xff09;控制数据的输出格式&#xff0c;这些流操作符定义在2…

用循环结构程序自动化计算——计数循环

用循环结构程序自动化计算——计数循环 低阶目标&#xff1a; 利用for循环结构来完成已知次数的自动化处理&#xff0c;掌握计数循环结构应用方法 高阶目标&#xff1a; 学会利用for循环解决生活中的实际问题 用循环结构程序自动化计算——计数循环 用循环结构程序自动化计算…

缓存-Spring Cache 缓存抽象

缓存-Spring Cache 缓存抽象 Spring从版本3.1开始提供非侵入的将Cache集成到Spring应用的方式。Spring Cache提供Cache的统一抽象&#xff0c;支持集成各种不同的缓存解决方案。从4.1版本开始&#xff0c;提供了注解和更多的定制参数。 Spring Cache 抽象提供了对Java方法的缓存…

yo!这里是STL::unordered系列简单模拟实现

目录 前言 相关概念介绍 哈希概念 哈希冲突与哈希函数 闭散列 框架 核心函数 开散列 框架 核心函数 哈希表&#xff08;开散列&#xff09;的修改 迭代器实现 细节修改 unordered系列封装 后记 前言 我们之前了解过map和set知道&#xff0c;map、set的底层结构是…

电脑软件:推荐一款电脑多屏幕管理工具DisplayFusion

下载https://download.csdn.net/download/mo3408/88514558 一、软件简介 DisplayFusion是一款多屏幕管理工具&#xff0c;它可以让用户更轻松地管理连接到同一台计算机上的多个显示器。 二、软件功能 2.1 多个任务栏 通过在每个显示器上显示任务栏&#xff0c;让您的窗口管理更…

MATLAB绘图中文显示为方框

MATLAB绘图中文显示为方框 MATLAB显示英文和字母没有问题&#xff0c;但是当显示中文时会显示乱码&#xff0c;中文显示为方框&#xff0c;如下图&#xff1a; 可以在绘图命令中添加如下代码&#xff1a; set(gca,Fontname,Monospaced); 例如&#xff1a; % 滤波器系数%低通…

16 DNS协议详解

1、DNS的由来 很难记住网站的 IP 地址&#xff0c;因而也需要一个地 址簿&#xff0c;就是DNS 服务器。DNS 在日常生活中非常重要。每个人上网&#xff0c;都需要访问它&#xff0c;因此一旦DNS出现故障&#xff0c;是非常可怕的。因而&#xff0c;DNS 服务器&#xff0c;一定…

装修服务预约小程序的内容如何

大小装修不断&#xff0c;市场中大小品牌也比较多&#xff0c;对需求客户来说&#xff0c;可以线下咨询也可以线上寻找品牌&#xff0c;总是可以找到满意的服务公司&#xff0c;而对装修公司来说如今线下流量匮乏&#xff0c;很多东西也难以通过线下方式承载&#xff0c;更需要…

【Java 进阶篇】Java Filter 快速入门

欢迎来到这篇有关 Java Filter 的快速入门指南&#xff01;如果你是一名 Java 开发者或者正在学习 Java Web 开发&#xff0c;Filter 是一个强大的工具&#xff0c;可以帮助你管理和控制 Web 应用程序中的请求和响应。本文将向你解释 Filter 的基本概念&#xff0c;如何创建和配…

84 柱状图中的最大的矩形(单调栈)

题目 柱状图中的最大的矩形 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。 示例 1: 输入&#xff1a;heights [2,1,5,6,2,3] 输出&#xff1a;10 …