C语言——数据在内存中的存储(上)
数据在内存中的存储
1. 数据类型的介绍
之前已经介绍过C语言中的基本数据类型了,主要有:
char//字符数据类型short//短整型int//整形long//长整型long long//更长的整形float//单精度浮点数double//双精度浮点数注意:C语言中是是没有字符串类型的。
类型的意义:
- 使用这种类型的数据所开辟的内存空间的大小。
- 如何看待内存空间的视角。
2. 类型的基本分类
【整形家族】
char :unsigned char signed char
short :unsigned short signed short
int :unsigned int signed int
long :unsigned long signed long
long long :unsigned long long signed long long注意:C语言规定:sizeof(long)>=sizeof(int),所以long类型的占用的空间不能确定是4还是8。
【浮点数家族】
float
double
【构造类型】
数组类型
结构体类型
枚举类型
联合类型
【指针类型】
int *pi;
char *pc;
float* pf;
void* pv;
3. 整形在内存中的存储
由于变量的创建是需要空间的,具体使用的空间的大小是根据不同的类型而确定的。例如:
char ch = 0;这里ch变量是char类型,所以就在内存中占用了一个字节。
注意:
char类型一般C语言官方没有明确规定是signed char还是unsigned char,一般的编译器,例如VS上,char就是signed char。但是除了char以外,其他的整形都是有明确规定的,例如:int就是signed int。
那么不同的数据类型所能表示的范围是多少呢?我们可以通过以下代码来查看:
#include<stdio.h>
#include<stdlib.h>
#include <limits.h>
int main()
{printf("%d\n", INT_MAX);printf("%d\n", INT_MIN);return 0;
}
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-133iB8YJ-1685460890411)(C:\Users\30539\AppData\Roaming\Typora\typora-user-images\image-20230528135439546.png)]](https://img-blog.csdnimg.cn/07add5bc65a140199f461215fcefb463.png)
那么这些数据的范围大小是怎么计算出来的呢?这里以char为例:
char占用一个字节:一个字节有8个比特位,每一个比特位只能是0或1,所以char类型在内存中组合方式一共就有256种:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IXcfGFbt-1685460890412)(C:\Users\30539\AppData\Roaming\Typora\typora-user-images\image-20230528144545767.png)]](https://img-blog.csdnimg.cn/41035def92c5490b900fefa418cde0ec.png)
注意:这里图中所有的二进制序列都是代表的是内存中的补码。由此观之,char类型的数据范围就是:-128~127。unsigned char的范围就是0~255。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6k6czyBp-1685460890412)(C:\Users\30539\AppData\Roaming\Typora\typora-user-images\image-20230528145453042.png)]](https://img-blog.csdnimg.cn/8ab92347d4314ca9b35f5dacfcdaeaa5.png)
由此类推:short数据范围就是:-32768~32767。其他的整数数据类型的范围小伙伴们可以自行查阅。
3.1 整形在内存中的存储
计算机中保存整数二进制的方式主要有三种,分别是原码,反码,补码。整形在内存中主要是以补码的形式保存。三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位则是直接读取即可。
正数的原、反、补码都相同。
负整数的三种表示方法各不相同。
原码:直接将数值按照正负数的形式翻译成二进制就可以得到原码。
补码:将原码的符号位不变,其他位依次按位取反就可以得到反码。
反码+1就得到补码。
对于整形来说:数据存放内存中其实存放的是补码。使用补码可以将其符号位和数值域进行统一运算。
原因:
在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统 一处理; 同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程 是相同的,不需要额外的硬件电路。
对于数据存放内存中存放的是补码我们可以通过编译器进行直接观察。例如:-1的补码是32个1,用16进制表示就是全f。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kpqakovm-1685460890413)(C:\Users\30539\AppData\Roaming\Typora\typora-user-images\image-20230528141952454.png)]](https://img-blog.csdnimg.cn/ee5b87c629ad405f8100ec4510a7ea75.png)
但我们把例子换成4的时候:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EHJdZDxY-1685460890413)(C:\Users\30539\AppData\Roaming\Typora\typora-user-images\image-20230528142156157.png)]](https://img-blog.csdnimg.cn/14d5f5e64f3844c99d45108f54a64a24.png)
这里发现内存中是有低地址到高地址存放数据的。数据的低权值位是放在低地址处的。这里就要引出新概念了:大端字节序和小端字节序。
4. 大小端介绍
概念:
大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;
小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地址中。
为什么有大端和小端?
为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8 bit。但是在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处理器还可以由硬件来选择是大端模式 还是小端模式。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5g4vpl2R-1685460890414)(C:\Users\30539\AppData\Roaming\Typora\typora-user-images\image-20230528142934825.png)]](https://img-blog.csdnimg.cn/0a296f3c5fe344ee8a41a55854b7c9e1.png)
字节序:以字节为单位讨论数据的存储的。一个char类型只占用一个字节,所以对char类型讨论大小端字节序是没有意义的,这里大小端字节序是针对占用的内存空间大于1个字节的整数数据类型的。
大小端字节序是由电脑内置部件决定的,与编译器的类型无关。这里作者的电脑是以小端字节序存储的。
4.1 练习
Q1
请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。
Answer:
#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;
}
以下是错误的写法:
int main()//这种是错误的
{int a = 0x11223344;char b = (char)a;//无论如何b拿到的都是a的最低字节的数据 if (b == 0x44)printf("小端!\n");if (b == 0x11)printf("大端!\n");return 0;
}
上面这段代码无论如何b拿到的都是a的最低字节的数据 。
Q2
//输出什么?
#include <stdio.h>
int main()
{char a= -1;unsigned char c=-1;printf("a=%d,c=%d",a,c);return 0;
}
char a= -1;//-1的二进制补码是32个1。因为char只有一个字节,存放不下,先发生截断,a中存放的就是8个1。
unsigned char c = -1;//c也是只有1个字节,发生截断,存放的也是8个1。
当
printf("a = %d,c = %d",a,c);执行时,由于%d代表的是有符号打印,所以a和c均会发生整形提升:先看a的整形提升:a是有符号数,整形提升时补的是符号位,所以就补1,变成32个1,又因为是以有符号的形式打印,而符号位又是1,所以将32个1翻译成原码就是-1,即打印-1.
再看b的整形提升,b是无符号数,整形提升时,最高位补0,所以b就变成了24个0和8个1,又因为是以有符号的形式打印,而符号位是0,翻译成原码就是255。
运行结果:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VnpFNqgL-1685460890414)(C:\Users\30539\AppData\Roaming\Typora\typora-user-images\image-20230528145735159.png)]](https://img-blog.csdnimg.cn/c9033b4f64374957aefbe1c76227bc81.png)
Q3
//输出什么?
#include <stdio.h>
int main()
{char a = -128;printf("%u\n",a);return 0;
}
-128的
原码:100000000000000000000000010000000
反码:111111111111111111111111101111111
补码:111111111111111111111111110000000
由于a只有8比特的空间,所以发生截断,a中存放的是:10000000
在执行
printf("%u\n",a);语句时,因为%u是无符号整形打印:所以a会发生整形提升,由于a是signed char,为有符号类型,整形提升时高位补符号位的数,也就是补1,所以此时a中存放的是:11111111111111111111111110000000,因为是%u无符号打印,所以直接将这串二进制序列看作原码进行打印。
运行结果:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WN0RLHE5-1685460890414)(C:\Users\30539\AppData\Roaming\Typora\typora-user-images\image-20230528150508845.png)]](https://img-blog.csdnimg.cn/e24d03ee355649b89347bf936354dadd.png)
Q4
//输出什么?
#include <stdio.h>
int main()
{char a = 128;printf("%u\n",a);return 0;
}
先写出128的补码,再截断存储到a中,a中存放的也是:10000000,与Q3类似。
运行结果:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ciQP3UZd-1685460890415)(C:\Users\30539\AppData\Roaming\Typora\typora-user-images\image-20230528150659634.png)]](https://img-blog.csdnimg.cn/c22ab6e96cc94d39b456d9c8cab18fa4.png)
Q5
int main()
{//输出什么?int i = -20;unsigned int j = 10;printf("%d\n", i + j);//按照补码的形式进行运算,最后格式化成为有符号整数return 0;
}
先写出i的
原码:10000000000000000000000000010100
反码:11111111111111111111111111101011
补码:11111111111111111111111111101100
写出j的
补码:00000000000000000000000000001010
接着让这两个补码相加:
11111111111111111111111111101100+
00000000000000000000000000001010=
11111111111111111111111111110110
又因为是%d以有符号整形进行打印,所以将相加之后的二进制的最高位看作符号位。所以这里将相加得到的二进制序列转换成原码:10000000000000000000000000001010,也就是-1。
运行结果:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vxadLC1q-1685460890415)(C:\Users\30539\AppData\Roaming\Typora\typora-user-images\image-20230528151358092.png)]](https://img-blog.csdnimg.cn/2b0d4ea78ebe48048527a2f83d6dd9f2.png)
Q6
//输出什么?
unsigned int i;
for(i = 9; i >= 0; i--)
{printf("%u\n",i);
}
这里由于i的数据类型是unsigned int 类型,是恒>=0的,所以I>0这个条件会一直满足,程序发生死循环。
运行结果:发生死循环
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P9xU8IBl-1685460890415)(C:\Users\30539\AppData\Roaming\Typora\typora-user-images\image-20230528151504019.png)]](https://img-blog.csdnimg.cn/eacdfa0cc5c147d89bf340dbd39010c5.png)
Q7
//输出什么?
int main()
{char a[1000];int i;for(i=0; i<1000; i++){a[i] = -1-i;}printf("%d",strlen(a));return 0;
}
这里arr[i]的值一开始是-1,-2,-3……当arr[i]的值变成-128时,,由本文之前画的图可知,此时再减1就会变成127,接着就是126,125,……1,0.这里strlen计算数组的长度时,会遇到’\0’才停止,而’\0’的ascll码值就是0,即这里数组的长度就是当arr[i]变成0之前的元素的个数,这里由-1到-128,再由-128到127再到1,一共有255个元素。所以结果就是255.
运行结果:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wAHbsYh1-1685460890416)(C:\Users\30539\AppData\Roaming\Typora\typora-user-images\image-20230528151546746.png)]](https://img-blog.csdnimg.cn/ab038701ea1a4a5b96caa4f18d3ed98c.png)
Q8
//输出什么?
#include <stdio.h>
unsigned char i = 0;
int main()
{for(i = 0;i<=255;i++){printf("hello world\n");}return 0;
}
此处由于i的数据类型是unsigned char 其数据范围是[0,255],始终是大于0的,所以会一直打印,发生死循环。
运行结果:发生死循环
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jTcEiukT-1685460890416)(C:\Users\30539\AppData\Roaming\Typora\typora-user-images\image-20230528151616258.png)]](https://img-blog.csdnimg.cn/dc79ccf9e3c242f0b4263c12e7f04bac.png)
相关文章:
C语言——数据在内存中的存储(上)
数据在内存中的存储 1. 数据类型的介绍 之前已经介绍过C语言中的基本数据类型了,主要有: char //字符数据类型short //短整型int //整形long //长整型long long //更长的整形float //单精度浮点数double //双精度浮点数 注意:C语言中是是没…...
LinkedIn 国际版怎么在国内登录?怎么使用领英国际版?
自从去年底国内用户使用LinkedIn就只能跳转到领英职场,而且就只是一个简单的招聘求职平台,没办法搜索添加国外客户,开发客户资源的效率大打折扣。但是国际版领英就不受影响,东哥今天就给各位做外贸的朋友分享如何使用国际版领英。…...
QThread Class
QThread QThread类枚举类型成员函数可重写函数公共槽信号静态成员函数保护函数静态保护函数QThread简单案例1QThread简单案例2 QThread类 标准头文件:#include <QThread> qmake: QT core 继承(父): QObject枚举类型 线程的优先级 enum Priority { IdlePri…...
C语言中的运算符及其优先级详解
引言: 在C语言中,运算符是用于进行各种数学和逻辑运算的符号。了解不同类型的运算符及其优先级对于正确理解和编写C语言代码至关重要。本文将详细介绍C语言中常用的运算符,包括算术运算符、赋值运算符、比较运算符、逻辑运算符等,…...
【C语言】语言篇——数组和字符串
C站的小伙伴们,大家好呀😝😝!我最近在阅读学习刘汝佳老师的《算法竞赛入门经典》,今天将整理本书的第三章——数组和字符串的一些习题,本章习题较多,下选取部分习题进行练习总结,在这…...
Js写的二级联动和三级联动
二级联动的实现 第一步 在HTML页面创建两个 select 下拉列表元素,并设置id为 ‘province’和id ‘city’ <!--省份--> <select id"province" onchange"getCity()"></select><!--城市--> <select id"city&qu…...
一文带你了解UI自动化测试框架
PythonSeleniumUnittestDdtHTMLReport分布式数据驱动自动化测试框架结构 1、Business:公共业务模块,如登录模块,可以把登录模块进行封装供调用 ------login_business.py from Page_Object.Common_Page.login_page import Login_Page from H…...
【Linux】守护进程
守护进程(Daemon)是一种在后台运行的特殊进程。它通常在操作系统启动时启动,并一直运行直至系统关闭。它不与任何终端关联,并且没有标准输入、输出和错误流。它的主要作用是在系统启动后执行一些特定的任务或者提供某些服务&#…...
Vue中组件和插件有什么区别?
Vue中组件和插件有什么区别? 组件是什么 组件就是把图形、非图形的各种逻辑均抽象为一个统一的概念(组件)来实现开发的模式,在Vue中每一个.vue文件都可以视为一个组件 组件的优势 降低整个系统的耦合度,在保持接口…...
第五章 图像处理
文章目录 前言一、图像金字塔1.高斯金字塔2.拉普拉斯金字塔 二、图像轮廓1. 轮廓提取2. 轮廓绘制3. 轮廓特征4. 轮廓近似5. 轮廓标记 三、模板匹配四、直方图1. 对比度2. 绘制直方图3. 均衡化3.1 理论3.2 代码 4. CLAHE 五、图像傅里叶变换5.1 正弦平面波5.2 二维傅里叶变换5.3…...
算法8.从暴力递归到动态规划1
算法|8.从暴力递归到动态规划1 目前感觉,背包问题和货币数组问题本质相同,货币的与dp相关的三种代码写完了,快复习不完了,背包暂时先不写了,回头再写,补充,再总结,结合那个C大神的文…...
8-JDBC 编程
目录 1.数据库编程的必备条件 PS:程序是怎么操作数据库的? 2.什么是JDBC? 2.1.JDBC定义 2.2.JDBC工作原理 3.JDBC使用 3.1.创建项目并添加MySQL驱动包 3.2.使用代码操作数据库 3.2.1.获得数据源 3.2.2.获得连接 3.2.3.获得执行器 …...
零基础如何学习 Web 安全?
Web安全不仅是互联网的核心,而且还是云计算和移动互联网的最佳载体。对于信息安全从业者而言,Web安全是一个非常重要的研究课题之一。 Web应用是指采用B/S架构、通过HTTP/HTTPS协议提供服务的统称。随着互联网的广泛使用,社交网络、聊天工具…...
【简单实用框架】【AddressablesMgr】【可移植】
☀️博客主页:CSDN博客主页💨本文由 萌萌的小木屋 原创,首发于 CSDN💢🔥学习专栏推荐:面试汇总❗️游戏框架专栏推荐:游戏实用框架专栏⛅️点赞 👍 收藏 ⭐留言 📝&#…...
android 12.0Launcher3禁止拖拽app图标到第一屏
1.概述 在12.0进行定制化开发Launcher3中,会对Launcher3 做些要求,比如现在的需求就是Launcher3第一屏的图标固定,不让其他屏的图标拖动到 第一屏所以说这个需求和 禁止拖拽图标到Hotseat类似,也是从WorkSpace.java里面寻找解决方案 2.Launcher3禁止拖拽app图标到第一屏相…...
SkyLine简介
简介 SkyLine产品系列(TerraExplorer 、TerraGate、TerraBuilder)是一套优秀的三维数字地球平台软件。凭借其国际领先的三维数字化显示技术,它可以利用海量的遥感航测影像数据、数字高程数据以及其他二三维数据搭建出一个对真实世界进行模拟…...
算法基础学习笔记——④前缀和\差分\双指针\位运算
✨博主:命运之光 ✨专栏:算法基础学习 目录 ✨前缀和 ✨一维前缀和 🍓一维前缀和模板: ✨二维前缀和 🍓二位前缀和模板: 前言:算法学习笔记记录日常分享,需要的看哈O(∩_∩)O&a…...
【Linux系统基础快速入门详解】Linux下安装软件必知必会4种方法(yum,编译安装,rpm包,二进制方式)等详解
在 Linux 下安装软件有多种方法可供选择,常用的包括 yum、编译安装、rpm 包和二进制方式。下面对这些方法进行详细说明: 使用 yum 安装软件yum 是 Red Hat 系列 Linux 发行版中常用的软件包管理工具,通过 yum 可以方便地安装、升级和删除软件包。yum 默认从官方仓库中下载软…...
ASEMI代理长电可控硅BT136参数,BT136规格,BT136说明
编辑-Z 长电可控硅BT136参数: 型号:BT136 RMS通态电流IT(RMS):6A 非重复浪涌峰值导通电流ITSM:25A 峰值栅极电流IGM:2A 平均栅极功耗PG(AV):0.5W 存储接点温度范围Tstg:-40 to 150℃ 工…...
代码线程安全
线程生命周期 synchronized synchronized会自动释放锁 synchronized同步代码块 synchronized后面括号里obj是锁对象(保证唯一);static修饰的obj对象是自定义MyThread线程类的静态成员变量,该自定义线程类所有实例共享保证锁对象唯一性;另一…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...
HTML前端开发:JavaScript 获取元素方法详解
作为前端开发者,高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法,分为两大系列: 一、getElementBy... 系列 传统方法,直接通过 DOM 接口访问,返回动态集合(元素变化会实时更新)。…...
STM32标准库-ADC数模转换器
文章目录 一、ADC1.1简介1. 2逐次逼近型ADC1.3ADC框图1.4ADC基本结构1.4.1 信号 “上车点”:输入模块(GPIO、温度、V_REFINT)1.4.2 信号 “调度站”:多路开关1.4.3 信号 “加工厂”:ADC 转换器(规则组 注入…...
深入解析光敏传感技术:嵌入式仿真平台如何重塑电子工程教学
一、光敏传感技术的物理本质与系统级实现挑战 光敏电阻作为经典的光电传感器件,其工作原理根植于半导体材料的光电导效应。当入射光子能量超过材料带隙宽度时,价带电子受激发跃迁至导带,形成电子-空穴对,导致材料电导率显著提升。…...
数据挖掘是什么?数据挖掘技术有哪些?
目录 一、数据挖掘是什么 二、常见的数据挖掘技术 1. 关联规则挖掘 2. 分类算法 3. 聚类分析 4. 回归分析 三、数据挖掘的应用领域 1. 商业领域 2. 医疗领域 3. 金融领域 4. 其他领域 四、数据挖掘面临的挑战和未来趋势 1. 面临的挑战 2. 未来趋势 五、总结 数据…...
Electron简介(附电子书学习资料)
一、什么是Electron? Electron 是一个由 GitHub 开发的 开源框架,允许开发者使用 Web技术(HTML、CSS、JavaScript) 构建跨平台的桌面应用程序(Windows、macOS、Linux)。它将 Chromium浏览器内核 和 Node.j…...
智能体革命:企业如何构建自主决策的AI代理?
OpenAI智能代理构建实用指南详解 随着大型语言模型(LLM)在推理、多模态理解和工具调用能力上的进步,智能代理(Agents)成为自动化领域的新突破。与传统软件仅帮助用户自动化流程不同,智能代理能够自主执行工…...
