手把手教你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

相关文章

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

异构存储(冷热数据分离)

异构存储主要解决不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。 异构存储Shell操作 (1)查看当前有哪些存储策略可以用 [lytfly@hadoop102 hadoop-3.1.4]$ hdfs storagepolicies -listPolicies (2)为指定路径(数据存储目录)设置指定的存储策略 hdfs storagepolicies -setStoragePo

HDFS—存储优化(纠删码)

纠删码原理 HDFS 默认情况下,一个文件有3个副本,这样提高了数据的可靠性,但也带来了2倍的冗余开销。 Hadoop3.x 引入了纠删码,采用计算的方式,可以节省约50%左右的存储空间。 此种方式节约了空间,但是会增加 cpu 的计算。 纠删码策略是给具体一个路径设置。所有往此路径下存储的文件,都会执行此策略。 默认只开启对 RS-6-3-1024k

Hadoop集群数据均衡之磁盘间数据均衡

生产环境,由于硬盘空间不足,往往需要增加一块硬盘。刚加载的硬盘没有数据时,可以执行磁盘数据均衡命令。(Hadoop3.x新特性) plan后面带的节点的名字必须是已经存在的,并且是需要均衡的节点。 如果节点不存在,会报如下错误: 如果节点只有一个硬盘的话,不会创建均衡计划: (1)生成均衡计划 hdfs diskbalancer -plan hadoop102 (2)执行均衡计划 hd

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验