C语言----数据在内存中的存储(1)https://developer.aliyun.com/article/1544437
#include <stdio.h> int main() { char a[1000]; int i; for (i = 0; i < 1000; i++) { a[i] = -1 - i; } printf("%d", strlen(a));//255 return 0; } /* 因为这是一个char类型的数组,取值范围是-128~127的 -1 -2 -3 -4 ……………………-128 127 ……3 2 1 0 -1 -2 -3 -1到128是128个人元素,127到1是127个元素 那么总共就是255个元素了 因为strlen统计的是字符串中元素的个数, 并且检查的是'\0'之前的数 所以这个字符串数组内存在255个元素 */
#include <stdio.h> unsigned char i = 0;//全局变量 //因为这个char是unsigned char,无符号的char类型 int main() { for (i = 0; i <= 255; i++) { printf("hello world\n");//打印无限个 } return 0; } //因为前面有一个全局变量范围是0~255 //而循环的范围是i<=255,那么这个循环的条件恒成立,可以一直循环 //那么对于打印来说就是无限进行打印操作 //无限循环
#include <stdio.h> int main() { unsigned int i;//无符号整型,最小值是0 //对于这个循环来说,i>=0就恒成立了,这个循环就一直进行 for (i = 9; i >= 0; i--) { printf("%u\n", i); Sleep(100); } return 0; } /* 9 8 7 6 5 4 3 2 1 0 ---------- 0-1就变成-1了,-1被%u打印的时候将是一个非常大的数字 4294967295 …………………………下面就是非常大的数字了 */
#include <stdio.h> //X86环境 ⼩端字节序 int main() { int a[4] = { 1, 2, 3, 4 }; int* ptr1 = (int*)(&a + 1); //&a+1就是跳过一整个数组,指向这个数组的末尾 // // 将这个地址强制类型转换为int*赋值给ptr1,那么ptr1指向的就是这个数组的末尾 // ptr1[-1]---->*(ptr1-1) // 因为ptr1是整型指针,那么-1就是指向了4的位置,那么解引用得到的就是4 // // 那么4用16进制打印得到的还是4 // int* ptr2 = (int*)((int)a + 1); /* 这里的a是数组首元素的地址,那么被强制类型转换为整数类型, 那么(int)a+1就是+1 a是占4个字节的,但是被转换为整型了并且+1,那么现在就离开始的位置相差1个字节了 所以ptr2指向就是离首元素地址差1个字节的地址的位置 因为ptr2是整型指针,那么就是4个字节,从那个位置开始向后访问4个字节 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 所以就是从第2个00开始访问到02 00 00 00 02--因为这个地址在内存中是小端存在的, 所以原始的就是02 00 00 00 换成16进制的就是0x02 00 00 00 所以打印出来的就是2000000,最前面的0x0是不打印的 */ printf("%x,%x", ptr1[-1], *ptr2);//4,2000000 //%x是16进制的形式打印的 return 0; }
3.浮点数在内存中的存储
#include <stdio.h> int main() { int n = 9;//原反补相同 //00000000 00000000 00000000 00001001-----9 // // float* pFloat = (float*)&n; //取出n的地址并强制类型转换为float*类型的指针 //再赋值给pFloat,那么pFloat指向的就是二进制的起始位置 printf("n的值为:%d\n", n);//9 printf("*pFloat的值为:%f\n", *pFloat);//0.000000 //这个pFloat是浮点型指针, //站在*pFloat的角度上看,他会认为内存中存的是浮点数 // 那么这次就是以浮点数的形式取出这个值 // 因为整数和浮点数在内存中的存储形式不同 // 所以我们将二进制转换为S M E类型的进行读 // 0 00000000 00000000000000000001001 // S E M // 他会认为这个数是以S E M类型存在的 //E为全0的时候,那么是E+127=0,所以E就是-127 //那么这个数最后算出来就是一个正负无穷接近于0的数字 //那么打印出来的数是0.000000 *pFloat = 9.0; //1001.0---小数点向左移动3位,所以下面的科学计数法就是乘2的3次方 // 加上正负的处理的话(-1)^0 //科学计数法的形式:(-1)^0 * 1.001 * 2^3 // // S=0 // M=1.001 // E=3 // S=0 E=127+3=130 M--小数点后面的是001,还要满23个比特位,所以补上20个0 // 0 10000010 00100000000000000000000 // 所以9.0在内存中的二进制序列是01000001000100000000000000000000 // 其实是放到n的位置空间内了,因为pFloat指向的是n的起始位置 // /* 站在n的角度上,我们得到的科学计数法的数是补码 那么我们就要把原码算出来 因为高位是0,所以是正数,正数的原码补码反码相同 所以这个二进制换算的十进制的数就是1091567616 */ printf("num的值为:%d\n", n);//1091567616 printf("*pFloat的值为:%f\n", *pFloat);//9.000000 return 0; } /* 我们要清楚我们是以什么形式放进去的,怎么形式取出来的, 我以整数的形式放进去的,我以整数的视角取出来,那么就按照整数的视角计算原反补 我以浮点数的形式放进去的,我以浮点数的视角取出来,那么我们就按S M E相关的东西进行计算 不理解就看代码 */ /* 总之,就是浮点数和整数在内存中的存储方式是不同的 浮点数是S M E 我们可以利用二进制序列来得到这三个数据,进而得到我们浮点数在内存中的存储形式 */
常见的浮点数:3.14159、1E10--科学计数法
浮点数家族包括:float、double、long 、double类型
浮点数表示的范围:float.h中定义
整数和浮点数在内存中的存储方式是有区别的
10进制:5.5
2进制:101.1
5.5=(-1)^011.011*2^2
S=0
M=1.011
E=2
E是无符号的数
小数点后面的1就是表示2的负几次方,从-1开始
浮点数的存储,存储的就是S、M、E相关的值
对于32位的浮点数,最高的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M
对于64位的浮点数,最高的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M
1<M<2
在计算机内部保存M的时候,默认这个数的第一位总是1,因此可以被舍去,只保留后面的xxxx部分,xxxx部分表示小数部分
所以我们在存M的时候,一般存的都是小数点后面的位
10进制的0.5
2进制的0.1
科学计数法:1.0*2^-1
在存储E的时候还会添加中间值.float添加127
double添加1023
再将得到的值存在E的内存中
之前已经说过浮点数的存储,存储的就是S、M、E相关的值
取出来的三种情况:
1.正常存E的时候是E+中间值(127/1023),那么将这个取出来减去中间值就得到了E,对于M,将M取出+1就是我们要的M----这里的E不全为0或者不全为1
2.E为全0,那么取出来的E为-127,表示的就是正负无穷接近于0的数字
3.E为全1,如果全是1的话,那么刚好8个比特位,就是8个1,就是255
E+中间值(127)=255,那么E就是128
那么这个数也是一个正负无穷大的数字
int main() { float f = 5.5f; //S=0; //E=2 //M=1.011 //0 10000001 01100000000000000000000 //S E--129=(127+2) M--存的是小数点后面的-总共有23个比特位,那么剩下的20位补0 //0100 0000 1011 0000 0000 0000 0000 0000 // 11在16进制就是b // 4 0 b 0 0 0 0 0 // 0x40b00000--最后得到的数据--浮点数5.5在内存中得到的形式 //得到的二进制数每4个二进制位就能换一个16进制数 return 0; }