《C语言深度解剖》(9):深度剖析数据在内存中的存储

news2024/12/23 4:29:41

🤡博客主页:醉竺

🥰本文专栏:《C语言深度解剖》

😻欢迎关注:感谢大家的点赞评论+关注,祝您学有所成!


✨✨💜💛想要学习更多数据结构与算法点击专栏链接查看💛💜✨✨ 


1. 数据类型介绍

前面我们已经学习了基本的内置类型:

char        //字符数据类型
short       //短整型
int         //整形
long        //长整型
long long   //更长的整形
float       //单精度浮点数
double      //双精度浮点数
//C语言有没有字符串类型?

以及他们所占存储空间的大小。

类型的意义:

1. 使用这个类型开辟内存空间的大小(大小决定了使用范围)。

2. 如何看待内存空间的视角。 

1.1 类型的基本归类

整形家族: 

char
    unsigned char
    signed char
short
    unsigned short[int]
    signed short[int]
int
    unsigned int
    signed int
long
    unsigned long[int]
    signed long[int]

字符在存储的时候存储的是ASCII码值,ASCII是整数,所以在归类的时候,字符属于整型家族 。

浮点数家族: 

float
double

构造类型:(自定义类型)

> 数组类型
> 结构体类型 struct
> 枚举类型 enum
> 联合类型 union

一个数组,把数组名去掉,剩下的就是这个数组的类型, 元素个数不一样,代表类型也不一样。

eg. int a[10] 和 int a[11]是不同的类型,第一个数组类型是int [10],第二个数组类型是int [11]. 所以说数组也是自定义类型。

指针类型 

int *pi;
char *pc;
float* pf;
void* pv;

C语言中所有“变量”的类型判断:把“变量”名去掉,剩下的就是该“变量”的类型。 

空类型: 

void 表示空类型(无类型)

通常应用于函数的返回类型、函数的参数、指针类型。

2. 整形在内存中的存储

我们之前讲过一个变量的创建是要在内存中开辟空间的。空间的大小是根据不同的类型而决定的。 

那接下来我们谈谈数据在所开辟内存中到底是如何存储的?

比如:

int a = 20;
int b = -10;

我们知道为 a 分配四个字节的空间。 那如何存储? 下来了解下面的概念: 

2.1 原码、反码、补码

计算机中的整数有三种2进制表示方法,即原码反码补码

三种表示方法均有符号位数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位

 正数的原、反、补码都相同。

负整数的三种表示方法各不相同。

原码

直接将数值按照正负数的形式翻译成二进制就可以得到原码。 

反码 

将原码的符号位不变,其他位依次按位取反就可以得到反码。

补码 

反码+1就得到补码。 

对于整形来说:数据存放内存中其实存放的是补码。 

为什么呢?

在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统 一处理;

同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。 

我们看看在内存中的存储:

我们可以看到对于a和b分别存储的是补码。

但是我们发现顺序有点不对劲。 这是又为什么? 

2.2 大小端介绍

什么大端小端: 

大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;

小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地址中。 

低位:指的是低权值位!

什么是数据的低位高位?

例如:十进制数:1356

1是数据的高位:千位 ;6是数据的低位:个位 

为什么有大端和小端: 

百度2015年系统工程师笔试题: 

请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。(10分)

有两种方法实现:

但是两种方法实现的本质是一样的:选择一个简单的数字(这里选择的是数字1),判断其第一个字节存储的是什么,如果是0就是大端存储模式,如果是1就代表是小端存储模式。 

//代码1
#include <stdio.h>
int check_sys()
{
	int i = 1;
	return (*(char*)&i);
}
int main()
{
	int ret = check_sys();
	if (ret == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;
}
//代码2
int check_sys()
{
	union
	{
		int i;
		char c;
	}un;
	un.i = 1;
	return un.c;
}

这里简单解释一下方法2为什么也可以实现,到后面深入学习到联合体的时候会进一步详细讲解,这里可以先掌握方法1.

  1. 定义一个联合体(union),联合体是一个特殊的数据类型,所有成员都从同一内存位置开始,所以同一时间只能存储其中一个成员的值。在这个联合体中,定义了两个成员:一个整数 int i; 和一个字符 char c;

  2. 将联合体 un 的整数成员 i 赋值为1。由于 int 类型通常大于 char 类型,如果系统是32位的话,int 将占用4个字节,这样整数1在内存中的表示(在小端字节序系统中)通常会是 01 00 00 00。也就是说,最低有效字节(最小的地址)存储了值1,而其他字节存储0。

  3. 由于联合体成员共享内存,char c; 将访问整数 i 第一个字节的内容。在小端系统中,由于1被存储在了最低位字节,char c 会读取到值1。在大端系统中,值1会被存储在最高位字节,而 char c 会读取到0。

  4. 函数返回 char c 的值。如果返回值为1,则系统为小端字节序。如果返回值为0,则系统为大端字节序。


2.3 练习(重难点)

  • C语言中的整数类型可以分为两种:有符号和无符号。
  • 有符号整数可以表示正数、负数和零, 而无符号整数仅能表示正数和零。
  • 无符号整数确实采用直接的二进制表示,所有的位都用于表示值,没有符号位。无符号整数不使用原码、反码和补码的概念,因为这些都是有符号整数的表示方法。
  • 在无符号整数中,所有的位,包括最高位,都是数值的一部分,没有一个位是用作符号位的。最高位的1或0并没有特殊的含义,它仅仅是数值的一部分,与其他位一样参与数值的表示。
  • 使用%u格式控制符打印无符号整数时,会直接以其十进制值输出非负整数。
  • 因此,使用%u打印无符号整数时,并不需要考虑原码、补码和反码的问题。以无符号形式打印的结果就是该无符号整数的真实值 。

a是char类型一个字节只能放8个比特位,所以截断了一些比特位,然后再整形提升。

下面程序输出什么?

 

有/无符号位数,是对存储在内存中数据的补码的一种看待(使用)方式!

同一个数字存储在内存中的二进制数字是一样的。

如果是以无符号位数的格式打印%u,那就把内存中数据的补码当成没有符号的数字使用(看待),直接打印出来这串二进制代表的十进制整数即可。

若是打印有符号位数%d,要把补码转换成原码所代表的十进制数字打印出来。

总之,存储内存中的数据是一样的,只不过以不同的方式来使用。 

这段代码看似是想循环打印256次"hello world",但实际上,它会导致一个无限循环,并且会无限地打印"hello world"。原因在于变量i的类型是unsigned char。

在C语言中,unsigned char的取值范围通常是0到255。当i增加到255并执行i++后,按照期望,i会变成256。但是,由于unsigned char的取值上限是255,所以当i尝试增加到256时,它实际上会溢出并回绕到0(这是无符号整数溢出时的正常行为),导致for循环的条件i <= 255始终为真。

这里补充一下char类型的取值范围

3. 浮点型在内存中的存储

常见的浮点数:

3.14159
1E10
浮点数家族包括: float、double、long double 类型。
浮点数表示的范围:float.h中定义

3.1 一个例子 

 浮点数存储的例子:

输出的结果是什么呢?

3.2 浮点数存储规则 

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

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

相关文章

ubuntu22.04 CH340/CH34x 驱动安装

CH34x驱动地址&#xff1a;CH341SER_LINUX.ZIP - 南京沁恒微电子股份有限公司 1、卸载旧驱动&#xff08;如果存在&#xff09; sudo rmmod ch341.ko 2、解压进入 driver 目录 unzip CH341SER_LINUX.ZIP cd CH341SER_LINUX/driver 3、编译 make 可能错误&#xff1a; make[1]…

Linux的学习之路:18、进程间通信(2)

摘要 本章主要是说一下命名管道和共享内存 目录 摘要 一、命名管道 1、创建一个命名管道 2、匿名管道与命名管道的区别 3、命名管道的打开规则 4、代码实现 二、system V共享内存 1、共享内存 2、共享内存函数 三、代码 四、思维导图 一、命名管道 1、创建一个命…

企业车辆管理系统平台是做什么的?

企业车辆管理系统平台是一种综合性的管理系统&#xff0c;它主要集车辆信息管理、车辆调度、车辆维修、油耗管理、驾驶员管理以及报表分析等多种功能于一体。通过这个平台&#xff0c;企业可以实现对车辆的全面管理&#xff0c;优化车辆使用效率&#xff0c;降低运营成本&#…

SpringAOP从入门到源码分析大全(四)SpringAOP的源码分析

文章目录 系列文档索引六、EnableAspectJAutoProxy源码分析1、AnnotationAwareAspectJAutoProxyCreator源码&#xff08;1&#xff09;wrapIfNecessary方法&#xff08;2&#xff09;createProxy 2、getAdvicesAndAdvisorsForBean查找所有Advisor&#xff08;1&#xff09;find…

进程概述与进程创建

进程概述 程序和进程是计算机科学中的基本概念&#xff0c;它们经常被提到&#xff0c;尤其是在操作系统的上下文中。这两个概念虽然紧密相关&#xff0c;但有明显的区别&#xff1a; 程序&#xff08;Program&#xff09; 程序是指存储在磁盘上的一组指令和数据&#xff0c…

【Vue3】$subscribe订阅与反应

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

STM32标准库编程与51单片机直接写寄存器的区别和联系

简介&#xff1a; 在学完51单片机之后&#xff0c;我们去学习32的时候&#xff0c;会发现编程的方法有很大的区别&#xff0c;让人非常的不适应&#xff0c;但是通过不断的调用相应外设的库函数之后&#xff0c;你也可以去编程STM32&#xff0c;来实现功能&#xff0c;但是你真…

nodejs版本过高导致vue-cli无法启动的解决方案

目录 前言异常现象解决方案总结 前言 之前使用软件管家升级了Nodejs&#xff0c;今天在运行Vue项目的时候老是报错&#xff0c;查了很多资料&#xff0c;最后确定是Nodejs版本过高导致的。 异常现象 E:\project\ry\RuoYi-Cloud\ruoyi-ui>npm run dev> ruoyi3.6.4 dev …

Attention和Transformer灵魂七问

1. 引言 最近&#xff0c;ChatGPT和其他聊天机器人将大语言模型LLMs推到了风口浪尖。这就导致了很多不是学ML和NLP领域的人关注并学习attention和Transformer模型。在本文中&#xff0c;我们将针对Transformer模型结构提出几个问题&#xff0c;并深入探讨其背后的技术理论。这…

实验2 组合逻辑电路与时序逻辑电路设计

实验目的: 1.构建基于verilog语言的组合逻辑电路和时序逻辑电路; 2.掌握verilog语言的电路设计技巧。 3.完成如下功能:加法器、译码器、多路选择器、计数器、移位寄存器等。 实验内容及步骤: 一、实验原理 原理图文件《数字系统设计_sch.pdf》,找到如下两个部分: 图…

Vim编辑器的安装及使用教程

文章目录 1&#xff1a;Ubuntu安装Vim1.1&#xff1a;图形界面安装1.2&#xff1a;命令行安装vim1.3&#xff1a;判断vim是否安装成功 2&#xff1a;vim简介3&#xff1a;vim的三种模式4&#xff1a;vim常用按键说明4.1 命令模式4.2 搜索和替换4.3 复制、粘贴和删除4.4 一般模式…

网络工程师---第十天

ARP表&#xff1a; 提起ARP表必然先想起ARP&#xff08;address resolution protocol&#xff09;协议&#xff0c;地址解析协议。 在实际应用中&#xff0c;我们经常遇到这样的问题&#xff1a;已知一个机器的IP地址&#xff0c;但在实际网络的链路上传送数据帧时&#xff0c;…

20240331-1-基于深度学习的模型

基于深度学习的模型 知识体系 主要包括深度学习相关的特征抽取模型&#xff0c;包括卷积网络、循环网络、注意力机制、预训练模型等。 CNN TextCNN 是 CNN 的 NLP 版本&#xff0c;来自 Kim 的 [1408.5882] Convolutional Neural Networks for Sentence Classification 结…

[ICCV2023]DIR-用于从单个RGB图像重建交互手部的解耦迭代细化框架

这篇论文的标题是《Decoupled Iterative Refinement Framework for Interacting Hands Reconstruction from a Single RGB Image》&#xff0c;作者是Pengfei Ren, Chao Wen, Xiaozheng Zheng, Zhou Xue, Haifeng Sun, Qi Qi, Jingyu Wang, Jianxin Liao。他们来自北京邮电大学…

Nodejs安装与配置--基于Linux系统--RedHat7.9

nodejs安装从未这么简单 1、nodejs版本设置&#xff1f; curl -fsSL https://rpm.nodesource.com/setup_16.x | sudo bash - 其他版本如下&#xff1a; * https://rpm.nodesource.com/setup_16.x — Node.js 16 "Gallium" (deprecated) * https://rpm.nodesource.co…

vue-project-tree vue3 树形结构展示组件

GitHub&#xff1a;vue-project-tree by one-ccs Gitee&#xff1a;vue-project-tree by one-ccs 遵循 MIT 开源协议 文章目录 vue-project-tree一、使用二、API1、属性2、事件3、方法4、插槽 vue-project-tree 使用 Vue3 TS 实现的树形结构展示组件&#xff0c;有拖拽、排序…

数字化革新:可视化墨水屏引领基板工艺MSAP贴膜阶段迈向无纸化高端制造应用背景

随着科技的飞速发展和环境保护意识的日益增强&#xff0c;制造印刷电路板&#xff08;PCB&#xff09;行业正面临着提升生产效率、降低资源消耗和推动绿色制造的迫切需求。 问题&#xff1a; PCB生产过程对洁净度要求高&#xff0c;传统打印的纸张会有粉尘&#xff0c;纸屑&am…

cookie与session区别和联系

在Web应用中&#xff0c;HTTP协议是无状态的&#xff0c;每次请求都是独立的&#xff0c;服务器无法直接识别一个用户的不同请求之间的关联。这就导致了如果我们希望在一个会话中保持一些数据的状态&#xff0c;比如用户的身份认证信息、购物车内容等&#xff0c;就需要借助Coo…

网络靶场实战-Qiling Fuzz实例分析

背景 在上一小节中&#xff0c;介绍了qiling框架的背景和基础使用&#xff0c;并以相关的CTF和qilinglab实例进行练习加深对qiling框架的使用&#xff0c;后续并简单介绍了qiling fuzz的功能。 在这一小节&#xff0c;我们将对qiling fuzz iot设备进行测试以及以实例的方式对…

【LLM】LLM API 开发

文章目录 LLM API 开发LLM入门基本概念LLM API使用实名认证创建应用使用API Prompt Engineering思考总结 参考文章 什么是提示工程&#xff08;Prompt Engineering&#xff09;&#xff1f; ChatGPT Prompt 最佳指南一 LLM API 开发 LLM入门基本概念 Prompt Prompt 最初是 NL…