【C语言进阶】深度剖析数据在内存中的存储--上

1. C语言中的数据类型的简单介绍

注:C99标准里面,定义了bool类型变量。这时,只要引入头文件stdbool.h ,就能在C语言里面正常使用bool类型。

在这里插入图片描述
1.1 在C语言中各类型所占内存空间的大小如下

char类型的数据类型大小为1字节即8比特位。

short类型的数据类型大小为2字节即16比特位。

int类型、float类型的数据类型大小为4字节即32比特位。
long类型较为特殊,C语言规定中sizeof(long)>=sizeof(int)
32位平台下long大小为4字节,64位平台下long大小为8字节。
long long类型、double类型的数据类型大小为8字节即64位。

1.2 类型的意义:

  1. 使用这个类型开辟内存空间的大小(大小决定了使用范围)。
  2. 如何看待内存空间的视角
    什么叫做看待内存空间的视角呢?以int类型、float类型为例,虽然大小都为4字节,但是存储的不同的数据类型。

1.3 类型的基本归类:
整型家族:

char类型在内存中以ASCLL码值存储,所以归类于整型家族
注:在C语言标准中,char类型默认为unsigned char 还是signed char是未定义的,取决于编译器,但是大部分编译器char默认为signed char
char

  unsigned char   signed char

short

unsigned short   signed short

int

int unsigned int   signed int

long

unsigned long   signed long

long long

unsigned long long   signed long long

有符号类型的最高位表示符号位,负数最高位是1,正数最高位是0。

浮点数家族:

float
double

构造类型:

数组类型

数组类型是去掉数组名,剩下的部分。
例如int arr1[5]和int arr2[8]两个数组的类型分别是int [5]和int [8].

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

指针类型

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

空类型:

void 表示空类型(无类型) 通常应用于函数的返回类型、函数的参数、指针类型

2. 整形在内存中的存储

我们知道数值有不同的表示方式.
例如十进制的21,用不同进制表示如下:
二进制表示:0b10101 (二进制以0b开头)
八进制表示:025 (八进制以0开头)
十六进制表示:0x15 (十六进制以0x开头)
而在计算机中数据是以2进制存储的。

2.1 原码、反码、补码

计算机中的整数有三种表示方法,即原码、反码和补码。 三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,
正整数的原码、反码、补码都相同。
负整数的三种表示方法各不相同。
原码 直接将二进制按照正负数的形式翻译成二进制就可以。
反码 将原码的符号位不变,其他位依次按位取反就可以得到了。
补码 反码+1就得到补码。

以正整数20和负整数10为例,原码反码补码如下。
数据在内存中是以二进制存储的,但为了方便程序员观察,在编译器的内存窗口显示的是16进制
在这里插入图片描述

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

2.2为什么要使用补码存储呢?

举个例子 计算机计算1-1是如何实现的呢,因为(CPU只有加法器)可以将1-1变为1+(-1) 假设都是短整型数据
1的原码是0000000000000001
-1的原码是1000000000000001
相加的结果是1000000000000010 //-2
1+(-1)的结果不应该是0么?这里的结果却是-2.
🤔🤔🤔🤔🤔🤔🤔🤔🤔🤔🤔🤔🤔🤔🤔
通过上面的例子我们可以看到,如果采用原码存储,不便于加减运算。无法直接得到计算结果。 而如果使用补码存储 假设都是短整型数据
1的补码是0000000000000001
-1的补码是111111111111111111
相加的结果是0000000000000000 // 0
通过上面的例子我们可以看到,如果采用补码存储,可以可以将符号位和数值域统 一处理,直接得到运算的结果。

补码与原码相互转换,其运算过程 是相同的,不需要额外的硬件电路。
这句话是什么意思呢?

我们知道负整数的补码就是将原码的符号位不变,其他位依次按位取反再加1 那么知道了它的补码如何求源码呢?
将运算过程逆过来,负整数的补码-1就是反码,而反码再符号位不变,其他位按位取反就是原码,这是一种普遍的方法。
但是其实负整数的补码转换为原码也可以采用原码转换为补码时采用的方法 将补码符号位不变,其他位按位取反,再将得到的结果加1就是负整数的原码
例如-10的补码转换为原码:
在这里插入图片描述

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

2.3 大小端介绍

什么大端小端: 大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址 中;
小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地 址中。 为什么有大端和小端:
为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元 都对应着一个字节,一个字节为8bit。但是在C语言中除了8 bit的char之外,还有16 bit的short型,32 bit的long型(要看具体的编
译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。
例如:一个 16bit 的 short 型 x ,在内存中的地址为 0x0010 , x 的值为 0x1122 ,那么 0x11 为
高字节, 0x22 为低字节。对于大端
模式,就将 0x11 放在低地址中,即 0x0010 中, 0x22 放在高地址中,即 0x0011 中。小端模式,
刚好相反。我们常用的 X86 结构是
小端模式,而 KEIL C51 则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式

在这里插入图片描述

百度2015年系统工程师笔试题:
请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。
#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;
}

3.练习巩固

学习了上面诸多知识后,让我们来实践一下吧。

1.打印a,b,c的结果分别是什么?
注:signed char 取值范围-128~127 unsigned char取值范围0-255

#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;
}

解析:

  char类型在vs编译器下默认是 signed char,将 -1存到signed char中会发生截断,-1默认是一个32位的整数。存到signed char中会截断低8位存储,所以a和b里存放的是11111111,而%d是打印有符号的整型数值,所以打印时会发生整型提升,提升时看a,b的类型,ab都是有符号类型,所以我们看它的最高位(符号位)来进行提升,这里的最高位是1,所以提升时在高位补24个1变为11111111111111111111111111111111,这时我们再将补码转换为原码1000000000000000000000000001得到的就是最终打印出来的结果的2进制序列,转换为10进制就是 -1,所以打印a,b的结果是 -1 .
  而c里存放的也是8个1,但是整型提升时因为是无符号类型,所以高位直接补24个0,凑齐32比特位。得到的补码是00000000000000000000000011111111,再将补码转换为原码依旧是00000000000000000000000011111111转换为10进制就是255,所以打印c的结果是 255。

2. 打印a的结果是什么?

#include <stdio.h>
int main()
{signed char a = -128;printf("%u\n",a);//%u打印无符号整数return 0;}

解析:
  -128的补码是11111111111111111111111110000000,截断低8位10000000,以%u形式打印发生整型提升,因为signed
char为有符号类型所以高位补符号位变为11111111111111111111111110000000,因为是以%u形式打印,所以会认为这串补码是一串非常大的正数的二进制序列,因为是正数所以补码原码相同,转换为10进制就是4294967168,所以a打印出来就是4294967168。

3.打印a的结果分别是是什么?

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

答案: printf(“%u\n”,a); //4294967168
printf(“%d\n”,a); //-128

4…打印i的结果是什么?

unsigned int i;
for(i = 9; i >= 0; i--)
{printf("%u\n",i);
}

答案:9 8 7 6 5 4 3 2 1 0 4294967295 4294967294 4294967293 …死循环下去
为什么结果会是这样呢? 解析: 因为i是一个无符号整数,所以9~0都是正常循环打印的,但是i–到了-1的时候,因为unsigned int
i是无符号整数,所以不会将-1的补码11111111111111111111111111111111看作是一个负数,而是会看作一个很大的正数,所以依旧满足循环条件。

在这里插入图片描述
5.字符串a的长度是多少?

int main()
{signed char a[1000];int i;for(i=0; i<1000; i++){a[i] = -1-i;}printf("%d",strlen(a));return 0;
}

解析:a[i]里存放的值依次是-1,-2,-3 …到-128为一个轮回,然后变为127,126
…2,1,0,然后再依次是-1,-2,-3
…一直循环到数组存满为止。本题求的是字符串长度,strlen在字符数组里找到‘\0’为止,而‘\0’的ascll码值为0,所以字符串a的长度是255。
在这里插入图片描述

6.下面代码的运行结果是什么?

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

答案:无限打印hello world,死循环下去。
解析:无符号数到255后+1又会变为0,无限循环下去。

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

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

相关文章

如何在PDF 文件中删除页面?

查看不同的工具以及解释如何在 Windows、Android、macOS 和 iOS 上从 PDF 删除页面的步骤&#xff1a; PDF 是最难处理的文件格式之一。曾经有一段时间&#xff0c;除了阅读之外&#xff0c;无法用 PDF 做任何事情。但是今天&#xff0c;有许多应用程序和工具可以让您用它们做…

用示波器测量这些参数你真的会吗?

大家好&#xff0c;我是砖一。 示波器是电子工程师最常见的仪器&#xff0c;很多人也把示波器比作工程师的“眼睛”&#xff0c;这也足以说明示波器对工程师有多重要。 信号是如何显示到示波器屏幕上的呢&#xff1f;在示波器上&#xff0c;信号传输经过探头内部的一系列电阻器…

通用防重幂等如何设计?

防重与幂等的区别 防重与幂等是在 Web 应用程序和分布式系统中重要而又非常常见的问题。 防重 防重是指在多次提交同样的请求过程中&#xff0c;系统会检测和消除重复的数据&#xff0c;确保相同的数据只会被处理一次&#xff0c;从而避免不必要的重复操作或产生错误的结果。…

MYSQL学习笔记:MYSQL存储引擎

MYSQL学习笔记&#xff1a;MYSQL存储引擎 MYSQL是插件式的存储引擎 存储引擎影响数据的存储方式 存储引擎是用来干什么的&#xff0c;innodb和myisam的主要区别–数据存储方式----索引 mysql> show engines; ----------------------------------------------------------…

作业2.13

1、选择题 1.1、若有定义语句&#xff1a;int a[3][6]; &#xff0c;按在内存中的存放顺序&#xff0c;a 数组的第10个元素是 D A&#xff09;a[0][4] B) a[1][3] C)a[0][3] D)a[1][4] 1.2、有数组 int a[5] {10&#xff0c;20&#xff0c;30&#xff0c;40&#xff0c;50},…

Github 2024-02-07 开源项目日报 Top9

根据Github Trendings的统计&#xff0c;今日(2024-02-07统计)共有9个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Rust项目2TypeScript项目2Python项目2Ruby项目1HTML项目1NASL项目1Go项目1C项目1Svelte项目1C项目1 React Nat…

自定义类型之枚举类型(enum)和联合体类型(union)

目录 枚举类型&#xff08;enum&#xff09; 什么是枚举类型&#xff1f; 枚举类型的使用 枚举类型的优势 枚举类型的应用场景 总结 联合体类型&#xff08;union&#xff09; 什么是联合体&#xff1f; 联合体的应用场景 联合体的注意事项 总结 枚举类型&#xff08…

C++ //练习 6.5 编写一个函数输出其实参的绝对值。

C Primer&#xff08;第5版&#xff09; 练习 6.5 练习 6.5 编写一个函数输出其实参的绝对值。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具&#xff1a;vim 代码块 /*************************************************************************&…

【Ubuntu】在.bashrc文件中误设置环境变量补救方法

这里是vim也不在PATH中了&#xff0c;因为 解决方法就是在输入vim之后提示的vim路径下用vim打开该文件&#xff0c;然后改回来

(三十六)大数据实战——ClickHouse数据库的部署安装实现

前言 ClickHouse是俄罗斯的Yandex于2016年开源的列式存储数据库 DBMS &#xff09;&#xff0c;使用C语言编写&#xff0c;主要用于在线分析处理查询&#xff08; OLAP &#xff09;&#xff0c;能够使用SQL查询实时生成分析数据报告。列式存储&#xff1a;数据按列进行存储&a…

局部特征描述子

局部特征描述子是用于表示图像、点云或其他数据中局部区域特征的一种方法。它们通常用于计算机视觉、三维重建和模式识别等领域。局部特征描述子的主要目标是捕获图像或数据中的局部结构和特征&#xff0c;这些特征在旋转、尺度和光照变化等方面具有不变性或者部分不变性。 一…

结合Next项目实际认识webpack.splitChunks

本文的目的在于简单的介绍webpack的优化功能配置&#xff1a;splitChunks。 webpack5出于“开箱即用”的目的&#xff0c;将大部分曾经要使用插件的功能集成到了config配置中&#xff0c;因此用户只需要了解如何配置&#xff0c;即可达到优化目的&#xff0c;其中最常使用接触的…

Backtrader 文档学习- Observers - Reference

Backtrader 文档学习- Observers - Reference 1.Benchmark class backtrader.observers.Benchmark() 观察器存储策略的回报和参考资产的回报&#xff0c;参考资产是传递给系统的数据之一。 参数&#xff1a; timeframe (default: None) &#xff0c;如果None&#xff0c;则将…

【ES】--ES集成自定义分词库

目录 一、相关安装1、(window单机)elasticsearch安装2、安装Elasticvue插件3、ik分词器插件4、ES集成自定义词库 一、相关安装 1、(window单机)elasticsearch安装 Win10下下载ES组件&#xff0c;安装部署如下&#xff1a;JDK1.8、elasticsearch-7.3.2-windows-x86_64。 Elast…

Debezium发布历史124

原文地址&#xff1a; https://debezium.io/blog/2022/06/21/debezium-1-9-4-final-released/ 欢迎关注留言&#xff0c;我是收集整理小能手&#xff0c;工具翻译&#xff0c;仅供参考&#xff0c;笔芯笔芯. Debezium 1.9.4.Final Released June 21, 2022 by Chris Cranford …

qt “美颜”

要想成为一名优秀的qt工程师 学会使用qss编程也是重要的 不可获缺的一部分 qss 简介和优势 QSS&#xff08;Qt Style Sheets&#xff09;是一种用于定义Qt应用程序界面外观和样式的样式表语言。它类似于CSS&#xff08;层叠样式表&#xff09;&#xff0c;但针对Qt框架进行了定…

末两位数(1992)_题解

【题解提供者】吴立强 解法 思路 指数函数增长速率过快&#xff0c;直接计算中间过程任何一种基本类型都无法存储。 通过乘法运算的规律&#xff0c;可以发现末两位数只和末两位数相关&#xff0c;故直接对中间结果保留末两位数&#xff08;mod 100&#xff09;即可避免乘法…

每日五道java面试题之java基础篇(七)

第一题. HashMap和HashTable有什么区别&#xff1f;其底层实现是什么&#xff1f; 区别 &#xff1a; HashMap⽅法没有synchronized修饰&#xff0c;线程⾮安全&#xff0c;HashTable线程安全&#xff1b;HashMap允许key和value为null&#xff0c;⽽HashTable不允许 底层实现…

容器高级知识: 适配器模式与 Sidecar 模式的区别

适配器模式与 Sidecar 模式的区别 在 Kubernetes 中&#xff0c;适配器模式和 Sidecar 模式都是扩展您的主应用程序容器功能的方法&#xff0c;但它们具有不同的目的和功能&#xff1a; Sidecar 模式&#xff1a; 通用目的&#xff1a; 为主应用程序提供 补充功能&#xff0…

(十五)springboot实战——spring securtity的核心过滤器介绍

前言 本节内容主要介绍spring securtity安全框架的一些核心过滤器及其作用&#xff0c;我们都清楚spring securtity安全框架底层是基于filter过滤器实现的&#xff0c;采用的是责任链的设计模式&#xff0c;它有一条很长的过滤器链。本次spring securtity原理介绍使用的版本是…