手把手教你C语言‘数据的存储‘[doge]

2023-11-23 16:00

本文主要是介绍手把手教你C语言‘数据的存储‘[doge],希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

@[toc](目录)

想来学完大多语法后,大家都对整型,浮点型,字符型都有了大概的认识,简而言之,大概知道是什么.

对其相关的了解想要更进一步,那就必须要知道这些类型在内存中是如何存储的了.

彳亍,那我们接下来就浅谈这几种类型的存储.

目录

数据类型

整型,浮点型的存储

大小端讲解

例题巩固


数据类型

想想到现在我们学了什么?               好像啥也没学

那从最基本的类型说起,下面是我们学过的几种类型

short   2
int     4
long    4
long long    8float   4
double  8char   1

他们的类型决定了我们看待内存的视角,也就是我们怎么看它,像一个标签一样

而要讨论他们在内存中的存在方式,肯定要讨论它的大小了

大小(所占字节数)决定了他们的精度,也决定了取值的范围

自然类型的意义就出来了:

1.类型决定了看待内存的角度

说人话:计算机怎么看它的,我们又是怎么看它的

2.类型决定了他们的使用范围

简单点:一个桶子只能装1L的水,你装1.1L就会溢出

下面我们就具体分一下类

Q:啥?上面不是分了?

A:那只是概述

具体分类如下

整型:char:   (别急后面解释为啥放这)unsigned char
signed charshort:
unsigned short
signed shortint:
unsigned int
signed intlong:
unsigned long
signed longlong long :
unsigned long long
signed long long

char字符型放在‘整型家族’的原因是char存的不是字符,而是字符的ASCII值,是个数字

浮点型:float
double构造类型:数组,struct,enum,union  (注意是数组和结构体,后面的枚举和联合知道有它就行了)指针:
char*
int*
float*
double*
void*    等等等等
指针类型太多在这不一一列举了空类型:
void
函数返回值,函数参数,指针类一般都可以见到它

现在你应该明白数据的分类了.

那么归好类,就得讲讲这个东西是怎么存的了

整型和浮点型的数据存储方式不同

所以小白时期明明感觉没错,但是打印的结果很奇怪,有一部分就是这个问题没有解决

先说整型:

整型在内存里存的是补码

我们进行的加减乘除全是操作补码

计算机里表示一个数有三种方法--原码,反码,补码

原码--符号位+二进制序列

第一位是符号位  0代表正,1代表负

例:

5的二进制101,如果放进int里面,int是32位

那么就写成

正数的原反补三码相同,写出原码就等价于写出补码

负数复杂一点

反码==原码符号位不动,其余位按位取反

解释:第一位不动,其余位0变成1,1变成0

补码==反码+1

例:

这就是整型,long,longlong之类的都可以类推

值得一提的是char类型,一个字节,八位,所以取值范围:-128-127

下面推导char的类型(有符号的char)


1000 0001是几?

由计算机算出来是127,加上符号位的1表示负数,所以是-127

那最后11111111是几?

显然是-1,可以自己动笔推算一下

由以上就可以知道char类型的取值是一个循环

假若我们从0开始

那就是0  ->  127  ->  (-128)  ->  (-1)  ->  0

这是有符号的char的范围:-128-127

注:127+1==-128

127是百尺竿头,再进一步就是-128

同理也可知道无符号的char: 0 - 255

到这里,我们就知道了整型在内存种的存储方式,存的是补码,我们也要知道怎么表示他们

同时也推导了char的取值范围,整型到这就告一段落了

---------------------------

整型,浮点型的存储

下面我们谈谈浮点型:

来一道典型的例题看看:

int main()
{int n = 9;float *pFloat = (float *)&n;printf("n的值为:%d\n",n);printf("*pFloat的值为:%f\n",*pFloat);*pFloat = 9.0;printf("num的值为:%d\n",n);printf("*pFloat的值为:%f\n",*pFloat);return 0; }

猜猜这四个打印的值是多少?

想好了没?

公布答案:

小朋友是不是有很多的问号?

哈哈哈哈哈哈,说回正题

具体介绍下浮点型咋存的,再来解释打印的结果

float

记住这么几个数字  :1-8-23

double   

记住这么几个数字:  1-11-52

这几个数字意义是什么:

从前往后:符号位 -指数- 有效数字(S-E-M)

E是一个无符号数,后面解释为什么

例:

S:0表示正数,1表示负数(这点和整型对应上了)

E有八位,第八位是符号位吗?前面说过转换过程+127所以一定是正数,

所以E的第八位不是符号位,这是一个无符号数

上面是E不全为0或者不全为1

那如果E(指数)是全0或者全1呢,属于特殊情况,分类讨论

全0:说明这个数很小,想想+127都是0了,那读取的时候应用规则:E取1-127的值或者1-1023的值

全1:这个数的绝对值很大,趋于无穷(指数不能决定正负)

到此我们知道了浮点数的存储方式

十进制的浮点数->写成二进制->转换成指数形式->根据规则确定存入的S-E-M的值,再按规则取出来

这就是浮点数的存储

那么我们来解释一下最开始的例题:

不用往上翻了

从内存入手:

先看这四句话:

n以%d(整型的方式读取)打印肯定是9,没问题

float*和int*都操作四个字节,都可以拿到32位,不存在截取的问题

所以%f就是以浮点数的读取方式读取整型,由补码入手:

E全是0,无限接近0的一个数,float默认打印小数点后6位,

自然结果:

 

那再看后面两行:

第一行赋值为9.0,float型指针,以浮点数的方式存进去

那就有:

以%d的形式打印,也就是以整型的办法去读取:

正数,所以直接补码==原码

读取的十进制数也就是计算器所呈现的1091567616

以%f,也就是浮点型的方式去读取它,自然是9.000000

我们再比对一下结果:

ohhhhhhhh,一样的对吧.

------------------

到这里我们就知道了浮点数的存储方式,进度条过半

-----------------

大小端讲解

接下来就是大小端的问题了

先给定义:

大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;
小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位 , ,保存在内存的高地址中。
简单点,说话的方式简单点
数字有高位和低位
例:12345  5是个位,是低位
10101010   0是2^0  是低位
地址有高地址和低地址
例:0x00000001  低地址
0x00000005  高地址
知道这两个再理解大小端:
大端:数据的低位 放在  高地址   
小端:数据的低位 放在 低地址
这么说还是太抽象了,举例说明:
这是VS编译器,通过调试我们知道a里面存的是这玩意?
所以VS是大端还是小端?
前情提要:
'0x'告诉编译器这是个十六进制数字,由于32个二进制位显示过长,所以调试显示的是16进制.
一个十六进制位==4个二进制位
两个十六进制位==1个字节,所以上面显示的一组数字就是一个字节,四组四个字节,满足int的大小.
由上图可知:低位放到了低地址,高位放到了高地址,对应定义,确实是小端存储.
对大小端有了一个认识后,我们来看一道题:
请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。( 10 分)
大端字节序:高字节内容保存在内存的低地址处,低字节内容保存在内存的高地址处
小端字节序: (看啥?补充啊,上面给了你个范本了)
小程序:
以1为例(数字简单好推算结果)
1==0x00 00 00 01
若是大端字节序,存的就是:00 00 00 01(正着存)
若是小端字节序,存的就是:01 00 00 00(倒着存)
显然只要看第一个字节的内容是1还是0?-> 操作一个字节-> char类型的指针 ->用拿到的数去 '&1' 就可以知道拿到的数是不是1
代码如下:
int check(int a)
{char* tmp = (char*)&a;if (*tmp & 1 == 1){return 1;}return 0;
}int main()
{int a = 1;if (check(a)){printf("小端\n");}else{printf("大端\n");}

再次证明VS是小端字节序机器.
------------------进度过去3/4,就快结束了
对于基础知识我们有了一定的了解,下面就是做题巩固了

例题巩固

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

因为是第一题,讲详细一点

某些编译器默认char是有符号的signed char,有些又当作unsigned char处理。VS默认signed char

char a==signed char a (VS编译器下)

有符号的char:

我们再来看看结果:
没问题!
有个诀窍:char--  在-128-127这个范围里面的肯定就是这个数本身
unsigned char   ---  0-255  在这个范围里面的肯定就是这个数本身,此题-1不在那就加或减256,让它进入这个范围(-1+256==255)

2.

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

-128在这个范围内,但是注意是无符号数打印(%d打印那就是-128),所以还是从补码入手

让我们来比对下答案:
没问题
3.最后一题
int i= -20;
unsigned  int  j = 10;
printf("%d\n", i+j); 
//按照补码的形式进行运算,最后格式化成为有符号整数

可以,没问题!

------------------终于写完了!-------------

能看到这真的强:

----------------------------

感谢阅读,如果有帮助别忘了点赞,这对我帮助很大,下次再见!

这篇关于手把手教你C语言‘数据的存储‘[doge]的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/419082

相关文章

Go语言中nil判断的注意事项(最新推荐)

《Go语言中nil判断的注意事项(最新推荐)》本文给大家介绍Go语言中nil判断的注意事项,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1.接口变量的特殊行为2.nil的合法类型3.nil值的实用行为4.自定义类型与nil5.反射判断nil6.函数返回的

Java中调用数据库存储过程的示例代码

《Java中调用数据库存储过程的示例代码》本文介绍Java通过JDBC调用数据库存储过程的方法,涵盖参数类型、执行步骤及数据库差异,需注意异常处理与资源管理,以优化性能并实现复杂业务逻辑,感兴趣的朋友... 目录一、存储过程概述二、Java调用存储过程的基本javascript步骤三、Java调用存储过程示

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁

MyBatisPlus如何优化千万级数据的CRUD

《MyBatisPlus如何优化千万级数据的CRUD》最近负责的一个项目,数据库表量级破千万,每次执行CRUD都像走钢丝,稍有不慎就引起数据库报警,本文就结合这个项目的实战经验,聊聊MyBatisPl... 目录背景一、MyBATis Plus 简介二、千万级数据的挑战三、优化 CRUD 的关键策略1. 查

python实现对数据公钥加密与私钥解密

《python实现对数据公钥加密与私钥解密》这篇文章主要为大家详细介绍了如何使用python实现对数据公钥加密与私钥解密,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录公钥私钥的生成使用公钥加密使用私钥解密公钥私钥的生成这一部分,使用python生成公钥与私钥,然后保存在两个文

MySQL之InnoDB存储引擎中的索引用法及说明

《MySQL之InnoDB存储引擎中的索引用法及说明》:本文主要介绍MySQL之InnoDB存储引擎中的索引用法及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录1、背景2、准备3、正篇【1】存储用户记录的数据页【2】存储目录项记录的数据页【3】聚簇索引【4】二

mysql中的数据目录用法及说明

《mysql中的数据目录用法及说明》:本文主要介绍mysql中的数据目录用法及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、版本3、数据目录4、总结1、背景安装mysql之后,在安装目录下会有一个data目录,我们创建的数据库、创建的表、插入的

MySQL之InnoDB存储页的独立表空间解读

《MySQL之InnoDB存储页的独立表空间解读》:本文主要介绍MySQL之InnoDB存储页的独立表空间,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、独立表空间【1】表空间大小【2】区【3】组【4】段【5】区的类型【6】XDES Entry区结构【

SQLite3 在嵌入式C环境中存储音频/视频文件的最优方案

《SQLite3在嵌入式C环境中存储音频/视频文件的最优方案》本文探讨了SQLite3在嵌入式C环境中存储音视频文件的优化方案,推荐采用文件路径存储结合元数据管理,兼顾效率与资源限制,小文件可使用B... 目录SQLite3 在嵌入式C环境中存储音频/视频文件的专业方案一、存储策略选择1. 直接存储 vs

Navicat数据表的数据添加,删除及使用sql完成数据的添加过程

《Navicat数据表的数据添加,删除及使用sql完成数据的添加过程》:本文主要介绍Navicat数据表的数据添加,删除及使用sql完成数据的添加过程,具有很好的参考价值,希望对大家有所帮助,如有... 目录Navicat数据表数据添加,删除及使用sql完成数据添加选中操作的表则出现如下界面,查看左下角从左