手把手教你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语言中错误处理的实践指南

《从基础到高级详解Go语言中错误处理的实践指南》Go语言采用了一种独特而明确的错误处理哲学,与其他主流编程语言形成鲜明对比,本文将为大家详细介绍Go语言中错误处理详细方法,希望对大家有所帮助... 目录1 Go 错误处理哲学与核心机制1.1 错误接口设计1.2 错误与异常的区别2 错误创建与检查2.1 基础

Linux下利用select实现串口数据读取过程

《Linux下利用select实现串口数据读取过程》文章介绍Linux中使用select、poll或epoll实现串口数据读取,通过I/O多路复用机制在数据到达时触发读取,避免持续轮询,示例代码展示设... 目录示例代码(使用select实现)代码解释总结在 linux 系统里,我们可以借助 select、

Go语言中json操作的实现

《Go语言中json操作的实现》本文主要介绍了Go语言中的json操作的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录 一、jsOChina编程N 与 Go 类型对应关系️ 二、基本操作:编码与解码 三、结构体标签(Struc

MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决

《MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决》MyBatis默认开启一级缓存,同一事务中循环调用查询方法时会重复使用缓存数据,导致获取的序列主键值均为1,... 目录问题原因解决办法如果是存储过程总结问题myBATis有如下代码获取序列作为主键IdMappe

C#使用iText获取PDF的trailer数据的代码示例

《C#使用iText获取PDF的trailer数据的代码示例》开发程序debug的时候,看到了PDF有个trailer数据,挺有意思,于是考虑用代码把它读出来,那么就用到我们常用的iText框架了,所... 目录引言iText 核心概念C# 代码示例步骤 1: 确保已安装 iText步骤 2: C# 代码程

Pandas处理缺失数据的方式汇总

《Pandas处理缺失数据的方式汇总》许多教程中的数据与现实世界中的数据有很大不同,现实世界中的数据很少是干净且同质的,本文我们将讨论处理缺失数据的一些常规注意事项,了解Pandas如何表示缺失数据,... 目录缺失数据约定的权衡Pandas 中的缺失数据None 作为哨兵值NaN:缺失的数值数据Panda

C++中处理文本数据char与string的终极对比指南

《C++中处理文本数据char与string的终极对比指南》在C++编程中char和string是两种用于处理字符数据的类型,但它们在使用方式和功能上有显著的不同,:本文主要介绍C++中处理文本数... 目录1. 基本定义与本质2. 内存管理3. 操作与功能4. 性能特点5. 使用场景6. 相互转换核心区别

k8s搭建nfs共享存储实践

《k8s搭建nfs共享存储实践》本文介绍NFS服务端搭建与客户端配置,涵盖安装工具、目录设置及服务启动,随后讲解K8S中NFS动态存储部署,包括创建命名空间、ServiceAccount、RBAC权限... 目录1. NFS搭建1.1 部署NFS服务端1.1.1 下载nfs-utils和rpcbind1.1

python语言中的常用容器(集合)示例详解

《python语言中的常用容器(集合)示例详解》Python集合是一种无序且不重复的数据容器,它可以存储任意类型的对象,包括数字、字符串、元组等,下面:本文主要介绍python语言中常用容器(集合... 目录1.核心内置容器1. 列表2. 元组3. 集合4. 冻结集合5. 字典2.collections模块

Redis高性能Key-Value存储与缓存利器常见解决方案

《Redis高性能Key-Value存储与缓存利器常见解决方案》Redis是高性能内存Key-Value存储系统,支持丰富数据类型与持久化方案(RDB/AOF),本文给大家介绍Redis高性能Key-... 目录Redis:高性能Key-Value存储与缓存利器什么是Redis?为什么选择Redis?Red