深入理解指针(六)
一、字符指针变量
1.1字符指针变量
在指针的类型中我们知道有一种指针类型为字符指针char*
一般有以下两种使用方式:
#include<stdio.h>
int main()
{
char ch = 'w';
char* pc = &ch;
*pc = 'w';
return 0;
}
#include<stdio.h>
int main()
{
const char* pstr = "hello world.";
printf("%s\n", pstr);
return 0;
}
代码const char* pstr="hello world.";特别容易让同学以为是把字符串 hello world 放
到字符指针 pstr 里了,但是本质是把字符串 hello world. 首字符的地址放到了pstr中。
接下来给大家分享一串代码,这是《剑指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("atr1 and str2 are not same\n");
if(str3==str4)
printf("str3 and str4 are same\n");
else
printf("atr3 and str4 are not same\n");
return 0;}
这里str3和str4指向的是一个同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当几个指针指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以str1和str2不同,str3和str4相同。
二、数组指针变量
2.1数组指针变量是什么
之前我们学习了指针数组,指针数组是⼀种数组,数组中存放的是地址(指针)。 数组指针变量是指针变量?还是数组?
答案是:指针变量。
我们已经熟悉:
整形指针变量: int * pint; 存放的是整形变量的地址,能够指向整形数据的指针。
浮点型指针变量: float * pf; 存放浮点型变量的地址,能够指向浮点型数据的指针。
那数组指针变量应该是:存放的应该是数组的地址,能够指向数组的指针变量。
下面代码哪个是数组指针变量?
int *p1[10];
int (*p2)[10];
思考一下:p1,p2分别是什么?
int *p1[10],p1是一个数组,每个元素都是一个指向int类型的指针。是一个包含10个指向int类型的指针的数组。它是一个指针数组
int (*p2)[10],p2先和*结合,然后指针指向的是⼀个大小为10个整型的数组。所以p2是 一个指针,指向一个数组,它是一个数组指针。
2.2数组指针变量怎么初始化
数组指针变量是⽤来存放数组地址的,那怎么获得数组的地址呢?就是我们之前学习的:&数组名。如:
int arr[5]={0};
int(*p)[5]=&arr;
int : p 指向的数组的元素类型
p : p 是数组指针变量名
10 : p 指向数组的元素个数
三、二维数组传参的本质
回想一下之前在进行二维数组传参给一个函数时,我们是怎样写的呢?可能是这样的:
#include <stdio.h>
void test(int a[3][5], int r, int c)
{int i = 0;int j = 0;for (i = 0; i < r; i++){for (j = 0; j < c; j++){printf("%d ", a[i][j]);}printf("\n");}
}
int main()
{int arr[3][5] = { {1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7} };test(arr, 3, 5);return 0;
}
这里实参是二维数组,形参也写成二维数组的形式,那还有什么其他的写法吗?
首先我们再次理解⼀下二维数组,二维数组起始可以看做是每个元素是一维数组的数组,也就是二维数组的每个元素是一个一维数组。那么二维数组的首元素就是第一行,是个一维数组。如下图:
由数组名是数组首元素地址可知,二维数组数组名代表第一行地址。根据上面的例子我们可知。第一行的一维数组类型是int [5],第一行的地址类型就是int(*)[5]。这就意味着二维数组传参的本质是传递地址。形参也可以写成以下形式:
#include <stdio.h>
void test(int (*p)[5], int r, int c)
{int i = 0;int j = 0;for (i = 0; i < r; i++){for (j = 0; j < c; j++){printf("%d ", *(*(p + i) + j));}printf("\n");}
}
int main()
{int arr[3][5] = { {1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7} };test(arr, 3, 5);return 0;
}
总结:二维数组传参,形参部分可以写成数组,也可以写成指针。
即
void test(int a[3][5], int r, int c)
可以写成
void test(int (*p)[5], int r, int c)
四 、函数指针变量
4.1函数指针变量的创建
根据前面学习的指针,我们可以得出函数指针变量是用来存放函数地址的,那么函数是否真的有地址呢?我们来做个测试:
#include <stdio.h>
void test()
{printf("hehe\n");
}
int main()
{printf("test: %p\n", test);printf("&test: %p\n", &test);return 0;
}
结果如下:
确实打印出来了地址,所以函数是有地址的,函数名就是函数的地址。如果要将函数的地址存起来,就要创建函数指针变量,它的写法其实和数组指针非常类似。
例如: void test()
函数变量指针可写为: void (*pf1)=&test
也可以写成: void (*pf1)=test
这是没有参数的,那有参数的应该怎么写呢?
例如: int Add(int x, int y)
函数变量指针可写为: int(*pf2)(int, int) = Add
也可以写成:int(*pf2)(int x, int y) = &Add;
int :是pf2指向函数的返回类型
(*pf2) :是函数指针变量名
(int x,int y):是pf2指向函数的参数类型和个数的交代。
总结:函数指针变量的格式为 int (*) (int x,int y)
4.2函数指针变量的使用
它是通过函数指针调用指针指向的函数,例如:
#include <stdio.h>
int Add(int x, int y)
{return x + y;
}
int main()
{int(*pf2)(int, int) = Add;printf("%d\n", (*pf2)(2, 3));printf("%d\n", pf2(3, 5));return 0;
}
输出结果如下:
这里有两段有趣的代码分享给大家,大家可以在评论区里说出自己的分析:
(*(void (*)())0)();
void (*signal(int , void(*)(int)))(int);
4.3typedef关键字
typedef大家应该都有所了解,它是用来类型重命名的,可以将复杂的类型简单化,例如:你觉得unsigned int太长你可以自己起个名字使用,就用uint吧,那应该怎么写呢?
typedef unsigned int uint;
指针类型也可以重命名,比如将int*重命名ptr_r
typedef int* ptr_t;
但是对于数组指针和函数指针,其实是有区别的,比如将int(*)[5]重命名为parr_t,要写为:
typedef int(*parr_t)[5];
函数指针的重命名也是一样的,比如将void(*)(int)类型重命名为pf_t,就要这样写:
typedef void(*pf_t)(int)
还可以这样写:pf_t signal(int, pf_t);
五、函数指针数组
把函数的地址存到一个数组中,那这个数组就叫函数指针数组,下面我给大家写三个代码,大家猜一下哪一个是函数指针数组
int (*parr1[3])();
int *parr2[3]();
int (*)() parr3[3];
答案是parr1,parr1先和[]结合,说明parr1是数组,这个数组的内容是int (*)() 类型的函数指针。
六、转移表
函数指针数组的用途:转移表,下面我们来举一个例子:计算器
#include <stdio.h>
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;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;
}
相关文章:

深入理解指针(六)
一、字符指针变量 1.1字符指针变量 在指针的类型中我们知道有一种指针类型为字符指针char* 一般有以下两种使用方式: #include<stdio.h> int main() { char ch w; char* pc &ch; *pc w; return 0; } #include<stdio.h> int main()…...

Linux下基本指令(4)
Linux权限的概念 Linux下有两种用户:超级用户(root)、普通用户。 超级用户:可以再linux系统下做任何事情,不受限制 普通用户:在linux下做有限的事情。 超级用户的命令提示符是“#”,普通用户…...

vue 手写分页
【先看效果】 (1)内容小于2页 不展示页码 (2)1 < 内容页数< 限定展示页码 展示:页码、上下页;隐藏:首页、末页图标,上、下一区间码。即:(页数&#…...

Spring Boot项目接收前端参数的11种方式
大家好,我是。在前后端项目交互中,前端传递的数据可以通过HTTP请求发送到后端, 后端在Spring Boot中如何接收各种复杂的前端数据呢?这篇文章总结了11种在Spring Boot中接收前端数据的方式。 1 搭建项目 1.通过Spring Initializr…...
Springboot项目:使用MockMvc测试get和post接口(含单个和多个请求参数场景)
一、引入MockMvc依赖 使用MockMvc,必须要引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>二、具体演示…...

OpenAI ChatGPT在心理治疗领域展现超凡同理心,通过图灵测试挑战人类专家
近期,一项关于OpenAI ChatGPT在心理治疗领域的研究更是引起了广泛关注。据报道,ChatGPT已经成功通过了治疗师领域的图灵测试,其表现甚至在某些方面超越了人类治疗师,尤其是在展现同理心方面,这一发现无疑为AI在心理健康…...

【HBase】HBaseJMX 接口监控信息实现钉钉告警
目录 一、JMX 简介 二、JMX监控信息钉钉告警实现 一、JMX 简介 官网:Apache HBase ™ Reference Guide JMX (Java管理扩展)提供了内置的工具,使您能够监视和管理Java VM。要启用远程系统的监视和管理,需要在启动Java…...

25旅游管理研究生复试面试问题汇总 旅游管理专业知识问题很全! 旅游管理复试全流程攻略 旅游管理考研复试真题汇总
旅游管理复试很难?! 别怕!经验超丰富的老学姐来给你们出谋划策啦! 最近是不是被旅游管理考研复试折磨得够呛?莫慌!我这有着丰富复试指导经验的老学姐来帮你们排雷,助力大家顺利上岸!…...
深入解析C++26 Execution Domain:设计原理与实战应用
一、Domain设计目标与核心价值 Domain是C26执行模型的策略载体,其核心解决两个问题: 执行策略泛化:将线程池、CUDA流等异构调度逻辑抽象为统一接口策略组合安全:通过类型隔离避免不同执行域的策略污染 // Domain类型定义示例&a…...
Linux命令基础
【Linux路径写法】 相对路径与绝对路径: 绝对路径:以根目录为起点,描述路径的一种写法,路径描述以 / 开头 相对路径:以当前目录为起点,描述路径的一种写法,路径描述无需以/开头 特殊路径符&…...
什么是超越编程(逾编程)(元编程?)
超越编程(逾编程)(元编程?)(meta-programming) 目录 1. meta- 的词源 2. 逾编程(meta-programming) 的直实含义 2.1 定义 2.2 说明 3. 翻译成“元编程”应该是一种错误 1. meta- 的词源 这是一个源自希腊语的构词元素,其有三种含义ÿ…...

netcore libreoffice word转pdf中文乱码
一、效果 解决: cd /usr/share/fonts/ mkdir zhFont cd zhFont #windows系统C:\Windows\Fonts 中复制/usr/share/fonts/zhFont sudo apt update sudo apt install xfonts-utils mkfontscale mkfontdir #刷新字体缓存 fc-cache -fv #查看已安装的字体列表 fc-list :…...
【练习】【回溯:组合:一个集合 元素可重复】力扣 39. 组合总和
题目 组合总和 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidates 中的 同一个 数字可以 无限制重…...

Mac 清理缓存,提高内存空间
步骤 1.打开【访达】 2.菜单栏第五个功能【前往】,点击【个人】 3.【command shift J】显示所有文件,打开【资源库】 4.删除【Containers】和【Caches】文件 Containers 文件夹:用于存储每个应用程序的沙盒数据,确保应用程序…...

数据结构——二叉树经典习题讲解
各位看官早安午安晚安呀 如果您觉得这篇文章对您有帮助的话 欢迎您一键三连,小编尽全力做到更好 欢迎您分享给更多人哦 大家好,我们今天来学习java数据结构的二叉树 递归很重要的一些注意事项: 1:递归你能不能掌握在于࿱…...

神经网络八股(三)
1.什么是梯度消失和梯度爆炸 梯度消失是指梯度在反向传播的过程中逐渐变小,最终趋近于零,这会导致靠前层的神经网络层权重参数更新缓慢,甚至不更新,学习不到有用的特征。 梯度爆炸是指梯度在方向传播过程中逐渐变大,…...

堆、优先队列、堆排序
堆: 定义: 必须是一个完全二叉树(完全二叉树:完全二叉树只允许最后一行不为满,且最后一行必须从左往右排序,最后一行元素之间不可以有间隔) 堆序性: 大根堆:每个父节点…...
vue 学习-vite api.js
/** 整机管理 * */ // 整机分类 列表 export const wholeMachineServersType params > ajaxGet({url: wholeMachine/serverstype/,params}) // 整机分类 新增 export const wholeMachineServersTypeAdd params > ajaxPost({url: wholeMachine/serverstype/,params}) /…...

java练习(35)
ps:题目来自力扣 整数反转 给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。 如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。 假设环境不允许存储 64 位整数(有符号或无符号)…...
PW_Balance
目录 1、 PW_Balance 1.1、 getDocumentsTypeID 1.2、 getShouldAmount 1.3、 setOptimalAmount 1.4、 setRemark PW_Balance package com.gx.pojo; public class PW_Balance { private Integer BalanceID; private Integer PaymentID; private Integer ReceptionID…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...