C语言——深度剖析数据在内存中的存储——第1篇——(第24篇)

news/2024/5/21 2:00:43/文章来源:https://blog.csdn.net/weixin_45641816/article/details/136278725

坚持就是胜利

文章目录

  • 一、数据类型详细介绍
    • 1、类型的基本归类
      • (1)整型家族
      • (2)浮点数家族
      • (3)构造类型 (自定义类型)
      • (4)指针类型
      • (5)空类型
  • 二、整型在内存中的存储解析
    • 1、原码、反码、补码
    • 2、大小端字节序介绍
      • (1)什么是大端小端?
      • (2)为什么有大端和小端?
      • (3)设计一个小程序来判断当前机器的字节序
    • 3、练习
      • (1)
      • (2)
      • (3)
      • (4)
      • (5)
      • (6)比较难,好好理解
      • (7)好题


一、数据类型详细介绍

前面我们学习了基本的内置类型,以及它们所占存储空间的大小。

char        //字符数据类型  1 字节
short       //短整型        2 字节 
int         //整型          4 字节
long        //长整型        4/8 字节  sizeof(long) >= sizeof(int)
long long   //更长的整型    8 字节
float       //单精度浮点数  4 字节
double      //双精度浮点数  8 字节

1、什么是 内置类型?

答:C语言本身自带的类型

2、为什么整型分为 short int long?

答:比如存储年龄 age,用 int 太大了,用 short 就可以。short 取值范围:-32768 ~ 32767

#include <limits.h>   //注意头文件//在此头文件下,可以查询内置类型的最大值,最小值int main()
{INT_MAX;   //转到定义return 0;
}

在这里插入图片描述

类型的意义:

1、使用这个类型开辟内存空间的大小(大小决定了使用范围)。
2、如何看待内存空间的视觉。

1、类型的基本归类

有符号数、无符号数,只针对 整型。
浮点数 没有 有符号数和无符号数 的说法和区分。

(1)整型家族

//字符 char 在存储的时候,存储的是 ASCII值,是整型所以归类的时候,放在整型家族。
char         unsigned char signed char
shortunsigned shortsigned short
int unsigned intsigned int
long unsigned long [int]signed long [int]
对于整型家族的类型来说,有:“有符号”和“无符号”的区分1char 到底是 signed char 还是 unsigned char 不确定(C语言没有给出明确的规定)(char 在 VS 上是 signed char2short == signed shortunsigned short
3int  ==  signed intunsigned int
4long  ==  signed longunsigned long

在这里插入图片描述
在这里插入图片描述

(2)浮点数家族

float
double

(3)构造类型 (自定义类型)

1、数组类型
2、结构体类型 struct
3、枚举类型 enum
4、联合类型 union//int arr1[10] ——> int [10]
//int arr2[20] ——> int [20]
//char arr3[10] ——> char [10]
//数组 arr1 和 arr2 和 arr3 类型各不相同

(4)指针类型

1int* pi;
2char* pc;
3float* pf;
4void* pv;
5、结构体指针类型;

(5)空类型

void 表示 空类型(无类型)
通常应用于 函数的返回类型、函数的参数、指针类型。
//void* ps;

二、整型在内存中的存储解析

一个变量的创建,是要在内存中开辟空间的。
空间的大小,是根据不同的类型而决定的。

1、原码、反码、补码

计算机中的整数有 3 种 2进制 表示方法,即原码、反码、补码。
三种表示方法均有 符号位 和 数值位 两部分,符号位都是用 0 表示 “正”,用 1 表示 “负”,
而数值位:
正整数的原码、反码、补码都相同。
负整数的三种表示方法各不相同。

原码
直接将数值按照正负数的形式翻译成二进制就可以得到原码反码
将原码的符号位不变,其他位依次按位取反就可以得到反码补码
反码 + 1 就得到补码

对于整型来说:数据存放内存中,其实存放的是补码。
为什么呢?

在计算机系统中,数值一律用补码来表示和存储。
原因在于,使用补码,可以将符号位和数值域统一处理;
同时,加法和减法也可以统一处理(CPU只有加法器),
此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。

在这里插入图片描述

为什么用 补码 计算,而不用 原码 计算?答:用 原码 计算,有些运算会出错计算 1 - 1  (由于CPU只有加法器,所以 1 - 1 就是 1 +  (-1)1+(-1)原码 计算 
00000000 00000000 00000000 00000001  数值 1
10000000 00000000 00000000 00000001  数值 -1
10000000 00000000 00000000 00000010  相加等于 -2 ,计算错误补码计算:将 符号位 和 数值域 统一处理
00000000 00000000 00000000 00000001  数值1原码
00000000 00000000 00000000 00000001  数值1反码
00000000 00000000 00000000 00000001  数值1补码10000000 00000000 00000000 00000001  数值-1原码
11111111 11111111 11111111 11111110  数值-1反码
11111111 11111111 11111111 11111111  数值-1补码00000000 00000000 00000000 00000001  数值1补码  11111111 11111111 11111111 11111111  数值-1补码
1 00000000 00000000 00000000 00000000  只能存3200000000 00000000 00000000 00000000  结果为 0 ,正确

2、大小端字节序介绍

什么是 字节序?
答:以 字节 为单位,讨论存储顺序的。

(1)什么是大端小端?

大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中。
小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,保存在内存的高地址中。

(2)为什么有大端和小端?

为什么会有大小端模式之分呢?
这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为 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 处理器 还可以由 硬件 来选择是大端模式还是小端模式。

在这里插入图片描述

(3)设计一个小程序来判断当前机器的字节序

在这里插入图片描述

由于 int a;
所以 &a 是 int* 类型
需要判断 int a 的 第1个字节
将 int* 转换为 char* 即可!
再 解引用* 
#include <stdio.h>int main()
{int a = 1;//char* p = &a;   //这么写是错误的,因为 &a 是 int* 类型char* p = (char*)&a;if (*p == 1){printf("小端存储\n");}else{printf("大端存储\n");}return 0;
}

在这里插入图片描述

#include <stdio.h>int main()
{int a = 1;if (*(char*)&a == 1){printf("小端存储\n");}else{printf("大端存储\n");}return 0;
}
#include <stdio.h>int check_sys()
{int a = 1;if (*(char*)&a == 1)  //再精简为:if(*(char*)&a){return 1;}else{return 0;}
}int main()
{int ret = check_sys();if (ret == 1){printf("小端存储\n");}else{printf("大端存储\n");}return 0;
}
#include <stdio.h>int check_sys()
{int a = 1;  return *(char*)&a;  //一步步精简成这样}int main()
{int ret = check_sys();if (ret == 1){printf("小端存储\n");}else{printf("大端存储\n");}return 0;
}

3、练习

(1)

对于整型家族的类型来说,有:“有符号”和“无符号”的区分1char 到底是 signed char 还是 unsigned char 不确定(C语言没有给出明确的规定)(char 在 VS 上是 signed char2short == signed shortunsigned short
3int  ==  signed intunsigned int
4long  ==  signed longunsigned long

在这里插入图片描述
在这里插入图片描述

#include <stdio.h>int main()
{char a = -1;signed char b = -1;unsigned char c = -1;printf("a=%d,b=%d,c=%d\n", a, b, c);  // a=-1 b=-1 c=255 return 0;
}

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

//知识点(之前学习过)
//1、长度大于 int 的,就不需要进行 ”整型提升“
//2、有符号的整型提升:高位补充符号位
//3、无符号的整型提升,高位补 0
//4、%d 十进制的形式打印有符号整型整数//正确的解答过程
//整数 -1 存入 char a 中
//整数 -1 原码:10000000 00000000 00000000 00000001
//        反码:11111111 11111111 11111111 11111110
//        补码:11111111 11111111 11111111 11111111//截断,因为只有 1 字节 才能存入 char a 中:11111111//%d 十进制的形式打印有符号整型整数
//对char a 进行 整型提升
//补码:11111111 11111111 11111111 11111111
//反码:10000000 00000000 00000000 00000000
//补码:10000000 00000000 00000000 00000001
//结果显示:-1//signed char b 和 char a 是一样的解答过程
//在本电脑中的VS编译器,char 类型是 signed char //unsigned char c
//整数 -1 存入 unsigned char c 中
//整数 -1 原码:10000000 00000000 00000000 00000001
//        反码:11111111 11111111 11111111 11111110
//        补码:11111111 11111111 11111111 11111111//截断,因为只有 1 字节 才能存入 unsigned char c 中:11111111//无符号整型提升,高位补 0
//补码:00000000 00000000 00000000 11111111
//%d 十进制的形式打印有符号整型整数
//因为此时已经按照 %d 的形式输出,最高位为 0,是 正数
// 正数的原码、反码、补码相同
//原码:00000000 00000000 00000000 11111111
//结果:255

(2)

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

在这里插入图片描述
在这里插入图片描述

//知识点:
//%u 十进制的形式打印无符号的整型整数//整数-128,存入 char a 中
//-128补码:10000000 00000000 00000000 10000000
//    反码:11111111 11111111 11111111 01111111
//    补码:11111111 11111111 11111111 10000000//截断:10000000  存入 char a 中//%u 十进制的形式打印无符号的整型整数
//整型提升,也就是对 char a 进行整型提升
//char a 是有符号的,符号位是 1
//补码:11111111 11111111 11111111 10000000  
//%u 是无符号数,内存中就没有符号位,内存中存入的就是:11111111 11111111 11111111 10000000
//无符号数可以看成 正数,补码,反码,原码都是一样的
//结果就是:11111111 11111111 11111111 10000000
//十进制就是:4294967168

(3)

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

在这里插入图片描述

//知识点:
//%u 十进制的形式打印无符号的整型整数//整数128,存入 char a 中
//128补码:00000000 00000000 00000000 10000000
//正数的原码、反码、补码相同//截断:10000000  存入 char a 中//%u 十进制的形式打印无符号的整型整数
//整型提升,也就是对 char a 进行整型提升,char a 是有符号的,符号位为 1
//char a 是有符号的,符号位是 1
//补码:11111111 11111111 11111111 10000000  
//%u 是无符号数,内存中就没有符号位,内存中存入的就是:11111111 11111111 11111111 10000000
//无符号数可以看成 正数,补码,反码,原码都是一样的
//结果就是:11111111 11111111 11111111 10000000
//十进制就是:4294967168

(4)

在这里插入图片描述

#include <stdio.h>int main()
{int i = -20;unsigned int j = 10;printf("%d\n", i + j);return 0;
}

在这里插入图片描述

//知识点:
//1、补码得到原码有两种方式:
//                          (1)补码-1得到反码,反码取反得到原码
//                          (2)补码先取反再加1,得到原码//整数-20原码:10000000 00000000 00000000 00010100
//       反码:11111111 11111111 11111111 11101011
//       补码:11111111 11111111 11111111 11101100//unsigned int j = 10原码:00000000 00000000 00000000 00001010
//无符号数的反码、原码、补码相同
//                   补码:00000000 00000000 00000000 00001010//i+j  补码相加 11111111 11111111 11111111 11101100
//              00000000 00000000 00000000 00001010
//              11111111 11111111 11111111 11110110 
//截断:11111111 11111111 11111111 11110110 
// (1)补码-1得到反码,反码取反得到原码
//补码:11111111 11111111 11111111 11110110  
//反码:11111111 11111111 11111111 11110101
//原码:10000000 00000000 00000000 00001010
//结果:-10//(2)补码先取反再加1,得到原码
//补码:11111111 11111111 11111111 11110110 
//取反:10000000 00000000 00000000 00001001
//+1  :10000000 00000000 00000000 00001010
//结果:-10

(5)

#include <stdio.h>
#include <windows.h>int main()
{unsigned int i;for (i = 9; i >= 0; i--){printf("%u\n", i);Sleep(1000);  //单位:毫秒   5000毫秒}return 0;
}

在这里插入图片描述
死循环,因为 unsigned int i 是 恒大于等于零 的。
在这里插入图片描述

//9 8 7 6 5 4 3 2 1 0 的原码、反码、补码 相同
//0 原码:00000000 00000000 00000000 00000000//-1 原码:10000000 00000000 00000000 00000001
//   反码:11111111 11111111 11111111 11111110
//   补码:11111111 11111111 11111111 11111111//0-1  0+(-1)
//0 补码:00000000 00000000 00000000 00000000
//-1补码:11111111 11111111 11111111 11111111
//相加  :11111111 11111111 11111111 11111111//以 %u 输出:4294967295

在这里插入图片描述

(6)比较难,好好理解

#include <stdio.h>
#include <string.h>int main()
{char a[1000];int i;for (i = 0; i < 1000; i++){a[i] = -1 - i;printf("%d\n", a[i]);}printf("%d\n", strlen(a));  //答案是:255return 0;
}

结果:255
原因:strlen() 统计的是 ‘\0’,之前出现的数字的个数!!!
在这里插入图片描述
在这里插入图片描述

(7)好题

#include <stdio.h>unsigned char i = 0;   //unsigned char 的取值范围:0 ~ 255int main()
{for (i = 0; i <= 255; i++)      //此时:i<=255 条件恒成立,所以死循环{printf("hell0 world\n");    //死循环}return 0;
}

微软雅黑字体
黑体
3号字
4号字
红色
绿色
蓝色

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

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

相关文章

PHP项目中composer和Git的组合使用

highlight: 在国内由于众所周知的原因&#xff0c;composer的package可能无法访问&#xff0c;解决办法是使用中国的全镜像&#xff1a; composer config -g repositories.packagist composer http://packagist.phpcomposer.com 在需要使用composer package的地方创建composer…

小程序实现定位城市切换且城市根据首字母A-Z排序后端数据实现逻辑

场景&#xff1a; 话不多说后端提供数据实现步骤&#xff1a; 1.controller层 Api(tags {"[地区]-城市相关接口"}) RestController RequestMapping("region") Slf4j public class RegionController extends BaseController {Resourceprivate RegionServ…

9 款顶级 iPhone 系统修复软件,可修复各种 iPhone 软件问题

iOS的封闭性和纯粹性仍然无法让iPhone免受潜在风险的影响。iPhone 存在常见问题&#xff0c;包括iPhone/iPad 卡住 Apple 徽标、iOS 更新无法充电问题、iPhone 耳机问题等等。 通常&#xff0c;在这种情况下&#xff0c;您的 iPhone 数据可能无法访问&#xff0c;甚至面临很大…

爬虫IP代理池的搭建与使用指南

目录 一、爬虫IP代理池的重要性 二、搭建IP代理池 选择合适的代理IP源 搭建代理IP池服务器 实现代理IP的获取和更新 三、使用IP代理池 配置爬虫程序 调用代理IP池API 实现代理IP的自动切换 四、案例与代码 五、总结 随着互联网的迅猛发展&#xff0c;网络爬虫作为一…

用于制作耳机壳的倒模专用UV树脂有什么特点?

制作耳机壳的UV树脂耳机壳UV胶具有以下特点&#xff1a; 快速固化&#xff1a;UV树脂可以在紫外线的照射下迅速固化&#xff0c;大大缩短了制作时间。高硬度与高耐磨性&#xff1a;UV树脂具有较高的硬度和耐磨性&#xff0c;能够提供良好的保护效果。透明度高&#xff1a;UV树…

selenium爬虫

方法选择和安装包 在动态网页并且登陆过程中不需要进行过于复杂的密码验证的时候使用selenium会非常的方便 安装准备过程也相对简单&#xff1a; 下载对应版本的chromedriver并且通过如下代码找到路径下载到python所在的目录&#xff1a; import sysprint(sys.executable) …

普中51单片机学习(LCD1602)

LCD1602 1602液晶也叫1602字符型液晶&#xff0c;它是一种专门用来显示字母、数字、符号的点阵型液晶模块。它是由若干个5x7或者5x10的点阵字符位组成&#xff0c;每个点阵字符位都可以用显示一个字符&#xff0c;每位之间有一个点距的间隔&#xff0c;每行之间也有间隔&#…

Home Assistant:基于Python的智能家居开源系统详解

Home Assistant&#xff1a;基于Python的智能家居开源系统详解 在数字化和智能化的时代&#xff0c;智能家居系统成为了现代家庭的新宠。它们能够让我们更加方便地控制家中的各种设备&#xff0c;实现自动化和个性化的居住体验。其中&#xff0c;Home Assistant作为一款基于Pyt…

Linux Shell脚本练习(一)

一、 Linux下执行Shell脚本的方式&#xff1a; 1、用shell程序执行脚本&#xff1a; a、根据你的shell脚本的类型&#xff0c;选择shell程序&#xff0c;常用的有sh&#xff0c;bash&#xff0c;tcsh等 b、程序的第一行#!/bin/bash里面指明了shell类型的&#xff0c;比如#!/…

【行业科普】常见的边缘计算产品有哪些?主要应用于哪些场景?

之前的几期科普文给大家介绍了什么是边缘计算&#xff0c;以及它的优势、应用场景等内容。有兴趣的可以戳链接再了解一下。&#xff08;【行业科普】边缘计算有多强&#xff1f;一起了解它的优势及其5大典型应用&#xff01;&#xff09;今天我们再来了解一下常见的边缘计算产品…

C# 获取类型 Type.GetType()

背景 C#是强类型语言&#xff0c;任何对象都有Type&#xff0c;有时候需要使用Type来进行反射、序列化、筛选等&#xff0c;获取Type有Type.GetType, typeof()&#xff0c;object.GetType() 等方法&#xff0c;本文重点介绍Type.GetType()。 系统类型/本程序集内的类型 对于系…

2023年全国职业院校技能大赛中职组大数据应用与服务赛项题库参考答案陆续更新中,敬请期待…

2023年全国职业院校技能大赛中职组大数据应用与服务赛项题库参考答案陆续更新中&#xff0c;敬请期待… 武汉唯众智创科技有限公司 2024 年 2 月 联系人&#xff1a;辜渝傧13037102709 题号&#xff1a;试题01 模块三&#xff1a;业务分析与可视化 &#xff08;一&#xff0…

基于springboot+vue的党员教育和管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

SOLIDWORKS参数化设计之工程图更新 慧德敏学

SOLIDWORKS参数化设计不仅仅包括三维模型的参数化设计&#xff0c;还包括工程图的自动更新&#xff0c;由于自动出图仍然存在一定的局限性&#xff0c;不能完美的实现视图的布局及尺寸的标注&#xff0c;因此&#xff0c;现阶段采用的最多的仍然是图纸的更新&#xff0c;也就是…

创作纪念日【第1024天】的感触与期待

我的创作纪念日 1.机缘2.日常3.成就4.收获5.憧憬 1.机缘 2021年的04月份进入新行业了&#xff0c;公司不让用自己的电脑进行办公&#xff0c;也不能带自己的设备&#xff0c;之前记录的笔记查看不太方便&#xff0c;所以想着弄个博客&#xff0c;也尝试过云笔记&#xff0c;最…

Java根据excel模版导出Excel(easyexcel、poi)——含项目测试例子拿来即用

Java根据excel模版导出Excel&#xff08;easyexcel、poi&#xff09;——含项目测试例子拿来即用 1. 前言1.1 关于Excel的一般导出2.2 关于easyexcel的根据模版导出 2. 先看效果2.1 模版2.2 效果 3. 代码实现&#xff08;核心代码&#xff09;3.1 项目代码结构3.2 静态填充例子…

Springboot项目中定时任务的四种实现方式

文章目录 1. 使用Scheduled注解1.1 时间间隔执行1.2 固定时间点执行 2. 使用EnableScheduling注解启用定时任务3. 实现SchedulingConfigurer接口4. 使用Quartz框架4.1 配置QuartzScheduler4.2 定义Job类和Trigger类 5. 总结 在开发现代应用时&#xff0c;定时任务是一个非常常见…

Peter算法小课堂—动态规划

Peter来啦&#xff0c;好久没有更新了呢 今天&#xff0c;我们来讨论讨论提高组的动态规划。 动态规划 动态规划有好多经典的题&#xff0c;有什么背包问题、正整数拆分、杨辉三角……但是&#xff0c;如果考到陌生的题&#xff0c;怎么办呢&#xff1f;比如说2000年提高组的…

压缩视频大小的软件有哪些?5款软件推荐

压缩视频大小的软件有哪些&#xff1f;随着高清摄像设备的普及和网络速度的不断提升&#xff0c;视频文件变得越来越庞大&#xff0c;动辄数百兆甚至数GB的大小常常让用户在分享和存储时感到头疼。幸运的是&#xff0c;市面上有许多优秀的视频压缩软件可以帮助我们轻松应对这一…

国产服务器操作系统

为何记录 最近的开发工作经常接触到国产服务器操作系统的业务&#xff0c;经常被x86、arm、龙芯、鲲鹏、欧拉...搞得一脸懵逼&#xff0c;遂记之&#xff01; 操作系统 这里按照应用场景分&#xff1a; 桌面操作系统&#xff1a;主要用于pc&#xff0c;如Windows、macOS、Li…