高级程序员必备知识——数据在内存中的存储(常量字符串大小端特殊指针浮点型存储方式)

Posted 燕麦冲冲冲

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了高级程序员必备知识——数据在内存中的存储(常量字符串大小端特殊指针浮点型存储方式)相关的知识,希望对你有一定的参考价值。

一、数据类型的基本分类

  • 整型家族 —— short char int long
  • 浮点数家族 —— float double
  • 构造类型(自定义类型)——
    (1)数组类型
    比如定义一个整形数组int arr[10], 去掉数组名arr, 剩下的就是数组类型,即int [10]
    (2) 结构体类型 —— struct
    (3) 枚举类型 —— enum
    (4) 联合类型 —— union
  • 指针类型 —— int* char* float* void*

1.1 坑爹的笔试题

一道笔试题
char str1[] = "hehe";
char str2[] = "hehe";
char* str3 = "hehe";
char* str4 = "hehe";
if(str1 == str2)
{
	printf("hehe");
}
if(str3 = str4)
{
	printf("haha");
}1)由于"hehe"是一个常量字符串,是无法被修改的,且拥有其独立的一块内存空间。
(2)要是将一个常量字符串赋值给指针变量,严格的语法形式应该如下:
const char* ptr = "hehe";
意思是指针所指向的内容不可被修改。
故这ptr3和ptr4指向的是同一块空间。
(3)而常量字符串赋值给字符数组,字符串会到字符数组开辟的空间上储存.
ptr1和ptr2是数组的首元素地址,指向的是不同的地址。

综上所述,答案是输出一个haha

二、简要介绍整形在内存中的存储

  • 原码 反码 补码

2.1原码反码的由来

  • 科学家采用二进制数的首位数字来表示正负号,1代表负号,0代表正号。
  • 计算机中的CPU没有加法器,如果将两个二进制数的原码直接相加的话,比如1+(-1),
1的原码 =  00000000000000000000000000000001
-1的原码 = 10000000000000000000000000000001
相加的结果 10000000000000000000000000000010
转换为十进制 = -2
但正确结果显然为 0
  • 所以科学家巧妙地利用了补码解决了这个问题
1的补码   =  00000000000000000000000000000001
-1的补码  =  11111111111111111111111111111111
相加的结果 = 10000000000000000000000000000000
多出的一位被舍去了,因为超出了32个bit位
最终的结果为320
  • 大小端字节序存储

2.2大小端字节序的背景

内存中的每个地址是一个字节,但是int类型的变量占四个字节,这四个字节存储的顺序就可以有多种情况,比如每8个bit挨着存放,或者不挨着存放,显然后者是没有任何意义的,只会给自己添加麻烦,所以我们讨论前者。

内存的地址有低地址和高地址之分,二进制数有低位和高位之分(类似与十进制数的个十百千万),所以二进制存储方式就会有两种情况:
(1)小端存储——二进制数的低位存在低地址,高位存在高地址。
(2)大端存储——二进制数的低位存在高地址,高位存低地址。

三、特殊的指针的巧妙理解

3.1 数组指针


理解方法

数组-指针
数组是修饰指针的形容词
缩写下来,数组指针 就是 指针
所以在创建一个数组指针变量的时候就需要让这个变量先与*结合:
(*arrp)
如果这个指针指向一个有五个元素的数组:
(*arrp)[5]
这个被指向的数组中元素类型为整形:
int (*arrp)[5]
按照这个流程就可以轻松地理解和定义一个数组指针变量了

3.2 指针数组

理解方法

指针-数组
指针是修饰数组的形容词
缩写下来,指针数组 就是 数组
所以在创建一个指针数组变量的时候就需要让这个变量先与[]结合:
parr[]
如果这个数组含有5个元素,存储的元素都是指针:
*parr[5]
每个元素都是整形指针:
int *parr[5]
按照这个流程就可以轻松地理解和定义一个指针数组变量了

四、浮点型在内存中的存储方式

4.0 规定的由来

小数都有小数点,那么是否应该用数字来表示小数点呢?
小数点的部分转化为二进制的时候也常常无法精确地转换,如何最高效地提升精确度呢?
基于小数的一系列的问题,IEEE(电气电子工程师学会)发布了一个国际标准,下面一一介绍。
任何一个浮点数可以表示为如下形式

(-1)^S * M * 2^E
其中(-1)^S 决定正负号
M * 2^E 表示一个二进制数用科学计数法表示的形式
就先拿我们熟悉的十进制数进行举例
100.1 -> 1.001 * 10^2

再与二进制对比
101.0 -> 1.01 * 2^2

令S = 0,M = 1.01,E = 2

而我们发现M的取值范围是在[1,2)中,
所以储存M的时候只会保留小数点后的数字,
即保留01,等到读取的时候再将第一位的1加上。

由于E可能会出现负数的情况,故储存的时候需要加上一个中间值,
来保证E大于0,这个中间值和类型有关。
float类型的E加127
double类型的E加1023

最终上面的101.0f的S = 0, M = 01, E = 129

4.1 float型的存储

在这里插入图片描述
如果M位数不够,会补0到23位。

4.2 double型的存储

在这里插入图片描述

4.3 单独聊聊E

4.3.1 E为全0

对一个float类型相当于一个数的次方本来是-127,加上127显示出E为0,这个数显然是个无限趋于0的数。
这里直接规定,取出这种数字的时候,M不再加上之前去掉的1,直接还原为0.xxxxxxxxxxxxxx的小数。

4.3.2 E为全1

易知这是一个趋于无穷的数。

以上是关于高级程序员必备知识——数据在内存中的存储(常量字符串大小端特殊指针浮点型存储方式)的主要内容,如果未能解决你的问题,请参考以下文章

☀️ 学会编程入门必备 C# 最基础知识介绍——变量常量运算符判断循环

C语言中字符串常量到底存在哪了?

字符型数据在内存中是以啥形式存放的

实验九——基本数据类型存储及应用总结

实验九——基本数据类型存储及应用总结

Java中的字符串常量池