作者:你我皆为凡人
博客主页:你我皆为凡人的博客
名言警句:时间不会为任何人停留,而事物与人,无时不刻也在变化着。每一个人,也都在不停向前!
觉得博主文章写的不错的话,希望大家三连(✌关注,✌点赞,✌评论),多多支持一下!!
系列作品:
C语言编程刷题篇
经典题型系列
目录
文章目录
前言
数据类型的介绍
整形在内存中的存储
原码,反码,补码
大小端介绍
一道经典笔试题
巩固练习
练习一
练习二
练习三
练习四
练习五
练习六
练习七
习题练习入口
本文重点讲解了数据类型的详细介绍与在内存中存放的数值,整形在内存中的存储以及原码反码补码的详细介绍,大小端字节序介绍及其判断,以及7道经典的题型让大家得以巩固知识
提示:以下是本篇文章正文内容,下面案例可供参考
前面我们已经学习了基本的内置类型:
#include
int main()
{
char 1字节 //字符数据类型
short 2字节 //短整型
int 4字节 //整形
long 4/8字节 //长整型
long long 8字节 //更长的整形
float 4字节 //单精度浮点数
double 8字节 //双精度浮点数
return 0;
}
类型的意义:
1,使用这个类型开辟内存空间的大小,而大小决定了使用的范围
2,决定了如何看待内存空间的视角
类型的基本归类:
整型家族:
char
unsigned char
signed char
short
unsigned short [int]
signed short [int]
int
unsigned int
signed int
long
unsigned long [int]
signed long [int]
浮点数家族:
float
double
构造类型:
数组类型
结构体类型 struct
枚举类型 enum
联合类型 union
指针类型:
int *pi;
char *pc;
float* pf;
void* pv;
空类型:
void 表示空类型(无类型)
通常应用于函数的返回类型、函数的参数、指针类型
int main()
{
int a = 20;
int b = -10;
return 0;
}
我们之前了解过一个变量的创建是要在内存中开辟空间的,空间大小是根据不同的类型而创建的,那么接下来我们谈谈数据在所开辟的内存中到底是如何存储的,比如上面的代码,我们知道a和b分配4个字节的空间,那么是如何存储的呢?
整数可以用二进制,十进制,十六进制,八进制表示,而在内存中是用二进制来展示,而整数的二进制表示有三种表示,原码,反码与补码
三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位用0或者1表示
对于负整数的三种表示方法各不相同:
原码:
直接将整数按照正负数的形式表示成二进制就可以
反码:
将原码的符号位不变,其他位依次安位取反就可以得到
补码:
反码+1就得到补码
正数的原,反,补码都相同
而对于整形来说,数据存放内存中其实存放的是补码
所以上图的代码在内存中的存储就是这样的:
int main()
{
int a = 20;
//20 正数
//00000000000000000000000000010100 原码
//00000000000000000000000000010100 反码
//00000000000000000000000000010100 补码
int b = -10;
//-10 负数
//10000000000000000000000000001010 原码
//11111111111111111111111111110101 反码
//11111111111111111111111111110110 补码
return 0;
}
二进制在内存中存储是32位比特位,太长了,一般在内存中以十六进制储存
那么转变过来就是:
int main()
{
int a = 20;
//20 正数
//00000000000000000000000000010100 原码
//0x00000014
//00000000000000000000000000010100 反码
//0x00000014
//00000000000000000000000000010100 补码
//0x00000014
int b = -10;
//-10 负数
//10000000000000000000000000001010 原码
// 0x800000a
//11111111111111111111111111110101 反码
// 0xffffff5
//11111111111111111111111111110110 补码
//0xfffffff6
return 0;
}
可是在内存中具体存放的是哪一个呢?正数的原码反码补码都相同,可是负数的原码反码与补码到底存放的是哪一个呢?接下来就明白了:
我们根据在内存中观察到的十六进制发现存放着的是补码
那么为什么呢?
在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统 一处理;同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。其实意思就是:1-1在计算机中会转换成1+(-1)那么如何计算呢?00000000000000000000000000000001 110000000000000000000000000000001 -1如果原码相加:10000000000000000000000000000010 -2 结果是错误的,无法计算如果补码相加:00000000000000000000000000000001 1的补码1111111111111111111111111111111111111 -1的补码相加结果:100000000000000000000000000000000 成为了33位比特位,而首位会丢弃,所以为0而补码与原码相互转换其运算过程是相同的,原码可以取反得到反码,反码+1得到补码,而同样,补码可以-1得到反码,反码取反回到原码,但是还可以补码取反+1得到原码比如:-101111111111111111111111111111011010000000000000000000000010011000000000000000000000001010
我们可以得出结论a与b分别存储的是补码,但是顺序好像有点不对劲,是反着来的,那么这又是为什么,这就涉及到大小端的概念了
什么是大端小端呢?:
大端【字节序】(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;小端【字节序】(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地址中;而在上面我们可以看到,内存中存放着是小端存储可是为什么会有大端和小端呢:为什么有大端和小端:为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为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处理器还可以 由硬件来选择是大端模式还是小端模式
这是一道百度2015年系统工程师笔试题
请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序
如1这个数字,无非就是 0x 00 00 00 01 与0x 01 00 00 00 这两种方式,区别在于第一个字节是否相同,那么如果我们取地址这个数是4个字节,那么强制转换为char类型就是1个字节,刚好是01或者00,而01就是1,00就是0,来进行判别
int main()
{
int a = 1;
if (*(char*)(&a) == 1)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
//输出什么?
#include
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类型的数值,在内存中有有符号与无符号之分,那么有符号在内存中存放的最大数值为127到-128之内,无符号在内存中存放的最大数值为0-255,那么short类型的呢?如果是无符号在内存中存放的最大数值为0到65535,如果是有符号在内存中存放的最大数值为-32768到32767,而其他的也可以按照二进制而推算出来
解析:
a的值是-1,存放到char类型中但是要以整形打印,-1的二进制为10000000000000000000000000000001 -1的源码
1111111111111111111111111111111111110 -1的反码
1111111111111111111111111111111111111 -1的补码
但是char类型中只能存放1个字节,就是8个比特位,发生了截断
11111111 a的值
%d的打印有符号的整形,所以要整型提升,有符号char根据符号位补齐
1111111111111111111111111111111111111 a的补码,但是打印的是源码
10000000000000000000000000000000
10000000000000000000000000000001 a的源码,也就是最后打印的数值 -1
同理,b的也是有符号char,所以也是-1
c是个无符号char,而无符号char在内存中只能存放0到255,那么如何存放-1呢?
10000000000000000000000000000001 -1的源码
1111111111111111111111111111111111110 -1的反码
1111111111111111111111111111111111111 -1的补码
截断:
11111111
注意无符号的char 整型提升直接补0
000000000000000000000000011111111 补码
而整数的正数原反补都相同,所以打印出来的数为255
#include
int main()
{
char a = -128;
printf("%u\n",a);
return 0;
}
char的取值范围在-128到127之间,而a的值在这个范围内,是有符号的char,而要以无符号类型打印出来
10000000000000000000000010000000 -128原码
111111111111111111111111111101111111 -128反码
1111111111111111111111111111110000000 -128补码
截断放入char a中
10000000 -a
整型提升,无符号直接打印1
11111111111111111111111110000000 a的值是一个非常大的数值 4,294,967,168
#include
int main()
{
char a = 128;
printf("%u\n",a);
return 0;
}
char的128不在char范围内,先写出原码
10000000000000000000000010000000
截断到char中
10000000
无符号打印,要整形提升,直接写1
11111111111111111111111110000000 a的值最后也是一个非常大的数值 4,294,967,168
int i= -20;
unsigned int j = 10;
printf("%d\n", i+j);
//按照补码的形式进行运算,最后格式化成为有符号整数
i是整数的-20
10000000000000000000000000010100 -20的原码
11111111111111111111111111101011 -20的反码
11111111111111111111111111101100 -20的补码
j是无符号整数10
00000000000000000000000000001010 10的补码
整数形式打印i+j
11111111111111111111111111101100 -20的补码
00000000000000000000000000001010 10的补码
相加后的结果:
11111111111111111111111111110110 相加后的补码
10000000000000000000000000001001 反码
10000000000000000000000000001010 最后的补码 打印的结果就是-10
unsigned int i;
for(i = 9; i >= 0; i--)
{
printf("%u\n",i);
}
定义i是一个无符号的整数,i为9,从9打印到0,然后0-1为-1,而无符号是没有负数的存在的,-1的补码是全1,这是一个很大的数字,往后会是一直打印死循环
int main()
{
char a[1000];
int i;
for(i=0; i<1000; i++)
{
a[i] = -1-i;
}
printf("%d",strlen(a));
return 0;
}
char数组里存放1000个元素,a【i】= -1-i;可能我们会想,那么最后的数字不就是-1,-2,-3.。。。到-1000,一千个数嘛 而strlen是求字符串的长度,关注的是字符串中\0(数字0)之前出现过多少字符,而这里面没有\0和数字0,所以是1000,这样想就大错特错了,char的取值范围是-128-127,从-1到-128,下一个会是127-0,那么-128到127之间会有255个数值所以答案是255
#include
unsigned char i = 0;
int main()
{
for(i = 0;i<=255;i++)
{
printf("hello world\n");
}
return 0;
}
定义一个无符号的char类型的i,i小于等于255,要跳出循环得是256,但是无符号char类型的i最大的存储数值为0到255,所以永远不会成为256,所以是死循环
看完这些不具体操作操作那么是不可以的,可以点击上方直达去练习一些有关习题,也可以随便看一看C语言的一些习题,练习练习选择题和编程题,让自己的知识得到巩固,直接点入标题就可直达,另外想获得大厂内推资格也可以去看看:
大厂内推