带你学C语言~指针(1)

        Hello,CSDN的各位家人们,你们好啊!今天,小赵要给大家分享的C语言知识是指针,相信不少家人们都或多或少被指针搞得晕头转向,小赵一开始也是,但后来小赵经过不断地努力学习,终于将这里面的知识弄懂了。由于指针的知识点实在太多,小赵决定将它分为几个小部分,让大家更好地学习和吸收。

目录

🎾内存与地址

⚾内存

⚾地址

🎾指针变量与地址

⚾取地址

⚾指针变量

⚾如何认识指针类型

⚾解指针

⚾指针占多少内存

🥉指针变量类型的意义

🎯不同指针类型的影响

🎯void型指针

🎯const修饰指针

🥈指针运算

🏉指针与整数运算(加减)

🏉指针与指针运算

🏉指针的大小比较

🥇野指针

🏓野指针是什么

🏓如何避免野指针

🏐assert断言

🏆指针的使用和地址的调用

⚽模拟strlen函数

⚽传值与传址

🏆结束语


     

🎾内存与地址

⚾内存

在开始指针之前,小赵先和你们聊聊内存,内存是什么,其实我们大多数人心中应该是有自己的一个定义的,因为我们的手机啊,电脑啊,存储一些软件,音乐什么的靠的其实就是我们的内存,可内存究竟是怎么调用的,我们好像并不太清楚也并不太了解。但我们的生活中有一个有意思的例子可以让我们摸清楚就是,我们的房子也是用来存东西的,存我们的书籍,衣服等等,那它是怎么调用和找到的,其实靠的点就两个一个门牌,一个钥匙。

正是这两个东西的存在,让我们所有人都可以井然有序的生活,不会乱放自己的东西在别人家,不会走错门,也让自己的东西不会被别人偷。那我们的内存是不是也是一样呢。其实电脑和内存的关系就是下面这张图展现的。

我们的电脑其实就是通过给每个内存编号,来进行存储访问的,而这个编号其实就是我们下面要讲的地址了。 

⚾地址

如此庞大的内存,究竟是靠着怎么编写的地址来进行有序的访问,相信这是不少小伙伴们的疑惑,其实要解决这个问题还是要借助我们的内存。我们都知道,我们的内存存储是分很多的单位。正如下面这张图。

 在这些茫茫的内存中我们的地址选择了字节,内存把自己分成了无数个细小的字节单位,给每一个字节编写编号,而这个编号就是我们的地址。

🎾指针变量与地址

⚾取地址

我们说既然每个东西它都有自己的内存也都有自己的地址,那我们如何去取出我们的地址呢?又该如何去看到我们的地址。那么小赵就在这里为大家演示一下,首先呢,在我们的C语言中是有一个专门的操作符用来取这个地址的,这操作符就叫取地址操作符,即&。那么如何用呢?

利用我们VS的调试的功能

 在里面输入我们的地址,然后再按一下回车,就可以出来我们的地址了。

 

⚾指针变量

那么既然已经如此完美了,那为什么还要我们指针的存在呢?就像你要去往任何一个房屋总要直到它的地址,而我们的指针干的就是存地址的活,同时它还可以帮助你去打开地址,往那块内存里面去存。这一点就相当于什么呢,就好比这个房子的主人把自己房子的门牌号告诉给了那个人,同时还给了它钥匙,让他能够去拥有这个房子的使用权,但这个房子其实还是归属于这个房主的,在现实中其实也有对应就是租房子给别人的那种感觉。

⚾如何认识指针类型

讲到现在也没把指针长啥样,拉出来给大家看看,那么现在我们就当当当请出我们的指针,来看看这究竟长啥样,能如此强大。

其实看完了这个图相必大家也能推出其他类型的指针,比如字符指针,short类型的指针,long.....等一系列指针,但其实指针也有一些需要注意的或者说难写的,这个我们后面再聊。

⚾解指针

那好了,现在指针我们拿到了地址了,可你不能光给我地址啊,我都租了,你好歹让我在你这个房子里倒腾一下,这个我们C语言也早就准备好了,我们C语言的解指针用的就是*,对没错这个是不是超级像你那个钥匙插进去的那个门缝,所以这个可好记了,下面小赵就要给大家演示一下我们该怎么用这个指针去倒腾这个房子了。

怎么样是不是很神奇,其实这里小赵还有一个比较有意思的说法,a=10,其实就相当于我们家本来的样子,*p=150,就相当于我们打开家,把家倒腾成的样子,然后我们再输出家的样子。怎么样还是有意思的吧。

⚾指针占多少内存

那么我们的指针究竟占多少的内存呢?

这个其实这要分情况的,首先就是我们x64(即64位)的版本下面,我们可以打出来看看。

接着就是我们的x86(即32位)

🥉指针变量类型的意义

相信这个时候就有人问了,指针变量所占的内存的大小是一样的吗?那当然是一样的。那为什么还要划分为各种指针类型呢?既然大家内存都一样,直接用就好了,分这么多类干嘛?那么接下来小赵就来帮助你去解决这个问题。

🎯不同指针类型的影响

其实我们都知道,不同的类型所占的内存大小是不一样的,而到了指针这里,就完全可以看作是它所控制的内存大小,比如你租房子只租给一个人卧室,那么对这个人来说他所能改变的其实就只能是这个卧室以内的范围,外面的厨房其实他没办法去改变。那么对指针来讲也是一样的。比如你一个指向char类型的指针去指向人家int的类型的指针那你所能改变的也只有人家的四分之一部分咯。

在上面的这些案例中,我们不难发现不同类型的指针变量所拥有的权利是不一样的,它们的访问权完全由自身所指向的类型的所占的内存大小决定。

🎯void型指针

但一个队伍总会有这么一个特殊的存在,也可以说是几乎全能的存在,没错这个在指针中可以访问一切类型的指针类型是存在的就是我们的void型指针,这个指针类型可以接收所有的指针类型,但全能未必是好事,它的遗憾就是它无法打开门读取(即无法解指针),也无法对内存做出任何修改。如果要进入其中修改,就必须强制类型转化成其他类型,这个我们后边会多次使用这个指针去接收一些其他指针,在这里小赵就不多讲了,就给大家举个简单的例子吧。

🎯const修饰指针

首先我们先再一次认识一下我们const.

const 限定符,它把一个对象转换成一个常量。

既然const是把我们修饰的变量转变为常量,那你说这个变量还能变吗?当然是不能啦。比如我们的常量1,还能有一天忽然变了不成,当然不可能变啦。下面可以看一下小赵举得一个例子更加深刻地体会一下。 

那放到我们的指针上又是怎么样呢?

先看第一种

那么这里为什么会报错呢,其实这里就相当于是修饰我们指针变量所指的地址的那部分内存,就是我把你这部分内存给定下来了,既然定下来了,那你说这个内存我还能变吗?

但是我们p这个租房子的是可以走的,你定了房子的样子,但不代表我这个租房子的人不能走啊。

我们的p只需要重新去租个房子就好了。

下面看第二种

其实这里也相当于我们的第一种,当然小赵在这里有个比较有意思的说法啊就是把这个*p(人和钥匙绑一起就是那个房间)当成我们租的那块地盘,你把我租的地盘定下了,那你说这个地盘还能动吗?而单独的一个P则相当于一个自由自在的人,那它不就可以改变了吗?

接下来看第三种。

第三种其实你再用小赵上面的理解就好理解了,就是我把你这个租客定下来,也就是这个指针变量所指的地址定下来,那你说他还自由吗,他不久不能换地址了,但这时候地址那块空间没定下来,那不就可以随便改吗?

总结:

结论:const修饰指针变量的时候
• const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。
但是指针变量本身的内容可变。
• const如果放在*的右边,修饰的是指针变量本身,保证了指针变量的内容不能修改,但是指针指 向的内容,可以通过指针改变。

🥈指针运算

那么接下来就有人要问了,指针可以运算吗,运算的意义又是什么呢?

下面小赵来为你解答。

🏉指针与整数运算(加减)

指针于整数的与运算,上面我们提到了,我们地址在内存中是以一个一个的单元存储的,每个单元是1个字节,那我们的指针与整数的加减运算,其实就是跳过了多少个这样的单元,而跳过多少个单元的问题,那究竟跳过多少个呢?其实就是(整数)*(指向的类型所占的字节大小)

这里小赵为了方便大家理解,用我们的数组做个示范。因为数组里面存储的数据是连续的。

🏉指针与指针运算

那么指针与指针的运算,这个就比较有意思了,它的结果其实就是这两个地址之间的元素多少,当然这个其实我们一般也是数组用的多,因为其他的数据都不一定是连续的,只有数组我们目前确定是连续的。

🏉指针的大小比较

那么两个指针的大小比较呢,其实这个就跟我们的地址高低有关了,其实也是后面小赵要与各位聊的,但可以透露的一点是数组下面的下标越高,它的地址一般越高,毕竟也是后创建的。

当然还有一点要提的是,我们的数组必须是在一个数组中,两个数组是不连续的。 

🥇野指针

🏓野指针是什么

野指针往往其实指的就是一块没有被开发的内存,就是你这个指针啊,没有指向任何地址,这个地址就是随机的,同时也是不允许被使用的。就像你随便找了一个房子没被人授权,这能允许吗?

野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)指针变量在定义时如果未初始化,其值是随机的,指针变量的值是别的变量的地址,意味着指针指向了一个地址是不确定的变量,此时去解引用就是去访问了一个不确定的地址,所以结果是不可知的。 

像我们在敲代码时候常遇到的情况有 三种

第一种,是由于我们没给它地址。

这时候我们的编译器是会报错的;

第二种越界访问。

这里我们跳过了a这块区域,然后就是未知区域,所以出来的也是随机值。 

第三种使用的空间被回收或释放

这里出现的情况就是我们的函数在运行结束后将自己开辟的那块空间收回了,所以再找也就是一块野指针了。(这里函数栈帧会讲)

🏓如何避免野指针

那么如何避免这个野指针呢?

方案一

我们把我们的指针上来就指向一个明确的地址。

方案二

给它一个空指针,让它什么都没有无法使用。

它既然是一块空区域,那你也就没办法塞东西给里面了。

🏐assert断言

assert是用来干嘛呢?我们可以先用小赵上次说的网站查查。

我们注意到assert是看你括号里面的东西是否是真的,如果错了它就会终止程序的运行。

那么这个就刚好可以判断我们的指针是否是空指针,防止我们的错误使用。

🏆指针的使用和地址的调用

好了,我们了解上面的一些关于指针的相关知识下面小赵带你去实际应用我们的指针吧。

⚽模拟strlen函数

 其实这个函数也是小赵多次提到的一个函数,它的主要作用,就是去算一个字符串在\0之前的字母数,同时还要注意的一点是它的是要头文件的即#include<string.h>

 那我们究竟该如何实现呢?在这里小赵就不卖关子了。

int my_strlen(char* a)
{int count = 0;while (*a != '\0')//*a不等于'\0',继续运行{a++;//看下一个字母count++;//统计字母数量}return count;//返回字母数量
}
int main()
{char a[10] = "abcdef";int m = my_strlen(a);printf("%d", m);}

 

⚽传值与传址

其实之前学完函数后就有不少人有这样的困惑了,就是要给两个变量在函数里面换值的无法成功,这其实是因为函数里面创建的变量都是临时变量,当函数运行完了,这些代码的空间什么的都会回收,我们的值就像我们输入进去,给它们里面的两个在里面换,但人间不会影响到你外面的人

但如果这里你用我们的地址就不一样了,因为我们如果用地址,那么它就可以开打开我们这边的房间对我们进行换值了。

void Swap(int* px, int* py)//传入的地址给你
{int tmp = 0;tmp = *px;//这部分和之前的交换一样*px = *py;*py = tmp;
}
int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b);printf("交换前:a=%d b=%d\n", a, b);Swap(&a, &b);printf("交换后:a=%d b=%d\n", a, b);return 0;
}

🏆结束语

好了小赵今天的分享就到这里了,如果大家有什么不明白的地方可以在小赵的下方留言哦,同时如果小赵有什么地方说得不对也希望得到大家的指点,谢谢各位家人们的支持。你们的支持是小赵创作的动力,加油。

如果觉得文章对你有帮助的话,还请点赞,关注,收藏支持小赵,如有不足还请指点,小赵及时改正,感谢大家支持!!!

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

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

相关文章

Pearson、Spearman 相关性分析使用

介绍 Pearson 积差相关系数衡量了两个定量变量之间的线性相关程度。 用来衡量两个数据集的线性相关程度&#xff0c;仅当一个变量的变化与另一个变量的比例变化相关时&#xff0c;关系才是线性的。 Spearman等级相关系数则衡量分级定序变量之间的相关程度。斯皮尔曼相关系数不…

汽车充电协议OpenV2G的平替cbexigen!!

纵所周知&#xff0c;开源欧规协议 CCS 的 OpenV2G 协议不支持 ISO15118-20:2022 协议&#xff0c;并且软件维护者已经明确不在进行该软件的维护。 前几天在 Github 上冲浪发现了一个宝藏开源项目&#xff0c;完美的实现的 OpenV2G 的 Exidizer 工具的功能&#xff1a;cbexigen…

Centos开机进入grub命令行模式进入不了操作系统

环境&#xff1a;没有linux命令&#xff0c;没有initrd命令&#xff0c;没有init6命令 由于删除了/boot/efi/EFI/centos/grub.cfg &#xff0c;重启服务器后&#xff0c;无法进入原来正常的系统&#xff0c;进入了grub命令行界面 备注&#xff1a;对于centos7/8/openEuler: 如果…

java_扁平<--->树转换的思路和方法参考

扁平转树形笔记 1.通过先找到根节点&#xff0c;然后在递归子节点的方法找子节点的子节点 public static List<Good> list2tree(List<Good> list){List<Good> resList new ArrayList<>();for (Good good : list) {// 找到根节点if (good.getpId() …

数据结构之排序

目录 ​ 1.常见的排序算法 2.插入排序 直接插入排序 希尔排序 3.交换排序 冒泡排序 快速排序 hoare版本 挖坑法 前后指针法 非递归实现 4.选择排序 直接选择排序 堆排序 5.归并排序 6.排序总结 一起去&#xff0c;更远的远方 1.常见的排序算法 排序&#xff1a;所…

Unity实现GoF23种设计模式

文章目录 Unity实现GoF23种设计模式概要一、创建型模式(Creational Patterns):二、结构型模式(Structural Patterns):三、行为型模式(Behavioral Patterns):Unity实现GoF23种设计模式概要 GoF所提出的23种设计模式主要基于以下面向对象设计原则: 对接口编程而不是对实…

IP段(CIDR格式)构建匹配库,传入IP查询是否命中

代码中有一些没用的自行去掉&#xff0c;我使用的CIDR格式&#xff0c;也可以通过IP的范围改造一下代码使用。 导入依赖 <dependency><groupId>com.github.seancfoley</groupId><artifactId>ipaddress</artifactId><version>5.3.3</ve…

RocketMQ系统性学习-RocketMQ领域模型及Linux下单机安装

MQ 之间的对比 三种常用的 MQ 对比&#xff0c;ActiveMQ、Kafka、RocketMQ 性能方面&#xff1a; 三种 MQ 吞吐量级别为&#xff1a;万&#xff0c;百万&#xff0c;十万消息发送时延&#xff1a;毫秒&#xff0c;毫秒&#xff0c;微秒可用性&#xff1a;主从&#xff0c;分…

可删除背包(计数类): P4141

https://www.luogu.com.cn/problem/P4141 看完第一眼想到打分治&#xff0c;然后记得以前打abc时好像见到过一种可撤销背包。 使用条件&#xff1a; 计数类&#xff0c;非最优性问题物品之间顺序无影响 因此我们直接撤销是对的

PyQt6 QFrame分割线控件

锋哥原创的PyQt6视频教程&#xff1a; 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计46条视频&#xff0c;包括&#xff1a;2024版 PyQt6 Python桌面开发 视频教程(无废话版…

消除非受检警告

在Java中&#xff0c;有一些情况下编译器会生成非受检警告&#xff08;Unchecked Warnings&#xff09;。这些警告通常与泛型、类型转换或原始类型相关。消除这些警告可以提高代码的可读性和安全性。以下是一些常见的非受检警告以及如何消除它们的例子&#xff1a; 1. 泛型类型…

STM32-UART-DMA HAL库缓冲收发

文章目录 1、说明1.1、注意事项&#xff1a;1.2、接收部分1.3、发送部分 2、代码2.1、初始化2.2、缓冲接收2.3、缓冲发送2.4、格式化打印 1、说明 1.1、注意事项&#xff1a; HAL库的DMA底层基本都会默认开启中断使能&#xff0c;如果在STM32CubeMx禁用了中断相关的功能&…

【WinForm.NET开发】使用 FlowLayoutPanel 在 Windows 窗体上排列控件

本文内容 创建项目水平和垂直排列控件更改流方向插入流中断使用停靠和锚定来定位控件使用填充和边距排列控件通过在工具箱中双击来插入控件通过绘制控件轮廓来插入控件使用插入条来插入控件将现有控件重新分配给不同的父控件后续步骤 某些应用程序要求窗体布局在窗体调整大小…

人工智能与量子计算:开启未知领域的智慧之旅

导言 人工智能与量子计算的结合是科技领域的一场创新盛宴&#xff0c;引领我们进入了探索未知领域的新时代。本文将深入研究人工智能与量子计算的交汇点&#xff0c;探讨其原理、应用以及对计算领域的深远影响。 量子计算的崛起为人工智能领域注入了新的活力&#xff0c;开启了…

利用canvas封装录像时间轴拖动(uniapp),封装上传uniapp插件市场

gitee项目地址,项目是一个空项目,其中包含了封装的插件,自己阅读,由于利用了canvas所以在使用中暂不支持.nvue,待优化; 项目也是借鉴了github上的一个项目,timeline-canvas,​​​​​​​ ​​​​​​​

GPT-4V被超越?SEED-Bench多模态大模型测评基准更新

&#x1f4d6; 技术报告 SEED-Bench-1&#xff1a;https://arxiv.org/abs/2307.16125 SEED-Bench-2&#xff1a;https://arxiv.org/abs/2311.17092 &#x1f917; 测评数据 SEED-Bench-1&#xff1a;https://huggingface.co/datasets/AILab-CVC/SEED-Bench SEED-Bench-2&…

纽扣电池是什么

纽扣电池 电工电气百科 文章目录 纽扣电池前言一、纽扣电池是什么二、纽扣电池的类别三、纽扣电池的作用原理总结前言 纽扣电池具有易于更换的特点,这使得它们成为许多便携设备的理想电源选择。但是,由于它们较小且外壳易于打开,所以家中有婴幼儿的家庭应特别注意将其放置在…

抓包工具:Sunny网络中间件

Sunny网络中间件 和 Fiddler 类似。 是可跨平台的网络分析组件 可用于HTTP/HTTPS/WS/WSS/TCP/UDP网络分析 为二次开发量身制作 支持 获取/修改 HTTP/HTTPS/WS/WSS/TCP/TLS-TCP/UDP 发送及返回数据 支持 对 HTTP/HTTPS/WS/WSS 指定连接使用指定代理 支持 对 HTTP/HTTPS/WS/WSS/T…

Mybatis-Plus利用Sql注入器批量插入更新

Mybatis-Plus是在Mybatis持久层框架上封装的一层非常好用的工具&#xff0c;最近因为想要在Mapper里加入自己自定义的通用方法&#xff0c;所以用到了Mybatis-Plus的Sql注入器。Sql注入器的作用是可以实现自定义的sql脚本并注入到MappedStatement里&#xff0c;从而达到动态拼装…

[css] flex wrap 九宫格布局

<div class"box"><ul class"box-inner"><li>九宫格1</li><li>九宫格2</li><li>九宫格3</li><li>九宫格4</li><li>九宫格5</li><li>九宫格6</li><li>九宫格7&l…