C语言题目与练习解析:配套《数据在内存中的存储》
- 🌈🌈🌈这里是say-fall分享,感兴趣欢迎三连与评论区留言
- 🔥🔥🔥专栏:《C语言入门知识点》、《C语言底层》、《精通C语言》
- 💪💪💪格言:今天多敲一行代码,明天少吃一份苦头
前言:
本篇是上一篇《数据在内存中的存储》的练习篇,为了缩减上一篇的篇幅,将练习篇特意摘出来供大家深入思考
文章目录
- 前言:
- 正文:
- 1.4.2 练习2
- 1.4.3 练习3
- 1.4.4 练习4
- 1.4.5 练习5
- 1.4.6 练习6
- 1.4.7 练习7
- 1.4.8 练习8
- 2.1.1 练习9
正文:
1.4.2 练习2
#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;
}
运行结果:
a=-1,b=-1,c=255
解析:
//char a = -1 一个字节
//a = 0x10000001
//----->补码:0x11111111
//----->整数提升,默认有符号,前面补1:0x11...11111111
//----->原码:10000...00000001----->最终结果:-1
//b与a同理,结果也为-1
//c与ab前面相同
//整数提升时前面补0:0x00...11111111
//----->原码与补码相同:0x00...11111111----->最终结果:255
1.4.3 练习3
#include <stdio.h>
int main()
{char a = -128;printf("%u\n",a);return 0;
}
运行结果:
4294967168
解析:
//char a = -128 一个字节
//好像一个字节无法放得下-128,那先让我们来看一下char(默认有符号)是如何储存的
实际上,我们可以看一下这个存储方式,每一个表格就代表了一个
bit
,在第一个数字代表的是符号位的情况下,我们就能发现除了0x10000000
以外,其他都很正常,可以理解为一个循环
其实在内部的定义里面这个
0x10000000
被认为是 -128 而非 “-0”
这样子的话这个-128就很好处理了
//a的补码:0x10000000
//----->整数提升:0x11...10000000
//----->输出:4294967168
为什么这里不需要再由原码转换为补码呢?
因为%u
是用于输出无符号整数的格式符,而无符号整数在计算机中没有原码、反码、补码的区分—— 它们的二进制表示就是其本身的数值形式,直接对应十进制的非负整数。
1.4.4 练习4
#include <stdio.h>
int main()
{char a = 128;printf("%u\n",a);return 0;
}
运行结果:
4294967168
解析:
//char a = 128 同样是一个字节
//存的也就是`0x10000000`,而如果以`%u`的形式输出,结果必然和上面是一样的
1.4.5 练习5
#include <stdio.h>
int main()
{char a[1000];int i;for(i=0; i<1000; i++){a[i] = -1-i;}printf("%d",strlen(a));return 0;
}
运行结果:
255
解析:
按照常规结果来说的话,大家一定认为是输出随机值,因为根本没有
\0
,但是别忘了我们刚才分析的有符号char
类型,这里当strlen(a)
=255时,这里的a[i]
此时也刚好为255,而再加1就会变成0(溢出)0x10000000
也就是说,在256之前就会循环停止,这就导致了输出255
1.4.6 练习6
#include <stdio.h>
unsigned char i = 0;
int main()
{for(i = 0;i<=255;i++){printf("hello world\n");}return 0;
}
运行结果:
hello world
hello world
hello world
...
//死循环
解析:
为什么会造成死循环呢?
我们知道无符号char的范围是0-255
而注意函数循环到最后是256,当 i = 256时,由于循环溢出就会导致归零,死循环就形成了
1.4.7 练习7
#include <stdio.h>
int main()
{unsigned int i;for(i = 9; i >= 0; i--){printf("%u\n",i);}return 0;
}
运行结果:
//对于运行结果想必大家也猜到了
9
8
7
6
5
4
3
2
1
0
4294967295
4294967294
//...循环
解析:
这个循环是怎么造成的呢?
其实就是当i = -1
的时候由于是无符号整型,就导致了实际上系统识别出来的是4294967295
从而造成了死循环
1.4.8 练习8
#include <stdio.h>
//X86环境 ⼩端字节序
int main()
{int a[4] = { 1, 2, 3, 4 };int *ptr1 = (int *)(&a + 1);int *ptr2 = (int *)((int)a + 1);printf("%x,%x", ptr1[-1], *ptr2);return 0;//%x意思是16进制输出
}
运行结果:
4,2000000
解析:
对于
*ptr1[-1]
来说,小端字节序,第一个&a
处存的就是4,而&a+1
处存的就是3,ptr1[-1]
处存的也就是4
对于*ptr2
来说,(int *)((int)a + 1)
将a处地址强转为int
类型,然后加1,再强转为int*
类型
仔细分析:(int*)(int)a+1
就相当于是在基础上向后偏移一个字节,这个字节由于小段排序,刚好就是 0x 02 00 00 00 ,这就导致了输出为2000000
2.1.1 练习9
#include <stdio.h>
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;
}
运行结果:
n的值为:9
*pFloat的值为:0.000000
num的值为:1091567616
*pFloat的值为:9.000000
解析:
//对于int n = 9用%d输出和*float = 9.0用%f输出,这两个都是正常输出
//而对于int n = 9用%f输出和*float = 9.0用%n输出,我们需要先了解一下浮点数的存储规则,这里只直接说明
IEEE 754规定:
- 对于32位的浮点数,最⾼的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M
- 对于64位的浮点数,最⾼的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M
即:
如图,float
类型浮点数在内存中是这样分配的
接下来我们正常分析 int n = 9是这样的存储的:
补码:00000000 00000000 00000000 00001001
解析时他会这样子:0 00000000 00000000000000000001001
即浮点数:1.084×10^-38
这样的话已经非常接近于0了,近似于0
同理:*pFloat = 9.0 是
补码:0 10000010 00100000000000000000000
直接%d输出的话就会自动识别为整型
即整数:1091567616
- 本节完…