【C语言】深剖数据在内存中的存储

在这里插入图片描述

👦个人主页:Weraphael
✍🏻作者简介:目前正在回炉重造C语言(2023暑假)
✈️专栏:【C语言航路】
🐋 希望大家多多支持,咱一起进步!😁
如果文章对你有帮助的话
欢迎 评论💬 点赞👍🏻 收藏 📂 加关注😍


目录

  • 一、数据类型介绍
      • 1.1 基本的内置类型
      • 1.2 类型的基本归类
  • 二、整型在内存中的存储
      • 2.1 原码、反码、补码
      • 2.2 探讨:为什么整型内存中存的是补码,而不是反码和原码?
  • 三、 大小端介绍
      • 3.1 经典大小端面试题
  • 四、练习
      • 4.1 例1
      • 4.2 例2
      • 4.3 例3
      • 4.4 例4
      • 4.5 例5
      • 4.6 例6
      • 4.7 例7
      • 4.8 例8
  • 五、浮点数在内存中的存储
      • 5.1 浮点数存储规则
      • 5.2 浮点数存储模型
      • 5.3 特别规定
      • 5.4 浮点数存储的例题
        • 5.4.1 例1
        • 5.4.2 例2

一、数据类型介绍

1.1 基本的内置类型

char       //字符数据类型
short      //短整型
int        //整型
long       //长整型
long long   //更长的整型
float      //单进度浮点型
double     //双精度浮点型

类型的意义:

  1. 使用这个类型开辟内存空间的大小(大小决定了其使用范围)
  2. 看待内存空间的视角

1.2 类型的基本归类

  • 整型家族
char
    unsigned char
    signed char

//后面带括号的可省略
short
    unsigned short (int)   
    signed short (int)

int
    unsigned int
    signed int

long
    unsigned long (int)
    signed long (int)

long long
    unsigned long long (int)
    signed long long (int)
  • char属于整型并不奇怪,因为字符在存储的时候在内存存储的是ASCII值,因为ASCII是整数,所以在归类的时候,字符就属于整型家族。
  • 不管是long long / long / short / int + 变量都等价于signed long long / long /short /int + 变量,但注意:char到底是signed char还是unsigned char完全取决于编译器,常见的char是有符号的
  • 浮点数家族:
float
double
  • 构造类型(又称自定义类型):
数组类型  int[]char[]...
结构体类型 struct
枚举类型 enum
联合类型 union
  • 指针类型
int *p;
char *p;
float* p;
void* p;  //无具体类型的指针
  • 空类型
void 表示空类型(无类型)

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

二、整型在内存中的存储

我们之前讲过一个变量的创建是要在内存中开辟空间的。空间的大小是根据不同的类型而决定的。那么数据在所开辟的内存空间中到底是如何存储的?

比如:

int a = 20
int b = -10;

我们知道int需要开辟4个字节的空间,那么这4个字节的空间到底该如何使用呢?要知道这些首先必须知道什么是原码、反码、补码

2.1 原码、反码、补码

在这里插入图片描述

我们再回头讨论整型在所开辟的空间中到底是如何存储的?

对于整形来说:数据在内存中存储的是二进制序列的补码。

#include <stdio.h>
int main()
{
	int a = 20;
	//整数的原码、反码、补码相同
	//原码:00000000 00000000 00000000 00010100
	//反码:00000000 00000000 00000000 00010100
	//补码:00000000 00000000 00000000 00010100
	
    int b = -10;
	//原码:10000000 00000000 00000000 00001010
	//反码:11111111 11111111 11111111 11110101 //符号位不变,其他位取反
	//补码:11111111 11111111 11111111 11110110 //反码+1

	return 0;
}

接着我们可以通过调试分别查看变量a的内存和变量b的内存:

在这里插入图片描述

我们发现它们是按十六进制数存储的,这是因为如果是二进制的话,显得过于太长了

接下来分别写出a和b的十六进制,我们发现它们是倒着存放的(后面大小端介绍为什么是倒着放):

#include <stdio.h>
int main()
{
	int a = 20;
	//整数的原码、反码、补码相同
	//原码:00000000 00000000 00000000 00010100
	//反码:00000000 00000000 00000000 00010100
	//补码:00000000 00000000 00000000 00010100
    //十六进制:00     00        00       14
	
    int b = -10;
	//原码:10000000 00000000 00000000 00001010
	//反码:11111111 11111111 11111111 11110101 //符号位不变,其他位取反
	//补码:11111111 11111111 11111111 11110110 //反码+1
    //十六进制:ff     ff        ff       f6
	return 0;
}

2.2 探讨:为什么整型内存中存的是补码,而不是反码和原码?

在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。

这里可以举个例子帮助大家理解:

在这里插入图片描述

三、 大小端介绍

  • 大端:又称大端字节序存储,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中。
  • 小端:又称小端字节序存储,是指数据的低位保存在内存的低地址中,而数据的高位,保存在内存的高地址中。

文字有点干巴,我画图来帮助大家理解:

假设有一个十六进制位:0x 00 11 22 33 44,怎么知道数据的低位和高位呢?举个例子123,个位数的3就是低位,1就是高位,在上面的数据中,44就是低位,00就是高位。

【小端模式 - x86环境】

在这里插入图片描述

【大端模式 - x64环境】

在这里插入图片描述

3.1 经典大小端面试题

问:如何设计一个程序去判断当前的系统是大端还是小端呢?(请用编程实现)

思路:这里我们只要拿1就非常好判断,因为1的十六进制为0x00 00 00 01,在小端的存储模式是0x 01 00 00 00,大端则是0x 00 00 00 01,所以只需要判断第一个字节即可,是1就是小端,是0就是大端。

【代码实现】

#include <stdio.h>
int main()
{
	int a = 1;
	// char类型的指针一次只访问一个字节
	char* p = (char*)&a;
	if (*p == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;
}

四、练习

4.1 例1

#include <stdio.h>
int main()
{
	char a = -1;
	signed char b = -1;
	unsigned char c = -1;
	printf("a = %d, b = %d, c = %d", a, b, c);
	
	return 0;
}

【解析】

在这里插入图片描述

整型提升:点击跳转

4.2 例2

#include <stdio.h>
int main()
{
	char a = -128;
	printf("%u\n", a);
	return 0;
}

【解析】

在这里插入图片描述

4.3 例3

#include <stdio.h>
int main()
{
	char a = 128;
	printf("%u\n", a);
	return 0;
}

【解析】

在这里插入图片描述

4.4 例4

#include <stdio.h>
int main()
{
	char a = 128;
	printf("%u\n", a);
	return 0;
}

【解析】

在这里插入图片描述

4.5 例5

#include <stdio.h>
int main()
{
	int i = -20;
	unsigned int j = 10;

	printf("%d\n", i + j);
	return 0;
}

【解析】

在这里插入图片描述

4.6 例6

#include <stdio.h>
int main()
{
	unsigned int i;
	for (int i = 9; i >= 0; i--)
	{
		printf("%u\n", i);
	}
	return 0;
}

【解析】

i的类型是unsigned int,是无符号整型,说明i不可能为负数,因此以上代码发生死循环。

4.7 例7

#include <stdio.h>
#include <string.h>
int main()
{
	char a[1000];
	for (int i = 0; i < 1000; i++)
	{
		a[i] = -1 - i;
	}
	printf("%d", strlen(a));
	return 0;
}

【解析】

strlen只需计算'\0'之前的所有字符,所以只需要找到'\0'即可,其本质就是0。注意:有符号的char的取值范围:-128~127。则-1、-2、-3...-128、127、126、125...1、0。因此一共有127 + 128 = 225
在这里插入图片描述

4.8 例8

#include <stdio.h>
unsigned char i = 0;
//0~255
int main()
{
	for (i = 0; i <= 255; i++)
	{
		printf("hello world\n");
	}
	return 0;
}

i的类型是无符号char,因此范围:i的范围是0~255,永远都不可能超过225。所以循环里的内容恒成立,所以结果为死循环。

五、浮点数在内存中的存储

5.1 浮点数存储规则

注意:整型和浮点数在内存中的存储是截然不同的!

浮点数在计算机内部的表示方法:
任意一个二进制浮点数可以表示成下面的形式:(-1)S * M * 2E

  • (-1)S表示符号位,当S = 0,浮点数为正数;当S = 1,浮点数为负数。
  • M表示有效数字,其范围:大于等于1,小于2。
  • 2E表示指数位

举个例子来说:

十进制的5.0,写成二进制是101.0,就相当1.01×2²。那么,按照上面的格式,就可以得出S = 0(浮点数为正数),M = 1.01E = 2。

有了S、M、E,那浮点数在内存中又怎么表示呢?

5.2 浮点数存储模型

IEEE 754规定:

  • 对于32位的浮点数,最高的1位是符号位S,接着的8位是指数E,剩下的23位为有效数字M
    在这里插入图片描述
  • 对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M
    在这里插入图片描述

5.3 特别规定

注意:对于有效数字M和指数E,还有一些特别规定:

  • 前面说过,1≤M<2,也就是说,M可以写成1.xxxxxx的形式,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。也就是说,浮点数存入内存时1.xxxxxx中的1可以省略。比如保存1.01的时候,只保存01,剩下位补0。最后等到读取的时候,再把第一位的1加上去
  • 对于E,规定:存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。比如,210E10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001等到读取的时候再减去对应的中间数。

然后,指数E从内存中==取出==还可以再分成三种情况:

  • E不全为0或不全为1
    规定:指数E的计算值减去对应的中间值(127或1023),得到真实值,再将有效数字M前加上第一位的1
    比如:
    0.5的二进制形式为0.1,由于规定正数部分必须为1,即将小数点右移1位,则为
    1.0 × 2-1,其阶码为-1+127=126,表示为01111110,而尾数1.0去掉整数部分为0,补齐0到23位00000000000000000000000,则其二进制表示形式为:00111111000000000000000000000000
  • E全为0
    这时,浮点数的指数E等于1-127(或者1-1023)即为真实值,有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。
  • E全为1
    这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s)

5.4 浮点数存储的例题

5.4.1 例1

#include <stdio.h>
int main()
{
	float f = 5.5f;

	return 0;
}

【图解】

在这里插入图片描述

5.4.2 例2

#include <stdio.h>
int main()
{
	int n = 9;
	float* p = (float*)&n;
	printf("n的值为:%d\n", n);
	printf("*p的值为:%f\n", *p);

	*p = 9.0;
	printf("num的值为:%d\n", n);
	printf("*p的值为:%f\n", *p);

	return 0;
}

【程序结果】

在这里插入图片描述

【图解】

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

酷开科技大屏营销,撬动营销新增量

5G、人工智能、元宇宙等技术的发展促使数字营销的内容、渠道、传播方式发生了一系列变化&#xff1b;存量竞争下&#xff0c;增长成为企业更加迫切、更具挑战的课题&#xff0c;品牌营销活动越来越围绕“生意增长”和“提效转化”的目标展开。 如今的市场环境下&#xff0c;产…

Nacos(服务注册与发现)+SpringBoot+openFeign项目集成

&#x1f4dd; 学技术、更要掌握学习的方法&#xff0c;一起学习&#xff0c;让进步发生 &#x1f469;&#x1f3fb; 作者&#xff1a;一只IT攻城狮 &#xff0c;关注我&#xff0c;不迷路 。 &#x1f490;学习建议&#xff1a;1、养成习惯&#xff0c;学习java的任何一个技术…

基础语言模型LLaMA

LLaMA包含从7B到65B参数的基础语言模型集合。Meta在数万亿个tokens上训练了模型&#xff0c;LLaMA-13B在大多数基准测试中优于GPT-3&#xff08;175B&#xff09;。 来自&#xff1a;LLaMA: Open and Efficient Foundation Language Models 目录 背景概述方法预训练数据架构Op…

openGauss学习笔记-09 openGauss 简单数据管理-创建数据库

文章目录 openGauss学习笔记-09 openGauss 简单数据管理-创建数据库9.1 语法格式9.2 参数说明9.3 示例 openGauss学习笔记-09 openGauss 简单数据管理-创建数据库 数据库安装完成后&#xff0c;默认生成名称为postgres的数据库。您需要自己创建一个新的数据库。 9.1 语法格式…

Appium+python自动化(十一)- 元素定位- 下卷超详解)

1、 List定位 List故名思义就是一个列表&#xff0c;在python里面也有list这一个说法&#xff0c;如果你不是很理解什么是list&#xff0c;这里暂且理解为一个数组或者说一个集合。首先一个list是一个集合&#xff0c;那么他的个数也就成了不确定性&#xff0c;所以这里需要用复…

C\C++ 使用exception类,抛出自定义异常并捕获

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan 简介&#xff1a; 抛出异常&#xff0c;并捕获 exception 效果&#xff1a; 代码&#xff1a; #include <iostream> #include <exception> #include <stdexcept&g…

C# OpenCvSharp+DlibDotNet 人脸替换 换脸

效果 Demo下载 项目 VS2022.net4.8OpenCvSharp4DlibDotNet 相关介绍参考 代码 using DlibDotNet; using OpenCvSharp.Extensions; using OpenCvSharp; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Dra…

和为 K 的子数组——前缀和+哈希

题目链接&#xff1a;力扣 注意&#xff1a;此题不能使用滑动窗口&#xff0c;因为数组中可能会出现负数。也就是说右指针向后移1位不能保证区间会增大&#xff0c;左指针向后移1位也不能保证区间和会减小。给定左右指针的位置没有二段性 已知sum[i]是从nums[0~i]的和&#x…

实现小程序商城首页【源码公开】

效果图 页面源码 <view class"index-container"><view class"header"><!--搜索框【仅样式&#xff0c;不做处理】 start--><van-search bindtap"clickSearch" disabled shape"round" background"#9c7bf0&q…

Pycharm安装dlib

目录 一、下载dilb 二、使用pip安装dlib库(亲测有效) 三、使用Pycharm安装(未使用) 一、下载dilb 官方网址:德利卜 皮皮 (pypi.org) 二、使用pip安装dlib库(亲测有效) 将下载好的whl文件放入工程文件中 接下来使用Python自带的pip进行安装 1.winR2.输入cmd&#xff0c;回车…

MySQL第六章、JDBC编程

目录 一、数据库编程的必备条件 二、Java的数据库编程&#xff1a;JDBC 三、JDBC工作原理 四、JDBC使用 4.1JDBC开发案例 一、数据库编程的必备条件 编程语言&#xff0c;如Java&#xff0c;C、C、Python等数据库&#xff0c;如Oracle&#xff0c;MySQL&#xff0c;SQL S…

十大网络安全上市公司分析,让我们重点聊聊F5

网络安全上市厂商业务广泛分布于网络安全硬件、软件&#xff0c;网络安全服务等板块&#xff0c;总体来看&#xff0c;十大网络安全上市公司的竞争可谓是如火如荼。今天让我们把目光集中在F5&#xff0c;这个能为我们所有人创造更安全的数字世界的企业&#xff0c;在应用及API交…

Linux下使用命令行和配置文件两种方式实现主从复制

一、什么是主从复制&#xff1f; Redis的主从复制&#xff08;Master-Slave Replication&#xff09;是一种数据复制机制&#xff0c;其中一个Redis实例充当主节点&#xff08;Master&#xff09;&#xff0c;而其他一个或多个Redis实例则充当从节点&#xff08;Slave&#xff…

基于GIS的生态敏感性评价与产业路径选择研究:以江西省吉安市为例

导读: 确立绿水青山就是金山银山的理念,建立生态经济体系,是新时代生态环境保护与经济发展的协调之道。对产业规划而言,与生态同行,构建绿色产业体系,是推动地区高质量发展的根本要求。鉴于此,文章从实证角度出发,以江西省吉安市为研究对象,采用生态敏感性评价方法,选…

【EXCEL】通过url获取网页表格数据

目录 0.环境 1.背景 2.具体操作 0.环境 windows excel2021 1.背景 之前我用python的flask框架的爬虫爬取过豆瓣网的电影信息&#xff0c;没想到excel可以直接通过url去获取网页表格内的信息&#xff0c;比如下图这是电影信息界面 即将上映电影 (douban.com) 通过excel操作&…

(栈队列堆) 剑指 Offer 31. 栈的压入、弹出序列 ——【Leetcode每日一题】

❓ 剑指 Offer 31. 栈的压入、弹出序列 难度&#xff1a;中等 输入两个整数序列&#xff0c;第一个序列表示栈的压入顺序&#xff0c;请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如&#xff0c;序列 {1,2,3,4,5} 是某栈的压栈序列&#xff0c;序…

【字符串编码解码问题】

字符串中编码解码问题 1.编码 byte[] getBytes()&#xff1a;使用平台的默认字符集将该String编码为一系列字节&#xff0c;将结果存储到新的字节数组中byte[] getBytes(String charsetName)&#xff1a;使用指定的字符集将该String编码为一系列字节&#xff0c;将结果存储到…

AHB协议理解

从小父亲就教育我&#xff0c;做一个对社会有用的人&#xff01; 目录 Chapter1 AHB Block Diagram Ginput signal lnput signals Output Signal Chapter3 Transfers AHB接口Overview Chapter6 Data Buses HWDATA HRDATA Chapter1 Introduction AHB: Advanced High-performanc…

ubuntu创建多用户并使用ssh链接

添加多个同时登录的用户 以下内容中的“username”根据自己需求自己定义 1.创建新用户 sudo useradd username2.给新用户添加管理权限 sudo vim /etc/sudoers打开的文件中添加如下内容 username ALL(ALL:ALL) ALL3.设置密码 输入&#xff1a; sudo passwd username打开的…

创建型模式 - 原型模式

概述 用一个已经创建的实例作为原型&#xff0c;通过复制该原型对象来创建一个和原型对象相同的新对象。 结构 原型模式包含如下角色&#xff1a; 抽象原型类&#xff1a;规定了具体原型对象必须实现的的 clone() 方法。 具体原型类&#xff1a;实现抽象原型类的 clone() 方…