肯尼斯·里科《C和指针》第6章 指针(1)

作为补充资料来学习吧。

6.1 内存和地址

前面提到,我们可以把计算机的内存看作一条长街上的一排房屋。每座房子都可以容纳数据,并通过一个房号来标识。这个比喻颇为有用,但也存在局限性。计算机的内存由数以亿万计的位(bit)组成,每个位可以容纳值0或1。由于一个位所能表示的值的范围太有限,因此单独的位用处不大,通常将许多位合成一组作为一个单位,这样就可以存储范围较大的值。下图展示了现实机器中的一些内存位置

这些位置的每一个都被称为字节(byte),每个字节都包含了存储一个字符所需要的位数。在许多现代的机器上,每个字节包含8个位,可以存储无符号值0~255,或有符号值-128~127。上图并没有显示这些位置的内容,但内存中的每个位置总是包含一些值。每个字节通过地址来标识,如上图方框上面的数字所示。

为了存储更大的值,我们把两个或更多个字节合在一起作为一个更大的内存单位。例如,许多机器以字为单位存储整数,每个字一般由2字节或4字节组成。下图所表示的内存位置与上图相同,但这次它以4字节的字来表示。

注意,尽管一个字包含了4字节,但它仍然只有一个地址。至于它的地址是它最左边那个字节的位置还是最右边那个字节的位置,不同的机器有不同的规定。另一个需要注意的硬件事项是边界对齐(boundary alignment)。在要求边界对齐的机器上,整型值存储的起始位置只能是某些特定的字节,通常是2或4的倍数。但这些问题是硬件设计者的事情,很少影响C程序员。我们只对两件事情感兴趣:

1.内存中的每个位置由一个独一无二的地址标识;

2.内存中的每个位置都包含一个值。

批注:反正我在学校学是没有理解到这样的程度(当然主要也是因为我是蒟蒻) 。

这里显示了5个整数,每个都位于自己的字中。如果你记住了一个值的存储地址,以后就可以根据这个地址取得这个值。但是,通过记住所有这些地址来访问内存位置实在是太笨拙了,所以高级语言所提供的特性之一就是通过名字而不是地址来访问内存位置。下图与上图相同,但这次使用名字来代替地址。

当然,这些名字就是我们所称的变量。有一点非常重要,你必须记住,即名字与内存位置之间的关联并不是硬件来提供的,而是由编译器为我们实现的。所有这些变量给了我们一种更方便的方法记住地址——硬件仍然通过地址访问内存位置。

6.2 值和类型

现在看一下存储于这些位置的值。头两个位置所存储的是整数,第3个位置所存储的是一个非常大的整数,第4个和第5个位置所存储的也是整数。下面是这些变量的声明:

 在这些声明中,变量a和b确实用于存储整型值,但是又声明c所存储的是浮点值。可是,在上图中c的值却是一个整数。那么到底它应该是哪个呢?整数还是浮点数?答案是该变量包含了一序列内容为0或者1的位。它们可以被解释为整数,也可以被解释为浮点数,这取决于它们的使用方式。如果使用的是整型算术指令,这个值就被解释为整数;如果使用的是浮点型指令,这个值就被解释为浮点数。这个事实引出了一个重要的结论:不能简单地通过检查一个值的位来判断它的类型。

……

编译器会帮助我们避免这些错误。如果把c声明为float型变量,那么当程序访问它时,编译器就会产生浮点型指令。如果以某种对float类型而言不适当的方式访问该变量,编译器就会发出错误或警告信息。

这里给我的启发就是,当我们如上所示声明各种变量时,在内存里是怎样的。但是和我学习的时候还是有些出入的地方,比如说理解a=112,我学习的时候是先把a放到一个小格里面,然后把112赋给它,类似于int a,然后再让a = 112。但不管怎样&a就是a存储的位置。

6.3&4 指针变量的内容

a的值是112,b的值是-1,c的值是3.14。指针变量其实也很容易,d的值是100,e的值是108。如果你认为d和e的值分别是112和3.14,就犯了一个极为常见的错误。d和e被声明为指针并不会改变这些表达式的求值方式:一个变量的值就是分配给这个变量的内存位置所存储的数值。如果简单地认为由于d和e是指针,因此它们可以自动获得存储于位置100和108的值,就错了。变量的值就是分配给该变量的内存位置所存储的数值,即使是指针变量也不例外。

6.5 未初始化和非法的指针

这个声明创建了一个名叫a的指针变量,后面那条赋值语句把12存储在a所指向的内存位置。

但是究竟a指向哪里呢?我们声明了这个变量,但从未对它进行初始化,所以没有办法预测12这个值将存储于什么地方。从这一点看,指针变量和其他变量并无区别。如果变量是静态的,它会被初始化为0;如果变量是自动的,它根本不会被初始化。无论是哪种情况,声明一个指向整型的指针都不会“创建”用于存储整型值的内存空间。

所以,如果程序执行这个赋值操作,会发生什么情况呢?如果运气好,a的初始值会是个非法地址,这样赋值语句将会出错,从而终止程序。在UNIX系统上,这个错误被称为“段违例”(segmentation violation)或“内存错误”(memory fault)。它提示程序试图访问一个并未分配给程序的内存位置。在一台运行Windows的PC上,对未初始化或非法指针进行间接的访问操作是一般保护性异常(general protection exception)的根源之一。

对于那些要求整数必须存储于特定边界的机器而言,如果这种类型的数据在内存中的存储地址处于错误的边界上,那么对这个地址进行访问时将会产生一个错误。这种错误在UNIX系统中被称为“总线错误”(bus error)。

一种更为严重的情况是,这个指针偶尔可能包含了一个合法的地址。接下来的事很简单:位于那个位置的值被修改,虽然你并无意去修改它。像这种类型的错误非常难以捕捉,因为引发错误的代码可能与原先用于操作那个值的代码完全不相干。所以,在对指针进行间接访问之前,必须非常小心,确保它们已被初始化!

批注:原来自己写的“segmentation violation”是因为这个(捂脸)。

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

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

相关文章

[Android] Android架构体系(2)

文章目录 Bionic精简对系统调用的支持:不支持 System V IPC:有限的 Pthread 功能:有限支持C:不再支持本地化和/或宽字符:Bionic新增的特性系统属性硬编码写死的UID/GID内置了DNS解析硬编码写死的服务和协议 硬件抽象层Linux内核匿名共享内存(ASHMem)Binder-BinderLoggerION 内存…

【经典算法】有趣的算法之---粒子群算法梳理

every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 粒子群算法 粒子群算法(Particle Swarm Optimization,PSO)是一种用于解决优化问题的元启发式算法。它通过模拟鸟群或…

什么是车载信息娱乐系统和集成驾驶舱

什么是车载信息娱乐系统(IVI)? “车载信息娱乐(IVI)”通过向驾驶员和乘客提供信息和娱乐,为驾驶提供便利和舒适。为了理解这个概念,有必要知道“信息娱乐”的含义。“信息娱乐”是这个市场中使用的一个词,它结合了“信息”和“娱乐”两个词…

编译FFmpeg4.3.1 、x264并移植到Android

1、前言 FFmpeg 既是一款音视频编解码工具,同时也是一组音视频编解码开发套件。 2、准备工作 系统:LinuxNDK:android-ndk-r21b-linux-x86_64.zipFFmpeg:ffmpeg-snapshot.tar.bz2x264:x264 3、下载NDK 在linux环境中…

存内计算技术打破常规算力局限性

说明: 本文撰写人:三掌柜666 由三掌柜666原创首发:https://blog.csdn.net/CC1991_/article/details/135623056 文章目录 前言关于存内计算1、常规算力局限性2、存内计算诞生记3、存内计算核心 存内计算芯片研发历程及商业化1、存内计算芯片研…

Unix时间戳

时间戳,相信很多相关专业的人,计算机软件电子等等都会听过。由于最早是由Unix系统使用所以又叫Unix时间戳。 Unix 时间戳(Unix Timestamp)定义为从UTC(世界协调时)/GMT(格林尼治时)…

【Java】SpringBoot快速整合Redis

什么是Redis? 文末有源码gitee地址 【面试】浅学Redis_redis 广播-CSDN博客 Redis是一种高性能开源的基于内存的,采用键值对存储的非关系型数据库,它支持多种数据结构,包括字符串、哈希表、列表、集合、有序集合等。Redis的特点之…

机器学习--Matplotlib

机器学习–Matplotlib Matplotlib 是专门用于开发2D图表(包括3D图表)以渐进、交互式方式实现数据可视化 简单的Matplotlib画图 — 以折线图为例 matplotlib.pyplot模块 matplotlib.pytplot包含了一系列类似于matlab的画图函数。 import matplotlib.pyplot as plt图形绘制流…

STM32入门教程-2023版【4-1】OLED调试工具

关注 点赞 不错过精彩内容 大家好,我是硬核王同学,最近在做免费的嵌入式知识分享,帮助对嵌入式感兴趣的同学学习嵌入式、做项目、找工作! 一、概述 在这一节先提前介绍一下,在以后的教程中我们会经常用到这个显示屏&#xff0…

HCIA的访问控制列表ACL

ACL -----access control-list 允许/拒绝 ACL作用: 1.实现访问控制 2.定义感兴趣流量 ACL分类: 标准ACL 2000-2999(只关注源IP地址,使用时应该尽量靠近目标) 扩展ACL 3000-3999:写ACL不能写在源上&…

Java基础知识整理,注释、关键字、运算符

写在开头 万丈高楼平地起,要想学好汉语首先学拼音,想学好英语首先学26个字母,对于编程语言来说,一样的道理,要想学好必须先掌握其基础语法和知识,今天我们就来唠一唠Java语言中那些出现频率极高&#xff0…

Linux:shell脚本:基础使用(8)《函数局部|全局变量函数传入位置变量return》

基本的函数定义 把一些重复调用的命令写进一个函数里,下次直接调用函数名,这样的既方便修改,又可以让思路清晰 function 函数名(){ 当调用这个函数时候执行的命令...... } 这个是一个基础的函数定义,当然你不加function也是可以的…