目录
1.数据类型介绍:
C语言内置类型:
char 字符数据类型
short 短整型
int 整形
long 长整型
long long 长长整形
float 单精度浮点数
双精度浮点型
数的类型分为两大类:
实型:float、double
整型:内置类型中实型类型之外的类型
还包括
char
unsigned char
signed char
short
unsigned short [int]
signed short [int]
int
unsigned int
signed int
long
unsigned long [int]
signed long [int]
还有三大特殊类型:
构造类型:
数组类型
结构体类型 struct
枚举类型 enum
联合类型 union
指针类型:
int* pi;
char* pc;
float* pf;
void* pv;
空类型:
void 表示空类型(无类型)。
通常应用于函数的返回类型、函数的参数。指针类型。
数在内存中是以补码的形式存储的,所以要了解原码、反码、补码对本篇文章是很重要的。
实型在计算机存储比较复杂,放在整型后面讲。
整型存储:
由两部分组成:符号位。数值位
符号位:只表示数的正负,不表示大小。在存储是最左边的一位。1表示 - ,0表示 + 。
例如:char类型 -1 ——10000001(2)最左边的1就是符号位。1 —— 00000001(2)最左边的0就是符号位。
数值位:一个数的绝对值的二进制形式。
三个码的概念:
原码:
直接将二进制按照正负数的形式翻译成二进制就可以。
反码:
将原码的符号位不变,其他位依次按位取反就可以得到了。
补码:
反码+1就得到补码。
对于正数来说,原码、反码、补码相同
对于负数来说,
反码 :原码符号位不变,其他位按位取反(这个不知道的可以先去学习一下逻辑运算符后面也要用)
补码:数值位 + 1.
红色为数在内存的存储,为什么是14 00 00 00 呢?int是4个字节 一个字节8个bit位,即int又32个bit位,一个16进制数字是可以表示4个二进制的数字即12(16)可以表示 0001 0002。可能又有人会问20 不是00 00 00 14 吗?这个等下再说,这个和大小端存储方式有关,先不管这个,先知道是倒着存就行,一会文章后面会有解答。
这个b是逆推的先-1在符号位不变其他位取反。
2.大小端存储方式:
概念:
大端(存储)模式:
是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中。
小端(存储)模式:
是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地址中。
我就不讲为什么这样存了,有点脱离文章,如果感兴趣可以去找相关资料。
我用的Visual Studio 2019 软件是小端存储方式。所以我能够表示小端存储方式,大端存储方式其实还是简单的。
例如:
a = 1 ,a的补码为0000 0000 0000 0000 0000 0000 0000 0001,即00 00 00 01(16)。
正数的原码、反码、补码相同。
为什么是两个16进制数字是连着存的?之前说过一位16进制数字可以表示4位二进制数字,两位16进制数字可以表示8位二进制,即8个bit,即1个字节,计算机的存储最小单位是字节,所以是两个16进制位存在一起。
b = -5,b的补码1111 1111 1111 1111 1111 1111 1111 1011(2),即ff ff ff fb(16).。
数的是大端方式还是小端存储是怎么判断的呢?
我们可以用代码来观察计算机的存储方式:
1.用函数实现:
#include<stdio.h>
int W()
{
int a = 1;
//第一种方式
//char* p = &a;
//return *p;
//第二种方式
return *(char*)&a;
}
int main(void)
{
if (W() == 1)
{
printf("小端存储\n");
}
else
{
printf("大端存储\n");
}
return 0;
}
运行结果:
2.用联合体实现
(如果不知道联合体是什么可以先去学习一下,以后可能会分享结构体联合体相关的知识,但是估计要过一段时间了,所以要想知道下面的代码是怎么实现的先其他地方去学一下,反正不是很难)
#include<stdio.h>
union W
{
int a;
char c;
};
int main(void)
{
union W p;
p.a = 1;
if (p.c == 1)
{
printf("小端存储\n");
}
else
{
printf("大端存储\n");
}
return 0;
}
运行结果:
实型的储存规则:
根据国际标准IEEE(电气和电子工程协会) 754,任意一个二进制浮点数V可以表示成下面的形式:
* (-1)^S * M * 2^E
* (-1)^s表示符号位,当s=0,V为正数;当s=1,V为负数。
* M表示有效数字,大于等于1,小于2。
* 2^E表示指数位。
因为M是1到2之间的小数,所以为了M表示1.后面的数,即小数点后面的数。
float:
double:
S/E/M都是无符号的二进制,所以为了防止E小于0,标准规定储存时要让E加上127.
实例演示:
一:
二:
三:
较难的四:
1.
2.
3.
4.
5.
尝试实现计算机的加减:
思路:
代码如下:
#include<stdio.h>
int main(void)
{
int a = -98789;
//01010
int b = -3;
//10100
//int arr[32] = { 0 };
//int brr[32] = { 0 };
//for (int i = 0; i <= 31; i++)
//{
// arr[i] = (a >> i);
// brr[i] = (b >> i);
//}
//1 << (1 + i) 1073741824 int
int sum = 0;
for (int i = 31; i >= 0; i--)
{
if (((a >> i) & 1) + ((b >> i) & 1) == 2)
{
sum += (1 << (1 + i));
if (i == 31)//这个不理解 其实我也不太理解就是调试的时候发现的看看最后两幅图
{//主要是考虑负数 因为正数i = 31时是0 不用考虑
sum--;
}
}
else
{
sum += ((((a >> i) & 1) || ((b >> i)) & 1) << i);
}
}
printf("%d\n", sum);
//printf("%d\n", 1 << (32));
return 0;
}
运行结果:
测试的是a = -1, b = -1;
不知道为什么加了个1,就很离谱。有知道的大佬可以在评论区讲解一下或者出一篇文章,@我一下。🙏🙏🙏
为什么不放0或正数相加,因为比较简单,我已经成功了,放太多图还不如自己去试一下,我实验已成功。
放一道题:
代码如下:
int Add(int num1, int num2 ) {
// write code here
int n1, n2;
n1 = (num1 & num2) << 1;
n2 = num1 ^ num2;
while (n1 & n2)
{
num1 = n1; num2 = n2;
n1 = (num1 & num2) << 1;
n2 = num1 ^ num2;
}
return n1 | n2;
}
好吧~
这不是我写的,想了好几天,最终我看评论了,这是一个人的Java代码我让给粘贴来了。确实是神人,没事我也是抬着头看着这个人的。
最后要说的话:
文章有的知识点没讲,例如位运算,联合体。还有一个没解决的问题——就是实现计算机的运算的时候(两个数是负数)sum 第一位 加了1。真的感觉写一篇文章要涉及的知识太多了。