【理解指针(四)】
文章目录
- 一、指针数组
- 二、指针数组来模拟二维数组
- 三、字符指针变量
- 注意:
- 字符串的例子(曾经的一道笔试题)
- 四、数组指针变量
- 1、什么是数组指针变量
- 2、数组指针怎么初始化
- 五、二维数组传参的本质
- 六、函数指针
- 1、什么是函数指针变量
- 2、函数的地址
- 3、使用
- 4、 `typedef`关键字
- 结束语
一、指针数组
我们可以先来回顾一下整形数组和字符数组。
- 整形数组:
是存放整形的数组
- 字符数组:
是指存放字符的数组
类比上面两个例子之后,我们可以知道指针数组就是存放指针的数组,指针数组的每一个元素都是用来存放地址(指针)的。
二、指针数组来模拟二维数组
首先我们需要知道数组名是指数组首元素的地址
#include<stdio.h>
int main()
{int str[] = { 1,2,3,4,5 };int str1[] = { 3,4,5,6,7 };int str2[] = { 5,6,7,8,9 };int* pa[3] = { str,str1,str2 };for (int i = 0; i < 3; i++){for (int j = 0; j < 5; j++){printf("%d ", *(*(pa + i)) + j);}printf("\n");}return 0;
}
我们可以得到如下的结果:
第一次的for循环是循环的行,第二次的dor循环也就是列,数组名就是数组的首元素,我们这里的pa[i]找到数组元素指向的是整形一维数组,pa[i][j]就是指向整形一维数组的元素。
模拟出⼆维数组的效果,实际上并非完全是⼆维数组,因为每⼀行并非是连续的
画个图方便大家理解:
三、字符指针变量
我们知道字符指针是char*
常如下使用:
#include<stdio.h>
int main()
{char p = 'e';char* s = &p;printf("%c\n", *s);*s = 't';printf("%c\n", *s);return 0;
}
结果会分别打印出:e 和 t 。
当然还有其他适用方式:
#include<stdio.h>
int main()
{char str[] = "hello world!!!";char* pa = str;printf("%s\n", pa);return 0;
}
注意:
这里的hello world!!!
并没有放在指针变量pa
中,而是把这个字符串的首字符的地址放在了pa
中。
pa
也就是调用字符串中首字符的地址,而字符串的地址也是首字符元素的地址。
字符串的例子(曾经的一道笔试题)
#include <stdio.h>
int main()
{char str1[] = "hello bit.";char str2[] = "hello bit.";const char* str3 = "hello bit.";const char* str4 = "hello bit.";if (str1 == str2)printf("str1 and str2 are same\n");elseprintf("str1 and str2 are not same\n");if (str3 == str4)printf("str3 and str4 are same\n");elseprintf("str3 and str4 are not same\n");return 0;
}
这题的答案是str1 and str2 are not same
和str3 and str4 are same
我们大致来分析一下:
str1
和str2
都是存的相同的字符串内容,在内存中str1
和str2
是开辟了不同的空间存放相同的内容的,实质上完全没有必要存相同的内容开辟两个空间,两个空间的地址完全不一样,所以会打印出str1 and str2 are not same
;而str3
和str4
指向的是⼀个同⼀个常量字符串,C/C++会把常量字符串存储到单独的⼀个内存区域,指针指向同⼀个字符串的时候,他们实际会指向同⼀块内存,所以这里会打印出str3 and str4 are same
。
四、数组指针变量
1、什么是数组指针变量
首先我们可以来回顾一下:整形指针变量和浮点型指针变量
-
整形指针变量:
存放的是整型变量的指针,能够指向整形数据的指针。
形如:int* pa
-
浮点型指针变量:
存放的是浮点型变量的指针,能够指向浮点型数据的指针。
形如:float* pa
那么数组指针变量就是存放的是数组的地址,指向数组数据的指针。
形如:int(*p)[10]
这里的p是自己命名,10 也是根据自己写的代码来写。
p
先和*结合,所以p
是一个指针变量,指向的是一个大小为10个整形的数组。
综上:p是一个指针,指向一个数组,这就是数组指针。
2、数组指针怎么初始化
数组指针变量是⽤来存放数组地址的
int arr[5]={0};
&arr得到的就是数组的地址
int (*p)[5]=&arr//这个数组的地址存放在数组指针变量中
五、二维数组传参的本质
(二维数组我们可以看成许多一维数组的组成)
首先我们知道数组名是数组首元素的地址,那么⼆维数组的数组名表示的就是第⼀行的地址,也就是一维数组的地址,⼆维数组传参本质上也是传递了地址,传递的是第一行这个⼀维数组的地址
我们形参用指针写的形式如下:
#include<stdio.h>
void Shuzu(int(* pa)[5], int a, int b)
{for (int i = 0; i < a; i++){for (int j = 0; j < b; j++){printf("%d ", *(*(pa + i) + j));}printf("\n");}
}
int main()
{int arr[3][5] = { {1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15} };Shuzu(arr, 3, 5);return 0;
}
当然形参我们也可以数组的形式写:
#include<stdio.h>
void Shuzu(int p[][5], int s, int c)
{for (int i = 0; i < s; i++){for (int j = 0; j < c; j++){printf("%d ", p[i][j]);}printf("\n");}
}
int main()
{int arr[3][5] = { {1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15} };Shuzu(arr, 3, 5);return 0;
}
六、函数指针
1、什么是函数指针变量
通过上面的种种类比我们知道了什么是数组指针,整形指针,那么我们可以知道函数指针变量就是用来存放函数地址的。
2、函数的地址
首先我们可以简单的写一个代码,看看函数是否有地址:
#include<stdio.h>
void Ad()
{printf("abder\n");
}
int main()
{Ad();printf("&Ad=%p\n", &Ad);printf("Ad=%p\n", Ad);return 0;
}
由结果我们可以知道函数有地址,函数名就是我们的地址
如果我们要将函数的地址存放起来,就得创建函数指针变量:
#include<stdio.h>
int Add(int x, int y)
{return x + y;
}int(*pa)(int , int ) = Add;//&Add
其中==int(*)(int,int)==就是pa函数指针变量的类型。
3、使用
#include<stdio.h>
int Add(int x, int y)
{return x + y;
}
int main()
{int (*pa1)(int ,int) = Add;printf("%d\n", (*pa1)(2,4));printf("%d\n", pa1(5,6));return 0;
}
可以得出答案是6和11。
为什么第二个打印pa1可以不解引用?
因为pa1这个指针变量存放的是Add的地址,&符号与*相互直接抵消了,所以可以不使用解引用符号。
4、 typedef
关键字
typedef是用来类型重命名的
比如:
singed int 可能你觉得每次书写比较麻烦,你就可以直接有时候typedef来重命名
也就是:typedef singed int ty_t,这个时候,想要再使用singed int 就可以直接用ty_t替换,
本质上是一样的
1.但是函数指针的重命名有些许区别:
比如,我们想要把int(*pa)(int )
重命名为pa_t
:
typedef int(*pa_t)(int); //新类型的名字必须在*号的右边
2.数组指针重命名也是如此:
比如:我们需要把int(*pc)[10]
重命名为py_y
typedef int(*py_y)[10]; //新类型的名字也需要在*号的右边
结束语
这次的内容可能有些多,但是比较好理解,希望大家可以拿到自己想要的offer,最后,如果文章有什么打错字的地方,希望大家不要介意,也希望大家可以给我提出来。
最后,祝大家每天都开开心心,我们下次再见
相关文章:

【理解指针(四)】
文章目录 一、指针数组二、指针数组来模拟二维数组三、字符指针变量注意: 字符串的例子(曾经的一道笔试题) 四、数组指针变量1、什么是数组指针变量2、数组指针怎么初始化 五、二维数组传参的本质六、函数指针1、什么是函数指针变量2、函数的…...

Ribbon简介
目录 一 、概念介绍 1、Ribbon是什么 2、认识负载均衡 2.1 服务器端的负载均衡 2.2 客户端的负载均衡 3、Ribbon工作原理 4、Ribbon的主要组件 IClientConfig ServerList ServerListFilter IRule Iping ILoadBalancer ServerListUpdater 5、Ribbon支持…...

【感悟《剑指offer》典型编程题的极练之路】02字符串篇!
个人主页:秋风起,再归来~ 文章所属专栏:《剑指offer》典型编程题的极练之路 个人格言:悟已往之不谏,知来者犹可追 克心守己,…...
通过 Docker 实现国产数据库 OpenGauss 开发环境搭建
通过 Docker 实现国产数据库 OpenGauss 开发环境搭建 一 前置准备 2.1 下载镜像 docker pull enmotech/opengauss:5.0.1构建镜像的 Dockerfile,方便后期实现个性化定制: FROM ubuntu:22.04 as builderARG TARGETARCHWORKDIR /warehouseRUN set -eux;…...

【Java】LinkedList模拟实现
目录 整体框架IMyLinkedList接口IndexNotLegalException异常类MyLinkedList类成员变量(节点信息)addFirst(头插)addLast(尾插)在指定位置插入数据判断是否存在移除第一个相等的节点移除所有相等的节点链表的长度打印链表释放回收链表 整体框架 IMyLinkedList接口 这个接口用来…...
ubuntu下mysql常用命令
1. 登录数据库 mysql -u root -p 2.创建数据库 create database 数据库名字 mysql> create database yourdb; Query OK, 1 row affected (0.03 sec)3.显示数据库 show databases; 实操结果如下 mysql> show databases; -------------------- | Database | ---…...

燃气官网安全运行监测系统-阀井燃气监测仪-旭华智能
近年来,燃气爆炸事故频发,造成了重大人员伤亡和财产损失。这也再次为我们敲响警钟,燃气是我们日常生活中不可或缺的能源,但其潜在的危险性也是不容小觑。因此在重要节点加装燃气阀井气体监测仪,并将数据上传到系统平台…...
vue 文件预览(docx、.xlsx、pdf)
1.ifream <iframe src"" ></iframe> 注: src里面是文件地址 2.vue-office 支持vue2和vue3提供docx、.xlsx、pdf多种文档的在线预览方案 2.1安装 #docx文档预览组件 npm install vue-office/docx vue-demi#excel文档预览组件 npm install vue-office…...

云架构(二) 大使模式
Ambassador pattern (https://learn.microsoft.com/en-us/azure/architecture/patterns/ambassador) 简单描述 创建一个助手服务,这个服务代表消费服务或者应用程序发送网络请求。大使服务可以看做是与客户机同一个位置的进程外代理。 这种…...
.NET Path类库的特殊方法
在.NET中Path类库是非常常用的一个类库,包含很多我们常用的方法,常用的方法这里就不详细说明了,这里记录下几个非常规的方法。 获取随机文件名: //将返回随机的文件名Console.WriteLine(Path.GetRandomFileName()); 获取禁止在路…...
【JVM】JVM常用性能调优参数详细介绍
JVM常用性能调优参数详细介绍 一、何时进行JVM调优二、性能调优三、JVM调优的基本原则四、JVM调优目标五、JVM调优的步骤六、JVM参数七、JVM参数解析及调优八、JVM参数使用手册8.1 内存相关8.2 GC策略相关8.3 GC日志相关8.4 异常相关8.5 问题定位及优化相关九、参考文档一、何时…...
React中的受控组件与非受控组件
受控组件与非受控组件 受控组件 组件(input, select)的状态与state的值绑定,组件的状态全程响应外部数据 class TestComponent extends React.Component {constructor (props) {super(props);this.state { username: lindaidai };}render () {return <input …...
uniapp实现u-datetime-picker时间选择器的默认日期定位,解决default-value不生效问题
uniapp实现u-datetime-picker,设置默认定位日期,解决default-value不生效问题 想实现的效果是点开时间选择器默认显示当前日期,而不是该选择器最早的日期 给选择器添加ref属性,如下: <u-datetime-picker :show&q…...
react native 使用ScrollView实现下拉更新,上拉加载更多
在React Native中,要实现下拉更新和上拉加载更多的功能,你需要自定义ScrollView组件,监听滚动事件并根据滚动的位置来判断何时触发更新和加载更多的操作。以下是一个基本的实现思路: 监听滚动事件:使用ScrollView的on…...
vue2完结
笔记 关于不同版本的Vue: 1.vue.js与vue.runtime.xxx.js的区别:(1)vue.js是完整版的Vue,包含:核心功能模板解析器(2)vue.runtime.xxx.js是运行版本的Vue,只包含核心功能,没有模板解析器 2.因为…...
前端网页之间传递参数
在多页面应用中,我们可能面临着前端页面之间传递参数的情况,在一个页面获取到一些参数信息后,到另一个页面去进行后续处理,需要将前一个页面得到的一些参数带到第二个页面。当参数较少时,可以在跳转第二个页面时通过se…...
【常见面试题】Golang中,协程数最多可以开多少个?
参考: Goroutine 究竟可以开多少? 一、先说结论: 能开多少个协程,取决于单个协程处理方法所占用的CPU和内存资源(也就是看你计算机运行的应用程序的具体代码逻辑)。 二、具体来说: 如果是C…...

RabbitMQ基础笔记
视频链接:【黑马程序员RabbitMQ入门到实战教程】 文章目录 1.初识MQ1.1.同步调用1.2.异步调用1.3.技术选型 2.RabbitMQ2.1.安装2.1.1 Docker2.1.1 Linux2.1.1 Windows 2.2.收发消息2.2.1.交换机2.2.2.队列2.2.3.绑定关系2.2.4.发送消息 2.3.数据隔离2.3.1.用户管理2…...
大型项目管理神器:掌握yarn monorepo的安装和使用
I. 引言 在当今的前端开发中,由于项目规模的不断增长和多团队协同,Monorepo成为了越来越流行的开发模式。Monorepo指的是将多个相关项目或者模块打包在一起的软件开发模式,它可以让开发人员更好地组织管理代码,减少重复的代码&am…...

算法打卡day28|贪心算法篇02|Leetcode 122.买卖股票的最佳时机 II、55. 跳跃游戏、45.跳跃游戏 II
算法题 Leetcode 122.买卖股票的最佳时机 II 题目链接:122.买卖股票的最佳时机 II 大佬视频讲解:买卖股票的最佳时机 II视频讲解 个人思路 因为只有一只股票,且两天作一个交易单元,那每次只收集正利润就可以最终最多可以获取的利润…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...

Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
PostgreSQL——环境搭建
一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在࿰…...
提升移动端网页调试效率:WebDebugX 与常见工具组合实践
在日常移动端开发中,网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时,开发者迫切需要一套高效、可靠且跨平台的调试方案。过去,我们或多或少使用过 Chrome DevTools、Remote Debug…...
HTML前端开发:JavaScript 获取元素方法详解
作为前端开发者,高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法,分为两大系列: 一、getElementBy... 系列 传统方法,直接通过 DOM 接口访问,返回动态集合(元素变化会实时更新)。…...