当前位置: 首页 > news >正文

深入理解指针:【探索指针的高级概念和应用一】

目录

前言:

1. 字符指针

2. 指针数组

3.数组指针

3.1数组指针的定义

3.2 &数组名VS数组名

3.3数组指针的使用


前言:

🍂在了解今天的内容之前我们先复习一下指针的基本概念:

1,内存单元是有编号的,编号就是我们所说的地址,也可以叫指针,它们是一回事。如果我们把一个指针或地址存起来的话,我们就需要一个指针变量

2,指针变量就是个变量,用来存放地址,地址唯一标识一块空间。

3,地址或指针的大小是固定的4/8个字节(32位平台/64位平台),也可以理解为指针变量的大小是4/8个字节。

4,指针是有类型的,指针的类型决定了指针加减整数的步长,指针解引用操作时候的权限。


1. 字符指针

在指针的类型中我们知道有一种指针类型为字符指针 char* :
🍂一般使用:

#include <stdio.h>int main()
{char ch = 'w';//取出的变量ch的地址是char类型的变量,//就可以把它放在char* 类型的指针里边去char* pc = &ch;return 0;
}

🍂还有一种使用方式如下:

#include <stdio.h>int main()
{//这个字符串作为一个表达式的时候它的值是首字符的地址,指向字符串的本质是指向了第一个字符,//但因为字符串在内存中是连续存放的,也可以认为是指向了一个字符串//加const是为了防止有人通过*p修改字符串常量里边的内容const char* p = "abcdef";printf("%s\n", p);//如果对这个指针解引用,因为它是char*类型,解引用只拿到一个字符,所以格式控制符应该用“%c”printf("%c\n", *p);return 0;
}

 🍂下面我们来看一道面试题:

#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;
}

🍂这里最终输出的是: 

🎈分析: 

 如上图所示,st1数组和str2数组是两块独立的空间,它们的起始地址肯定不相同,所以打印的结果为不同;“hello bit”是一个常量字符串,它不能被修改,而对于常量字符串来说,它的内容一样的时候,只会保存一份,不会保存多份,当这个字符串把首字符的地址交给str3的时候,str3就是一个指针变量,里边存的是'h'的地址,同理,str4指针变量里边存放的也是'h'的地址,所以,str3和str4打印结果相同。


2. 指针数组

在刚接触指针的时候我们就说过指针数组是数组。那该怎么理解它呢?

🎈我们说:

字符数组是存放字符的数组;

整型数组是存放整形的数组;

那指针数组就是存放指针的数组,即存放在数组中的元素都是指针类型的。

🎈例:

int* arr[5];//存放整形指针的数组
char* ch[6];//存放字符指针的数组

 🍂下面我们使用指针数组模拟一个二维数组:

#include <stdio.h>int main()
{int arr1[] = { 1,2,3,4,5 };int arr2[] = { 2,3,4,5,6 };int arr3[] = { 3,4,5,6,7 };//指针数组int* arr[] = { arr1,arr2,arr3 };int i = 0;for (i = 0; i < 3; i++){int j = 0;for (j = 0; j < 5; j++)//打印一行的元素{printf("%d ", arr[i][j]);}printf("\n");}return 0;
}

 🍇运行结果:


3.数组指针

3.1数组指针的定义

数组指针是指针?还是数组?

答案是指针。

  • 我们知道字符指针是指向字符的指针;
  • 整形指针是指向整形的指针;
  • 浮点型指针是指向浮点型的指针;
  • 那数组指针就是指向数组的指针!

3.2 &数组名VS数组名

🎈对于下面的数组:

int arr[10];

arr 和 &arr 分别是啥?我们知道arr是数组名,数组名表示数组首元素的地址。那&arr数组名到底是啥?我们看一段代码:

#include <stdio.h>int main()
{int arr[10];printf("%p\n", arr);printf("%p\n", &arr);return 0;
}

🍂运行结果如下: 

可见数组名和&数组名打印的地址是一样的,难道两个是一样的吗?我们再看一段代码:

#include <stdio.h>int main()
{int arr[10] = { 0 };printf("arr = %p\n", arr);printf("arr+1 = %p\n", arr + 1);printf("&arr= %p\n", &arr);printf("&arr+1= %p\n", &arr + 1);return 0;
}

🍂运行结果如下: 

  1. 根据上面的代码我们发现,其实&arr和arr,虽然值是一样的,但是意义应该不一样的。
  2. 实际上: &arr 表示的是数组的地址,而不是数组首元素的地址。
  3. 本例中 &arr 的类型是: int(*)[10] ,是一种数组指针类型。
  4. 数组的地址+1,跳过整个数组的大小,所以 &arr+1 相对于 &arr 的差值是40。

3.3数组指针的使用

 那数组指针是怎么使用的呢?

既然数组指针指向的是数组,那数组指针中存放的应该是数组的地址,看代码:

#include <stdio.h>int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int(*p)[10] = &arr;//把数组arr的地址赋给数组指针变量pint i = 0;for (i = 0; i < 10; i++){//因为p里边存放的是&arr,对它解引用,//就相当于拿到了数组名(取地址和解引用可以互相抵消),//这时候访问数组里边每个元素的时候还得用下标(*p)[i],就会显得多此一举//所以我们一般很少这样写代码(*p) == (*&arr) == (arr);}//正确写法int* p = arr;int i = 0;for (i = 0; i < 10; i++){printf("%d ", p[i]);}return 0;
}

🍂数组指针的使用: 

#include <stdio.h>void print_arr1(int arr[3][5], int x, int y)//形参也是使用二维数组的形式
{int i = 0;for (i = 0; i < 3; i++){int j = 0;for (j = 0; j < 5; j++){printf("%d ", arr[i][j]);}printf("\n");}
}void print_arr2(int (*arr)[5], int x, int y)//形参的部分使用的是指针
{int i = 0;for (i = 0; i < 3; i++){int j = 0;for (j = 0; j < 5; j++){printf("%d ", arr[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} };print_arr1(arr, 3, 5);//二维数组传参//数组名arr,表示首元素的地址//但是二维数组的首元素是二维数组的第一行//所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址//可以数组指针来接收print_arr2(arr, 3, 5);//二维数组传参return 0;
}


 


🍂下面我们再来分析一组代码:

int arr[5];

arr是一个数组,数组有5个元素,每个元素是整形类型,所以arr是一个能够存放5个整形数据的数组 

int* parr1[10];

parr1是一个数组,数组有10个元素,每个元素的类型是int*类型 

int(*parr2)[10];

parr2是一个数组指针,该指针是指向数组的,指向的数组有10个元素,每个元素的类型是int 类型

int(*parr3[10])[5];

parr3是一个数组,是存放数组指针的数组,数组有10个元素;存放的这个数组指针,指向的数组有5个元素,每个元素是int类型 

相关文章:

深入理解指针:【探索指针的高级概念和应用一】

目录 前言&#xff1a; 1. 字符指针 2. 指针数组 3.数组指针 3.1数组指针的定义 3.2 &数组名VS数组名 3.3数组指针的使用 前言&#xff1a; &#x1f342;在了解今天的内容之前我们先复习一下指针的基本概念&#xff1a; 1&#xff0c;内存单元是有编号的&#xff…...

Leetcode周赛365补题(3 / 3)

目录 1、2、有序三元组的最大值 - 预处理前后最大值 遍历 &#xff08;1&#xff09;预处理前后值遍历&#xff08;枚举j&#xff09; &#xff08;2&#xff09;枚举k 2、无限数组的最短子数组 - 前缀和 滑动窗口 1、2、有序三元组的最大值 - 预处理前后最大值 遍历 …...

Python基础入门例程13-NP13 格式化输出(三)

目录 描述 输入描述&#xff1a; 输出描述&#xff1a; 示例1 解答&#xff1a; 1&#xff09;第一种strip函数 2&#xff09;先删除左边&#xff0c;再删除右边的空格&#xff0c;使用.lstrip函数和 .rstrip函数 3) 使用replace函数 4)使用split和join函数&#xff0c…...

Vue快速入门

一、概述 1.是一套前端框架&#xff0c;可免除原生JavaScript中的DOM操作&#xff0c;基于MVVM思想&#xff0c;实现数据双向绑定。 实现由MVC——>MVVM的转换 二、入门 1.新建HTML页面&#xff0c;引入Vue.js文件 2.在JS代码区&#xff0c;创建Vue核心对象&#xff0c;进行…...

MySQL - 如何判断一行扫描数?

在MySQL中&#xff0c;一行扫描数是在执行查询操作时&#xff0c;需要扫描的行数&#xff0c;以找到与查询条件匹配的行。这个值反映了查询的效率。 MySQL 判断一行扫描数的方法&#xff1a; 索引的使用&#xff1a;MySQL首先会检查查询是否可以使用索引。如果可以&#xff0…...

3682: 【C3】【递推】台阶问题

题目描述 有N级的台阶&#xff0c;你一开始在底部&#xff0c;每次可以向上迈最多K级台阶&#xff08;最少1级&#xff09;&#xff0c;问到达第N级台阶有多少种不同方式。 输入 两个正整数N&#xff0c;K。(N≤100000,K≤100) 输出 一个正整数&#xff0c;为不同方式数&a…...

C++(Qt)软件调试---线程死锁调试(15)

C(Qt)软件调试—线程死锁调试&#xff08;15&#xff09; 文章目录 C(Qt)软件调试---线程死锁调试&#xff08;15&#xff09;1、前言2、常见死锁3、linux下gdb调试C死锁1.1 使用代码1.2 gdb调试 3、linux下gdb调试Qt死锁1.1 使用代码1.2 gdb调试 4、Windows下gdb调试C死锁5、W…...

HugeGraph Hubble 配置 https 协议的操作步骤

背景 HugeGraph 图数据库的 Server 端支持 https 配置&#xff0c;官方文档中有说明相对比较容易&#xff0c;而 Hubble 部署过程都是 http的。 我们有一个应用要嵌入 hubble 页面&#xff0c;而且部署为 https &#xff0c;那么 Hubble 是否支持配置 https 呢&#xff1f;网…...

大型应用的架构演进--spring家族在其中的作用

01 大型应用的架构演进 带来的挑战&#xff1a; 运维与监控 分布式带来的复杂性 接口的调整成本 测试成本 依赖管理成本 02 Spring家族 在我看来&#xff0c;springboot的3大特点(我常用的)&#xff1a;内置的web容器&#xff1b;开箱即用的starter模版&#xff1b;自动配置&…...

LinkedHashMap 简单实现LRU

要使用 LinkedHashMap 来实现LRU&#xff08;最近最少使用&#xff09;缓存&#xff0c;可以设置它的访问顺序为true&#xff0c;以便在每次访问一个元素时&#xff0c;将它移到最后&#xff0c;从而实现LRU的特性。以下是一个简单的Java示例&#xff1a; import java.util.Li…...

mysql字符串函数

函数名 描述 示例 ASCII(s) 返回字符串s的第一个字符的ASCII码 返回CustomerName字段第一个字母的ASCII码&#xff1a; SELECT ASCII(CustomerName) AS NumCodeOfFirstChar FROM Customers; CHAR_LENGTH(s) 返回字符串s的字符数 返回字符串RUNOOB的字符数&#xff1a; …...

【强烈推荐】视频转gif、图片拼gif,嘎嘎好用,免费免费真的免费,亲测有效,无效过来打我

问题描述 最近遇到一个需求是需要将视频生成gif&#xff0c;这个看上去不是很难&#xff0c;所以有了以下的解决办法 解决办法 首先想到的当然是自己写一个&#xff0c;用了两套代码&#xff1a; from moviepy.editor import *# 读取视频文件 video_clip VideoFileClip(&quo…...

C# Onnx Yolov8 Detect 印章 指纹捺印 检测

应用场景 检测文件中的印章和指纹捺印&#xff0c;用于判断文件是否合规&#xff08;是否盖章&#xff0c;是否按印&#xff09; 效果 项目 代码 using Microsoft.ML.OnnxRuntime; using Microsoft.ML.OnnxRuntime.Tensors; using OpenCvSharp; using System; using System.…...

0034【Edabit ★☆☆☆☆☆】【修改Bug4】Buggy Code (Part 4)

0034【Edabit ★☆☆☆☆☆】【修改Bug4】Buggy Code (Part 4) bugs conditions strings Instructions Emmy has written a function that returns a greeting to users. However, she’s in love with Mubashir, and would like to greet him slightly differently. She add…...

第十五篇-推荐-Huggingface-镜像-2023-10

推荐一个Huggingface-镜像网站 可下载模型和数据集&#xff0c;解决Huggingface无法访问问题&#xff0c;希望可以一直使用 https://hf-mirror.com/ 举个栗子 https://hf-mirror.com/models?searchqwen 有时需要验证&#xff0c;按要求点就好 域名 hf-mirror.com&#xf…...

Macos文件图像比较工具:Kaleidoscope for Mac

Kaleidoscope是一款文件图像比较工具&#xff0c;它可以方便地比较两个文本或者图片文件的差异。这个工具可以在Mac系统上使用&#xff0c;并且支持多种文件格式&#xff0c;包括文本文件、图片文件、PDF文件等等。 Kaleidoscope有一个直观的用户界面&#xff0c;可以让用户轻…...

Docker搭建Plex流媒体服务并播放自己本地视频

Docker搭建Plex流媒体服务 安装Docker创建存储配置文件的目录创建Plex容器配置Plex设置媒体库访问Plex 1 介绍 Plex是一个流媒体服务器&#xff0c;可以轻松地将你的媒体文件库&#xff08;如电影、电视节目和音乐&#xff09;通过网络流式传输到各种设备上。 Plex 是一套媒体…...

idea + Docker-Compose 实现自动化打包部署(仅限测试环境)

一、修改docker.service文件&#xff0c;添加监听端口 vi /usr/lib/systemd/system/docker.service ExecStart/usr/bin/dockerd -H fd:// --containerd/run/containerd/containerd.sock -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock重启docker服务 systemctl daemo…...

ubuntu 下载Python

目前为止&#xff0c;Python 3.11 是最新版本的 Python。要在 Ubuntu 中下载和安装 Python 3.11&#xff0c;可以按照以下步骤进行&#xff1a; 安装编译所需的依赖项&#xff1a; sudo apt update sudo apt install -y build-essential zlib1g-dev libffi-dev libssl-dev libl…...

python 使用json包在json格式字符串和python对象之间的变化

起因&#xff1a;使用python json包时&#xff0c;将键值对均为数字的字典存入txt文件后重新加载进字典后出现“字典key值不唯一”的神奇现象。 相关代码&#xff1a; 字典添加数据部分 def xuhao_chuti(self):rand random.randint(1, 908)if rand in self.memery.keys() an…...

【C++】继承 ⑫ ( 继承的二义性 | virtual 虚继承 )

文章目录 一、继承的二义性1、场景说明 - 继承的二义性2、继承中的二义性报错3、完整代码示例 二、virtual 虚继承1、虚继承引入2、虚继承语法3、代码示例 - 虚继承 一、继承的二义性 1、场景说明 - 继承的二义性 A 类 是 父类 , B 类 和 C 类 继承 A 类 , 是 子类 , D 类 多…...

Linux网络流量监控iftop

在 Linux 系统下即时监控服务器的网络带宽使用情况&#xff0c;有很多工具&#xff0c;比如 iptraf、nethogs 等等&#xff0c;但是推荐使用小巧但功能很强大的 iftop 工具【官网&#xff1a;http://www.ex-parrot.com/~pdw/iftop/】。iftop 是 Linux 系统一个免费的网卡实时流…...

【虚幻引擎UE】UE4/UE5 基于2D屏幕坐标获取场景3D坐标 射线检测(蓝图/C++)

UE4/UE5 基于2D屏幕坐标获取场景3D坐标 一、射线检测1&#xff09;定义1&#xff09;射线与3D场景中的物体交互的流程2&#xff09;射线检测蓝图函数3&#xff09;蓝图实现根据鼠标点击位置获取场景中的坐标值4&#xff09;根据相机中心点获取场景中的坐标值5&#xff09;射线检…...

【OpenHarmony】系统编译环境搭建笔记

0、安装WSL 一定要安装WSL 2否则编译慢到怀疑人生。 1、将WSL从C盘迁移到其他盘 2、安装编译依赖库 按照上述流程&#xff0c;安装会提示一些错误&#xff0c;直接使用如下命令&#xff1a; sudo apt-get update && sudo apt-get install binutils binutils-dev g…...

深入理解JVM虚拟机第十二篇:JVM中的线程说明

文章目录 一:线程说明 1:线程概述 2:后台虚拟机主要线程 (一):虚拟机线程...

synchronized 、ReentrantLock

synchronized 和 ReentrantLock 都是用于实现多线程同步的机制: 锁的获取方式: synchronized 是内置的 Java 关键字,它通过对象的内置监视器来获取锁。每个对象都有一个关联的监视器,只有一个线程可以获得对象的监视器,其他线程必须等待。ReentrantLock 是一个类,它提供了…...

用VSCODE启动Java项目

下载插件 推荐下载插件 启动 在vscode中打开项目或将项目拖进vscode,等进度条加载完成即成启动项目...

最简单的修改linux系统上Docker的镜像源

前言 是不是从docker上下载镜像总是很慢 我有两个物理服务器,两个都在本地不能访问国际网络,那只能使用国内网络,就是下载docker镜像太慢了,慢的我心情都不好了,所以就出了这篇文章用来解决docker下载慢的问题 正文 1.首先你得下载好docker,在Linux上,下载Docker的命令是下面这…...

layui移除(删除)table表格的一行

表格里添加删除按钮&#xff1a; , {field: wealth, width: 150, title: 操作, align: center, fixed: right,templet: function (item) {return <a style"margin:0px 5px; color:red; cursor: pointer;" lay-event"delete" id"DeleteTr" >…...

67 跳跃游戏 II

跳跃游戏 II 题解1 贪心1 正向题解2 贪心2 反向题解3 DP 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说&#xff0c;如果你在 nums[i] 处&#xff0c;你可以跳转到任意 nums[i j] 处: 0 &…...