【C语言__指针01__复习篇11】

目录

前言

一、什么是指针

二、计算机中常见的单位

三、CPU是怎样找到一块内存空间的

四、如何得到变量的地址

五、指针变量

六、解引用指针变量的作用

七、指针变量的大小

八、指针变量类型的意义

        8.1  指针的解引用

        8.2  指针+-整数

九、void*指针

十、const修饰变量

        10.1 const普通变量

        10.1 const指针变量

十一、指针的运算

        11.1 指针+-整数

        11.2 指针-指针

        11.3 指针的关系比较

十二、野指针

        12.1 野指针的成因

                12.1.1 指针变量没有初始化

                12.1.2 指针变量越界访问

                12.1.3 指针变量指向的空间已被销毁

        12.2  如何规避野指针

                12.2.1 指针初始化

                12.2.2小心越界访问

                12.2.3 避免返回局部变量的地址

                12.2.4 指针使用前及时检查,指针使用后及时置NULL

十三、assert断言

十四、传值调用和传址调用

十五、strlen函数的模拟实现 


前言

本篇主要讨论以下问题:

1. 什么是指针

2. 计算机中的单位有哪些,各单位之间进制转换的大小又是怎样的

3. CPU是怎样找到一块内存空间的

3. 如何得到变量的地址,得到的地址有什么特点

4. 什么是指针变量

5. 指针和指针变量的区别是什么

6. 对指针变量解引用可以实现什么效果

7. 指针变量的大小与什么有关

8. 指针变量的类型有什么意义(2点意义)

9. 什么是void*指针,通常会怎么去使用它

10. 用const修饰普通变量、指针变量可以达到什么样的效果

11. 关于指针的运算(指针+-整数、指针-指针、指针的关系比较)它们可以怎么应用

12. 什么是野指针、野指针有哪三种常见成因,如何规避野指针

13. assert断言是什么,我们可以怎么使用它

14. 什么时候采用传值调用,什么时候采用传址调用

15. 指针的应用:strlen函数的模拟实现

一、什么是指针

1. 在生活中,一栋宿舍楼的每一个房间都会有自己的门牌号,目的是当我们想在众多房间中快速找到某一房间时,直接根据门牌号就可以快速找到,从而提高查找效率。对应在计算机中,我们在电脑上运行任何程序前,电脑首先做的工作都是先将数据载入内存中,而内存中的数据是通过CPU来处理的,CPU(中央处理器)在处理数据时,需要的数据是在内存中读取的,处理后的数据也会被放在内存中,为了能高效管理和利用内存,计算机的设计者仿照了生活中的例子,将内存划分为一个个内存单元,每个内存单元大小为1字节(8bit),每个内存单元的编号在硬件设计时就已经设计好了的并不需要额外去存储,内存单元的编号即内存单元的地址,在C语言中地址又被称为指针。

(内存单元的编号==地址==指针)

二、计算机中常见的单位

1. 1个比特位可以存放一个二进制位的0或1,8个比特位等于1个字节。

2. 8bit = 1byte、1024byte = 1KB、1024KB = 1MB(兆)、1024MB = 1TB、1024TB = 1PB。

三、CPU是怎样找到一块内存空间的

1. 计算机中的硬件和硬件之间数据传的递是通过电线实现的。

2. CPU和内存之间存在三种主要的电线:控制总线、数据总线、地址总线。

3. 每根地址总线根据有无电脉冲可用于表示二进制的0或1,32位机器上有32根地址总线(即,内存单元有2^32个,每个内存单元的地址由32个二进制位组成),64位机器上有64根地址总线(即,内存单元有2^62个,每个内存单元的地址由64个二进制位组成)。

4. CPU是怎样找到一块内存空间的?CPU向内存读取数据时,首先控制总线会发出R的指令,地址总线在接收到指令后将会生成要读取数据所在的地址,最后由数据总线通过该地址拿到将被读取的数据,并将数据传递给CPU。CPU向内存写入数据时,首先控制总线会发出W的指令,地址总线在接收到指令后将会生成要写入数据将被存放的地址,最后由数据总线在CPU中拿到将被写入的数据,并将数据存放在地址总线生成的地址中。

四、如何得到变量的地址

1. 利用取地址操作符(&),就可以得到一个变量的地址,取地址操作符(&)只有一个操作数,用printf打印地址时,用占位符%p(以16进制形式打印地址,一个16进制位表示4个二进制位,例如,0x00AFF760用二进制表示为0000 0000 1010 1111 1111 0111 0110 0000)。

2. 取地址得到的地址是变量开辟的所有内存单元中的最低的地址,因为知道最低的地址,变量所开辟的其他内存单元的地址顺藤摸瓜就能找到。

 

 

五、指针变量

1. 用于存放地址的变量称为指针变量。

2. 指针变量的类型由指针变量中地址所指向变量的类型与*组成,例如,int age = 10; int* pa = &age;这两句代码中指针变量pa类型的含义:*表达pa是一个指针变量,int表示指针变量pa所指向的变量的类型是int类型。

3. 关于定义指针变量时的格式:① int* pa ② int * pa ③ int *pa,这三种写法都可以,看个人喜好。

4. 指针和指针变量的区别:

    指针是地址,指针变量是变量它用于存放地址。

    不过在口头上所说的指针通常指的是指针变量。

六、解引用指针变量的作用

1. 对指针变量解引用后,*ptr整体表示的就是ptr所指向的变量。

2. int a = 100;

    int* pa = &a;

    *pa = 0; 

    在上面的三句代码中,*pa的意思就是通过pa中的地址找到所指向空间的变量*pa就是变量a,所以*pa = 0 这句代码相当a = 0这句代码。

3. 当我们不能/不想直接修改变量的值时,可以对存放该变量地址的指针变量解引用,间接修改变量的值。

七、指针变量的大小

1. 存放在指针变量中的值无论是什么都会被当作地址。

2. 指针变量是用来存放地址的,指针变量的大小则与地址的大小息息相关,地址的大小又是由机器的地址总线决定的(32位机器上有32位地址总线,每个地址的大小由32个二进制位组成,即需要4字节的空间来存储该地址;64位机器上有64位地址总线,每个地址的大小由64个二进制位组成,即需要8字节的空间来存储该地址),因此指针变量的大小只与机器(平台)有关,32位机器下所有地址的大小都是4字节,64位机器下所有地址的大小都是8字节

八、指针变量类型的意义

问:既然指针变量的大小只与机器(平台)有关,那么为什么不直接定义一个关键字表示指针变量的类型呢?

答:因为指针变量的类型有其特殊的两点意义。

8.1 指针的解引用

1. 对⽐,上⾯2段代码,在调试我们可以看到,代码1会将n的4个字节全部改为0,但是代码2只是将n的第⼀个字节改为0。

2. 结论:指针的类型决定了,对指针解引⽤的时候有多⼤的权限(⼀次能操作⼏个字节)。 ⽐如: char* 的指针解引⽤只能访问⼀个字节,⽽ int* 的指针的解引⽤就能访问四个字节。

8.2 指针+-整数

1. 可以看出, char* 类型的指针变量+1跳过1个字节, int* 类型的指针变量+1跳过了4个字节,这就是由于指针变量的类型差异带来的变化。

2. 结论:指针的类型决定了指针向前或者向后⾛⼀步有多⼤(距离)

九、void*指针

1. 在指针类型中有⼀种特殊的类型是 void* 类型的,可以理解为⽆具体类型的指针(或者叫泛型指 针),这种类型的指针可以⽤来接受任意类型地址。但是也有局限性, void* 类型的指针不能直接进⾏指针的+-整数和解引⽤的运算

2. ⼀般 void* 类型的指针是使⽤在函数参数的部分,⽤来接收不同类型数据的地址,这样的设计可以实现泛型编程的效果,在函数中想要使用void*中的地址时,直接强制类型转换成其他类型的指针变量即可

十、const修饰变量

10.1 const普通变量

1. const是一个关键字,恒定的、常数的意思

2. 变量本身是可以被修改的,如果想要在语法上限制变量不能被修改,在定义变量时在变量定义的前面加上const修饰即可,如下图代码所示。

3. 注意:被const修饰的变量只是在语法上限制了变量不能被修改,使得变量具有了常属性,但变量本身仍然是变量。

4. 如果想让变量的值不能被修改,其实单单用const修饰变量本身还不够,因为对存放变量地址的指针变量解引用,是可以间接修改变量的值,因此我们还要去限制一下存放变量地址的指针变量才能彻底保证变量的值不能被修改。

10.1 const指针变量

const修饰指针变量有两种写法,两种写法的含义各不相同:

1. const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变,但是指针变量本⾝的内容可变。

const int* pa = 10;和 int const * pa = 10;表达的含义一样,反正都是放在了*的左边。

2. const如果放在*的右边,修饰的是指针变量本⾝,保证了指针变量的内容不能修改,但是指针指向的内容,可以通过指针改变。

 

十一、指针的运算

11.1 指针+-整数

11.2 指针-指针

1. 指针-指针的绝对值==指针之间元素的个数 (大指针 - 小指针得正数,小指针 - 大指针得负数)。

2. 指针-指针的前提:两个指针是同一个类型的,并且指向的是通一个数组开辟的空间,否则指针之间的空隙大小是不可知的,也不知道按几个字节去计算一个元素的大小。

3. 指针 - 指针 = 中间得元素    ------------------------ 日期 - 日期 = 中间得天数

    指针 ± 整数 = 指针              ------------------------ 日期 ± 天数 = 日期 

 

11.3 指针的关系比较

十二、野指针

1. 什么是野指针:指针变量所指向的位置是没有被开辟/已经被销毁的空间。

12.1 野指针的成因

12.1.1 指针变量没有初始化

12.1.2 指针变量越界访问

12.1.3 指针变量指向的空间已被销毁

12.2  如何规避野指针

12.2.1 指针初始化

1. 如果明确知道指针指向哪⾥就直接赋值地址,如果不知道指针应该指向哪⾥,可以给指针赋值NULL.。

2. NULL 是C语⾔在<stdio.h>中定义的⼀个标识符常量,值是0,0也是地址,但这个地址是⽆法使⽤的,读写该地址会报错

#ifdef __cplusplus

        #define NULL 0

#else

        #define NULL ((void *)0)

#endif

12.2.2小心越界访问

1. ⼀个程序向内存申请了哪些空间,通过指针也就只能访问哪些空间,不能超出范围访问,超出了就是越界访问。

12.2.3 避免返回局部变量的地址

1. 如12.1.3中的代码出现的错误,不要返回局部变量的地址。

12.2.4 指针使用前及时检查,指针使用后及时置NULL

1. 约定俗成的⼀个规则:只要是NULL指针就不去访问 (NULL地址是⽆法使⽤的,读写该地址会报错)。

2. 在使用指针前先判断指针是否为NULL,在使用指针后及时将指针置NULL。

十三、assert断言

1. assert.h 头⽂件定义了宏 assert() ,⽤于在运⾏时确保程序符合指定条件,如果不符合,就报错终⽌运⾏,这个宏常常被称为“断⾔”。

2. assert() 宏接受⼀个表达式作为参数,如果该表达式为真, assert() 不会产⽣任何作⽤,程序继续运⾏。如果该表达式为假, assert() 就会报错,在标准错误流 stderr 中写⼊⼀条错误信息,显⽰没有通过的表达式,以及包含这个表达式的⽂件名和⾏号。

3. assert() 的使⽤对程序员是⾮常友好的,使⽤ assert() 有⼏个好处:它不仅能⾃动标识⽂件和 出问题的⾏号,还有⼀种⽆需更改代码就能开启或关闭 assert() 的机制。如果已经确认程序没有问题,不需要再做断⾔,就在 #include 语句的前⾯,定义⼀个宏 NDEBUG

#define NDEBUG

#include <assert.h>

然后,重新编译程序,编译器就会禁⽤⽂件中所有的 assert() 语句。如果程序⼜出现问题,可以移除这条 #define NDBUG 指令(或者把它注释掉),再次编译,这样就重新启⽤了 assert() 语句。

4. assert() 的缺点是,因为引⼊了额外的检查,增加了程序的运⾏时间。 ⼀般我们可以在 Debug 中使⽤,在 Release 版本中选择禁⽤ assert 就⾏,在 VS 这样的集成开发环境中,在 Release 版本中,直接就是优化掉了。这样在debug版本写有利于程序员排查问题, 在 Release 版本不影响⽤⼾使⽤时程序的效率。

十四、传值调用和传址调用

1. 传址调⽤,可以让函数和主调函数之间建⽴真正的联系,在被调函数内部可以通过对指针的解引用来修改主调函数中的变量。

2. 总之,所以未来函数中只是需要主调函数中的变量值来实现计算,采⽤传值调⽤;如果需要在被调函数内部要修改主调函数中的变量的值,就采用传址调⽤。 

 

十五、strlen函数的模拟实现 

    本篇文章已完结,谢谢支持!!!

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

【算法学习】线段树基础版

一 线段树 1.概念 线段树可以理解为一个二叉树&#xff0c;如果是利用线段树求区间的和&#xff0c;那么每个结点的权值维护的是结点所维护区间的和&#xff0c;再将该区间一分为二&#xff0c;分别交由左右儿子维护。 拿区间1 - 4的和来举例子&#xff0c; 根结点维护的是区…

开发简易复用 SDK(项目加分项)

文章目录 开发 SDK新建项目修改pom文件删除启动类创建配置类复制之前的客户端新建spring.factories打包 开发 SDK 为什么要开发SDK。 减少代码的冗余提高代码的复用 如果实际项目中需要使用到该SDK&#xff0c;在pom.xml中注入就可以了。 类似于maven一样&#xff0c;把需要…

ctfshow——XSS

文章目录 XSS介绍什么是xss&#xff1f;XSS危害XSS的分类常用XSSpayload web316——反射型XSSweb317——过滤<script> web318——过滤script、imgweb319——不止过滤script、imgweb320——过滤空格web321——不止过滤空格web322——不止过滤空格web323web324web 325web32…

618买什么最划算?618买什么东西便宜?必备数码好物清单分享

​只不&#xff0c;马上又到了618购物节咯&#xff0c;数码产品的优惠力度尤为显著&#xff0c;是购买数码产品的绝佳时机。接下来&#xff0c;我将为大家分享几款性价比超高的数码产品&#xff0c;相信总有一款能吸引你的目光。 一、南卡OE MIX开放式蓝牙耳机 在618购物狂欢节…

深兰科技入选2024全国“人工智能+”行动创新案例TOP100

近日&#xff0c;中科院《互联网周刊》联合eNET研究院、德本咨询、中国社会科学院信息化研究中心共同发布了《2024全国“人工智能”行动创新案例TOP100》榜单。经评委会层层遴选&#xff0c;深兰科技专为洛阳市打造的“工业智能化洛阳中心”项目成功入围该榜单。一同入围的还包…

IP-guard getdatarecord 存在任意文件读取

声明 本文仅用于技术交流&#xff0c;请勿用于非法用途 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;文章作者不为此承担任何责任。 一、产品介绍 IP-guard是由溢信科技股份有限公司开发的一款终端安全管…

案例:SpringBoot集成Sharding-JDBC实现分表分库与主从同步(详细版)

案例&#xff1a;SpringBoot集成Sharding-JDBC实现分表分库与主从同步&#xff1a;详细版 1. 案例分析2. 主从同步2.1 主从数据库准备2.2 简单插点数据 3 案例代码3.1 application.properties配置信息3.2 测试 4. 遇到的坑4.1 水平分表时的属性设置4.2 绑定表的配置 1. 案例分析…

边缘计算是什么?

一、边缘计算是什么&#xff1f; 边缘计算是一种分布式计算范式&#xff0c;它将计算任务和数据存储从中心化的云端推向网络的边缘&#xff0c;即设备或终端&#xff0c;以提高响应速度和降低网络带宽需求。在边缘计算中&#xff0c;数据在源头附近进行处理和分析&#x…

Sectigo证书申请流程及价格介绍

Sectigo 是一家全球知名的数字证书颁发机构&#xff08;Certificate Authority, CA&#xff09;&#xff0c;自1998年起就开始提供 SSL 证书服务&#xff0c;是全球最早的 CA 机构之一。 一 Sectigo证书申请流程 1 确定证书类型 根据自身的需求确定证书的类型&#xff0c;一…

ArrayList 和LinkedList

目录 ArrayListadd自动扩容ArrayList的remove()方法查找 indexof LinkedListLinkedList的add方法LinkedList的remove方法查找 indexof arraylist和linkedlist的区别 ArrayList ArrayList 的底层是数组队列&#xff0c;相当于动态数组。与 Java 中的数组相比&#xff0c;它的容…

政企单位内外网数据交互,如何保障安全性和合规性?

政府内外网隔离是一种网络安全措施&#xff0c;旨在保护政府内部网络的安全性和保密性。根据国家法律要求&#xff0c;涉及国家秘密的计算机信息系统与公共网络之间必须实行物理隔离。这意味着这些系统应该被完全隔离开来&#xff0c;以防止任何未经授权的访问或数据泄露。其次…

hyperf 三十一 极简DB组件

一 安装及配置 composer require hyperf/db php bin/hyperf.php vendor:publish hyperf/db 默认配置 config/autoload/db.php 如下&#xff0c;数据库支持多库配置&#xff0c;默认为 default。 配置项类型默认值备注driverstring无数据库引擎 支持 pdo 和 mysqlhoststringl…

投票刷礼物链接怎么弄?最新投票活动创建系统源码 轻松创建活动

投票刷礼物链接怎么弄&#xff1f;投票活动创建系统的作用和功能多种多样&#xff0c;为用户提供一个便捷、高效且功能强大的平台&#xff0c;用于创建、管理和执行各种投票活动。分享一个最新投票活动创建系统源码&#xff0c;源码开源可二开&#xff0c;含完整代码包和详细搭…

探索人工智能的边界:GPT 4.0与文心一言 4.0免费使用体验全揭秘!

探索人工智能的边界:GPT与文心一言免费试用体验全揭秘! 前言免费使用文心一言4.0的方法官方入口进入存在的问题免费使用文心一言4.0的方法免费使用GPT4.0的方法官方入口进入存在的问题免费使用GPT4.0的方法前言 未来已来,人工智能已经可以帮助人们完成许多工作了,不少工作…

自动批量将阿里云盘文件发布成WordPress文章脚本源码(以RiPro主题为例含付费信息下载地址SEO等自动设置)源码

背景 很多资源下载站&#xff0c;付费资源下载站&#xff0c;付费内容查看等都可以用WordPress站点发布内容&#xff0c;这些站点一般会基于一个主题&#xff0c;付费信息作为文章附属的信息发布&#xff0c;底层存储在WP表里&#xff0c;比如日主题&#xff0c;子比主题等。 …

凌恩病原微生物检测系统上线啦,助力环境病原微生物检测

病原微生物是指能够引起人类或动物疾病的微生物&#xff0c;包括病毒、细菌、真菌、衣原体和支原体等。病原微生物可以通过空气、体液等介质传播&#xff0c;危害人体健康&#xff0c;造成财产损失。因此&#xff0c;快速、准确地检测病原微生物对于疫情防控和保障人民生命健康…

Android SDK Manager安装Google Play Intel x86 Atom_64 System Image依赖问题

Package Google Play Intel x86 Atom_64 System Image,Android API R, revision 2 depends on SDK Platform Android R Preview, revision 2 问题 一开始以为网络还有依赖包没有勾选&#xff0c;尝试了很多次&#xff0c;勾选这边报错对应的license即可。此时点击一下其他licen…

Redis事务全解析:从MULTI到EXEC的操作指南!

【更多精彩内容,欢迎关注小米的微信公众号“软件求生”】 亲爱的粉丝朋友们,大家好!今天我们要讨论的主题是Redis的事务。Redis作为一款优秀的NoSQL数据库,凭借其高性能和灵活性广受欢迎。事务是Redis的一项关键功能,它为我们提供了一种在数据操作中确保一致性的机制。接…

atlas 500容器(ubuntu20.04)搭建

1.docker 及环境搭建略 2.宿主机驱动安装略 3.宿主机中能正确使用npu-smi 4.docker 拉取略 5.docker 容器启动 docker run -itd --device/dev/davinci0 --device/dev/davinci_manager --device/dev/devmm_svm --device/dev/hisi_hdc -v /run/board_cfg.ini:/run/b…

博士困境::博士毕业出路何在

::: block-1 “时问桫椤”是一个致力于为本科生到研究生教育阶段提供帮助的不太正式的公众号。我们旨在在大家感到困惑、痛苦或面临困难时伸出援手。通过总结广大研究生的经验&#xff0c;帮助大家尽早适应研究生生活&#xff0c;尽快了解科研的本质。祝一切顺利&#xff01;—…