【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);  //4294967168
    printf("%d\n",a); //-128
    return 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,无限循环下去。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySQL数据库⑨_事务(四个属性+回滚提交+隔离级别+MVCC)

目录 1. 事务的概念和四个属性 2. 事务的支持版本 3. 事务的提交方式 4. 事务的相关演示 4.1 常规操作_回滚_提交 4.2 原子性_演示 4.3 持久性_演示 4.4 begin自动更改提交方式 4.5 单条SQL与事务的关系 5. 事务的隔离级别 5.1 四种隔离级别 5.2 查看与设置隔离级别…

LeetCode、435. 无重叠区间【中等,贪心 区间问题】

文章目录 前言LeetCode、435. 无重叠区间【中等&#xff0c;贪心 区间问题】题目链接及分类思路贪心、区间问题 资料获取 前言 博主介绍&#xff1a;✌目前全网粉丝2W&#xff0c;csdn博客专家、Java领域优质创作者&#xff0c;博客之星、阿里云平台优质作者、专注于Java后端技…

2.03 作业

一、选择题 1-4 CCCB 二、填空题 1.传参 2.C 3.using namespace std 4.int i32 a>65 && a<90 5.iE6 三、编程题 3.1 f(‘A’)错误&#xff0c;重载函数中没有char类型 f(10, 23.4)错误&#xff0c;第一个参数是int&#xff0c;第二个是double类…

【精选】java进阶——包和final

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【python】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏…

【开源】JAVA+Vue.js实现高校学院网站

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 学院院系模块2.2 竞赛报名模块2.3 教育教学模块2.4 招生就业模块2.5 实时信息模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 学院院系表3.2.2 竞赛报名表3.2.3 教育教学表3.2.4 招生就业表3.2.5 实时信息表 四、系…

LAXCUS分布式操作系统目标:软件算力入口

英伟达现在的市值相当于整个中国股市&#xff01;说明了什么&#xff1f; AI 大潮下&#xff0c;算力就是生产力&#xff0c;也是未来 20 年一切产业的基础&#xff0c;英伟达已经把住硬件算力入口&#xff0c;LAXCUS 分布式操作系统瞄准软件算力入口&#xff0c;做好了&#…

Spring Boot 笔记 010 创建接口_更新用户头像

1.1.1 usercontroller中添加updateAvatar&#xff0c;校验是否为url PatchMapping("updateAvatar")public Result updateAvatar(RequestParam URL String avatarUrl) {userService.updateAvatar(avatarUrl);return Result.success();} 1.1.2 userservice //更新头像…

生成式人工智能(AIGC)之最全详解图解

生成式人工智能&#xff08;AIGC&#xff09;之最全详解图解 1. AIGC的发展历程1.1 AIGC演化重要时间节点AIGC发展历程图OpenAI大语言模型发展进程 1.2技术推进路线 2.AIGC技术场景2.1 技术场景 3.1AIGC相关应用4.AIGC未来发展前景 1. AIGC的发展历程 AIGC&#xff08;AI-Gene…

【EAI 019】Eureka: Human-Level Reward Design via Coding LLM

论文标题&#xff1a;Eureka: Human-Level Reward Design via Coding Large Language Models 论文作者&#xff1a;Yecheng Jason Ma, William Liang, Guanzhi Wang, De-An Huang, Osbert Bastani, Dinesh Jayaraman, Yuke Zhu, Linxi Fan, Anima Anandkumar 作者单位&#xff…

项目排期 - 华为OD统一考试

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 200分 题解&#xff1a; Java / Python / C 题目描述 项目组共有N个开发人员&#xff0c;项目经理接到了M个独立的需求&#xff0c;每个需求的工作量不同&#xff0c;且每个需求只能由一个开发人员独立完成&#xff0…

考研数据结构笔记(2)

线性表 线性表的定义线性表的基本操作lnitList(&L)DestroyList(&L)Listlnsert(&L,i,e)ListDelete(&L,i,&e)LocateElem(L,e)GetElem(L,i)Length(L)PrintList(L)Empty(L)Tips:引用值 小结 根据数据结构的三要素–逻辑结构、数据的运算、存储结构&#xff0c;…

文生图提示词:光线效果

色彩和光线 --光线效果 Lighting Effects 覆盖了光线效果的多个方面&#xff0c;包括光的性质、来源、作用方式以及光与物体相互作用产生的视觉效果&#xff0c;是摄影和视觉艺术中不可或缺的元素。 Soft Light 柔光 Hard Light 硬光 Natural Light 自然光 Artificial Light 人…

勒索病毒最新变种.target勒索病毒来袭,如何恢复受感染的数据?

导言&#xff1a; 在当今数字化时代&#xff0c;数据被视为企业和个人最重要的资产之一。然而&#xff0c;随着技术的进步&#xff0c;网络安全威胁也在不断演变。其中&#xff0c;勒索病毒是一种极具破坏性的威胁&#xff0c;而".target"勒索病毒是近期备受关注的一…

【开源】JAVA+Vue+SpringBoot实现学生综合素质评价系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 学生功能2.2 教师功能2.3 教务处功能 三、系统展示四、核心代码4.1 查询我的学科竞赛4.2 保存单个问卷4.3 根据类型查询学生问卷4.4 填写语数外评价4.5 填写品德自评问卷分 五、免责说明 一、摘要 1.1 项目介绍 基于J…

【分布式技术专题】「Zookeeper中间件」Paxos协议的原理和实际运行中的应用流程分析

Paxo算法介绍 Paxos算法是莱斯利兰伯特(Leslie Lamport)1990年提出的一种基于消息传递的一致性算法。 Paxos产生背景 Paxos算法是基于消息传递且具有高度容错特性的一致性算法&#xff0c;是目前公认的解决分布式一致性问题最有效的算法之一&#xff0c;其解决的问题就是在分…

[算法前沿]--059-大语言模型Fine-tuning踩坑经验之谈

前言 由于 ChatGPT 和 GPT4 兴起,如何让人人都用上这种大模型,是目前 AI 领域最活跃的事情。当下开源的 LLM(Large language model)非常多,可谓是百模大战。面对诸多开源本地模型,根据自己的需求,选择适合自己的基座模型和参数量很重要。选择完后需要对训练数据进行预处…

mlxtend,一个非常好用的 Python 库!

前言 Python 的 MLxtend&#xff08;Machine Learning Extensions&#xff09;库是一个强大的工具&#xff0c;为机器学习实验提供了一系列功能强大的扩展和工具。本文将深入探讨 MLxtend 库的核心功能、用法以及如何在机器学习项目中充分发挥其优势。 目录 前言 什么是 MLx…

C++异常特性以及使用

异常 1.C传统的处理错误方式2.异常概念3.异常使用规则抛出和匹配规则 4.异常的重新抛出4.异常安全5.异常规范6.使用自定义的异常7.C标准异常体系7.异常优缺点 1.C传统的处理错误方式 终止程序&#xff1a;如assert&#xff0c;缺陷&#xff1a;用户难以接受。如发生内存错误&a…

简单介绍源程序执行方式

源程序执行方式 编译和解释 程序设计语言能够把算法翻译成机器能够理解的可执行程序。这里将计算机不能直接执行的非机器语言源程序翻译成能直接执行的机器语言的语言翻译程序称为语言处理程序 源程序&#xff1a;用各种程序设计语言编写的程序称为源程序&#xff0c;计算机不…

celery异步框架的使用

文章目录 celery的介绍celery的架构celery的快速使用celery 包结构celery 定时 异步 延迟任务django使用celery celery的介绍 celery是什么&#xff1f; -翻译过来是芹菜 -官网&#xff1a;https://docs.celeryq.dev/en/stable/ -吉祥物&#xff1a;芹菜 -分布式的异步任务框架…