带你学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;
}

🏆结束语

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

线程的介绍

首先我们来了解一下线程是什么&#xff1a; 首先我们介绍一下程序是什么&#xff1f;程序就是我们编写的代码就叫程序&#xff0c;当我们程序运行的时候则称为进程&#xff0c;在我们现实生活中哪些用到了进程&#xff0c;就比如说我们qq&#xff0c;微信&#xff0c;百度网盘…

Spring容器中scope为prototype类型Bean的回收机制

文章目录 一、背景二、AutowireCapableBeanFactory 方法 autowireBean 分析三、Spring 容器中 scope 为 prototype 类型 Bean 的回收机制四、总结 一、背景 最近做 DDD 实践时&#xff0c;遇到业务对象需要交给 Spring 管理才能做一些职责内事情。假设账号注册邮箱应用层代码流…

【注解和反射】-- 04 类加载器、运行时类的对象

反射 03 类的加载与ClassLoader 3.4 类加载器 类加载器的作用&#xff1a;将class文件字节码内容加载到内存中&#xff0c;并将这些静态数据转换成方法区的运行时数据结构&#xff0c;然后在堆中生成一个代表这个类的java.lang.Class对象&#xff0c;作为方法中类数据的访问…

Amortized Bootstrapping of LWE:使用 BFV 打包处理

参考文献&#xff1a; [AP13] Alperin-Sheriff J, Peikert C. Practical bootstrapping in quasilinear time[C]//Annual Cryptology Conference. Berlin, Heidelberg: Springer Berlin Heidelberg, 2013: 1-20.[MS18] Micciancio D, Sorrell J. Ring packing and amortized F…

Flask维护者:李辉

Flask维护者&#xff1a;李辉&#xff0c; 最近看b站的flask相关&#xff0c;发现了这个视频&#xff1a;[PyCon China 2023] 濒危 Flask 扩展拯救计划 - 李辉_哔哩哔哩_bilibili 李辉讲他在维护flask之余&#xff0c;开发了apiflask这个依托flask的框架。GitHub - apiflask/a…

02markdown-学习笔记

一级标题 二级标题 三级标题 四级标题 五级标题 六级标题 换行符<br>标签 写入一段测试用的正文第二段测试文本,如果要对文本进行换行可以使用<br>标签 文本修饰符 字体为斜体的修饰&#xff0c;一对星号包含 字符为粗体&#xff0c;两对星号包含 字体为…

ISP-EE(Edge Enhance)

ISP-EE(Edge Enhance) EE模块在某些ISP主控中叫做sharpness或者sharpen&#xff0c;这些名称指代的模块是同一个&#xff0c;不用再纠结。主要就是在YUV域内弥补成像过程中图像的锐度损失&#xff0c;对边缘和细节进行加强&#xff0c;从而恢复场景本应具有的自然锐度。 锐度…

三层交换与DHCP

目录 一、三层交换 &#xff08;一&#xff09;基本概念 &#xff08;二&#xff09;转发原理 &#xff08;三&#xff09;ensp项目实验 二、DHCP &#xff08;一&#xff09;DHCP工作原理 1.DHCP的特点 2.工作原理 &#xff08;二&#xff09;DHCP项目实验 一、三层交…

Node.js黑马时钟案例

先上没有使用node.js之前的html部分代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title></title><style>* {margin: 0;padding: 0;}html,body {height: 100%;overflow: hidden;backgrou…

猿人学简单题分析(js逆向)

猿人学15T&#xff0c;实际带着大家分析一下。 开发者工具进行抓包&#xff0c;然后找的参数类型 由于这里的加密参数是m搜索出来的肯定是很多的&#xff0c;所以直接上XHR断点进行快速定位。 直接调用堆栈开始向上找。 控制台输出这个window.m查看这个函数的位置。 找到直接扣…

git安装和配置

git安装和配置 一、软件介绍 Git是一个免费开源的分布式版本控制系统&#xff0c;旨在快速高效地处理从小型到大型项目的所有内容。 Git易于学习&#xff0c;占地面积小&#xff0c;性能闪电般快。它以廉价的本地分支、方便的暂存区域和多个工作流等功能胜过了Subversion、C…

golang反射(reflect)虽爽,但很贵

标准库 reflect 为 Go 语言提供了运行时动态获取对象的类型和值以及动态创建对象的能力。反射可以帮助抽象和简化代码&#xff0c;提高开发效率。 但是使用反射势必会多出大量的操作指令&#xff0c;导致性能下降 案例 字段赋值方式对比 type Student struct {Name string…

1.electron之纯原生js/jquery的桌面应用程序(基础篇)

如果可以实现记得点赞分享&#xff0c;谢谢老铁&#xff5e; Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 Electron 将 Chromium 和 Node.js 嵌入到了一个二进制文件中&#xff0c;因此它允许你仅需一个代码仓库&#xff0c;就可以撰写支持 Windows、…

灾备建设中,虚拟机异构平台恢复技术原理与应用

在如今混合云环境下&#xff0c;实现异构虚拟化恢复与迁移面临着极大挑战。不同于市面上有代理的恢复方案&#xff0c;虚拟机无代理跨平台恢复解决方案利用自主研发的转换引擎&#xff08;VMCE&#xff09;对已备份虚拟机文件进行高效的存储格式转换和配置信息转换&#xff0c;…

基于java 的经济开发区管理系统设计与实现(源码+调试)

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。今天给大家介绍一篇基于java 的经济开发区管…

基于Springboot的教学信息反馈系统的设计与实现(源码+调试)

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。今天给大家介绍一篇基于Springboot的教学信…

如何进行Feign的自定义配置

Feign可以支持很多的自定义配置&#xff0c;下列是部分配置信息 类型作用说明Logger.Level修改日志级别配置键&#xff1a;loggerLevel&#xff0c;包含四种不同的级别&#xff1a;NONE、BASIC、HEADERS、FULLClass<Retryer>失败重试机制配置键&#xff1a;retryer&#…

dcoker-compose一键部署EFAK —— 筑梦之路

简介 EFAK&#xff08;Eagle For Apache Kafka&#xff0c;以前称为 Kafka Eagle&#xff09;是一款由国内公司开源的Kafka集群监控系统&#xff0c;可以用来监视kafka集群的broker状态、Topic信息、IO、内存、consumer线程、偏移量等信息&#xff0c;并进行可视化图表展示。独…

stm32H库的内部FLASH读写操作与结构体数组数据写入与读取

stm32H库的内部FLASH读写操作与结构体数组数据写入与读取 1.软硬件准备2.关于STM32的Flash的一些说明3.实验结果 参考博主-STM32系列(HAL库)——内部FLASH读写实验 1.软硬件准备 软件&#xff1a;CubeMX、SSCOM&#xff08;串口调试助手&#xff09; 硬件&#xff1a;SMT32F…

如何查看KylinOS银河麒麟操作系统版本?

如何查看KylinOS银河麒麟操作系统版本? 当前银河银河麒麟高级服务器操作系统V10发行版如下&#xff1a; (Tercel) 版本是 银河麒麟 V10 SP1 版本(Sword) 版本是 银河麒麟 V10 SP2 版本(Lance) 版本是 银河麒麟 V10 SP3 版本我们可使用如下三种方式&#xff08;命令&#xff0…