【C语言】数据类型存储、原码,反码,补码

简介: 是这个类型一旦确定之后就决定了它的内存空间的大小,也决定了它的这个范围有多大。举个例子就像:当你把一个变量a的值赋值给了int整形,那么它的存储大小就是4个字节取值的

类型的意义:

      使用这个类型开辟的内存空间的大小,从而大小也决定了范围。

就是这个类型一旦确定之后就决定了它的内存空间的大小,也决定了它的这个范围有多大。举个例子就像:当你把一个变量a的值赋值给了int整形,那么它的存储大小就是4个字节取值的范围就是 -32768~32767。

注意,各种类型的存储大小与系统位数有关,但目前通用的以64位系统为主。

C语言的类型分为

基本类型:

它们是算术类型,包括两种类型:整数类型和浮点类型。

枚举类型:

它们也是算术类型,被用来定义在程序中只能赋予其一定的离散整数值的变量。

void 类型:

类型说明符 void 表明没有可用的值。

派生类型:

它们包括:指针类型、数组类型、结构类型、共用体类型和函数类型。如何看清楚一个内存空间的视角,这个其实就是假设你

如何看待内存空间的视角:int的类型创建一个变量(a),占了4个字节, float类型创建一个变量(b),同样也只是占了仅仅4个字节的空间。但是给变量a的是格式符%d是一个整形,而给变量b的是格式符%f是一个单精度浮点型。

注意它们的存储的方式并不一样,大家可以在编译器上用调试内容一看就知道它们的内存是不同的

用 int a = 5;float b = 5.0; 用调试到内存那里就有了。

内存是计算机中一个主要部件, 用于保存进程运行时的程序和数据,也称可执行存储器。在计算机中,内存空间一般是指主存储器空间(物理地址空间)或系统为一个用户程序分配内存空间。扩展内存空间的方法一般有增加内存大小和虚拟内存。

在这里其他类型我就不跟大家讲解了,就说说构造类型,以及指针类型吧。

构造类型

数组类型:为什么说数组类型是构造类型呢?是因为假设 int arr[20],这样看是数组类型是吧。那么int [20] 是类型吧,那么我再进行一个改变int [10] 这个类型都在发生改变 那么如果你是不同的类型呢字符型,浮点型这样,所以数组也是一种自定义类型也是构造类型。

结构体类型:struct,成员类型在发生变化,那么它的结构体也在发生着变化。如果对结构体不了解的小伙伴们可以看看我文章里面有这个结构体的内容。

枚举类型:enum,这个是C语言的一个关键字,到时候会拿出写一篇给大家着重讲解这个枚举类型在C语言当中起到一个什么样子的作用。

联合体类型:union,这个也叫做是共用体,这个我们也现在不说。

指针类型

指针的目的其实就是为了存放一个地址赋值给其中的变量,而指针的字节都是4个字节。

这样我们用一段代码让大家直观的看看是不是指针是4个字节,由于博主再前面跟大家讲过野指针的内容但是指针的内容还没有跟大家说,到时候博主也会写一篇有关于指针的内容,由此可见指针类型是一种特殊的类型。注意一下,指针的定义方式就是带*💨

#include<stdio.h>
int main(void)
{
  int a = 10;
  int* p = &a;        //整形指针变量p接收a的地址
  //这里数据类型全部定义成指针了-- 32位 4byte 64位 8byte
  printf("%d\n", sizeof(int*));
  printf("%d\n", sizeof(short*));
  printf("%d\n", sizeof(double*));
  printf("%d\n", sizeof(char*));
}

运行结果:

image.png

空类型

一种特殊的返回类型,表示空函数,也就是没有返回值的函数。空类型(无类型) void 用于显示说明一个函数不返回任何值。还可以说明指向 void 类型的指针,说明以后,这个指针就可指向各种不同类型的数据对象💫

void无传参,当你在定义程序的时候加入无传参的时候,虽说程序也会运行起来。但是会有waring提示就是不需要的参数

函数的返回类型☮

#include<stdio.h>
void print()
{
    printf("hello word\n");
}
int main(void)
{
    print();
}

函数的参数☪

#include<stdio.h>
void print()//无参数的话进行传参也是可以的,但是这里没有所以我们C语言并不会进行接收
{
    printf("hello word\n");
}
int main(void)
{
    print(10);//在print函数当中给上参数10
}

整形在内存当中的存储空间

想要了解这个内容的话,我用一段代码给大家演示下:

#include<stdio.h>
int main(void)
{
    int a = 5;
    int b = -3;
}

a存储的结果

image.png

b存储的结果

image.png

大家发现了没有,这两个的存储结果是不一样的,接下来我就来告诉大家整形在内存当中是怎么存储的。

其实就是先要了解原码,反码,以及补码的概念。

计算机中有符号数(整形)有三种表示方法分别是:原码,反码以及补码。三种表示方法都有符号位和数值位两个部分,符号位是用0表示位"正",用1表示为"负",而数值位的三种表示方法各不相同。注:无符号的原码反码以及补码是相同的💨。

有符号数字是分为两种的一种叫做正数,另一种叫做是负数。在正数当中是相同的,然而在负数当中这三种的表达方式就不一样了💨

image.png

  • 上面的是负数形式三种情况,...........这个是省略如果是整形前面32位数字,注意这里最高位是1,所以是负数的三种形式。

原码

  • 直接将数字按照正数或者负数形式来转换翻译成二进制就可以了💨
int a = 5;//4个字节 —— 32bit位
//0(最高位正数)0000000000000000000000000000101
int b = -3;
//1(最高位负数)1111111111111111111111111111101

其实还有一个办法可以算补码我一开始就是这样的:

1、假设是负数1的补码你先看成是负数1原码的数字—10001(注意这里的最高位是1,是负数)

2、再直接反码注意最高位不用反码了——11110

3、最关键的一步就是补码了切记补码最后一位加1是1就往前面一位数字进1,结果就是——11111

当然这个是笨办法,如果不能理解的话用这个也是可以的我一开始就是这样😂

反码

将你的符号位不变,也就是最高位不变,其次再依次的按位取反,得到反码。

比如 int = - 10;的反码就是—11111111111111111111111111110101

补码

补码就是 反码+1 就能够得到补码,注意是前提是要反码加一💨

还是 比如 int = - 10;的补码就是—11111111111111111111111111110110

这里注意一下是满2进1,不要弄错了~!

如果它是正数的话:原码、补码以及反码都是相同的!

是负数的话就是我上面说的这样!对于整形来说存放的都是补码,切记!

一个字节=8个bit

为什么在计算机中存储的是补码?

在计算机的系统当中,数值都是用补码来表示存储的。原因在于,使用补码,可以将符号位和数值域进行统一的处理;同时,加法和减法当中用补码也可以进行统一的处理(CPU当中只有加法器),此外,尤其是补码与原码的运算过程是可以进行相互转换的!

那么我着重的跟大家说说这个加法器吧,这个加法器其实就是当中CPU运用的加法运算,好接下来我给大家举个例子比如说:1 - 1 那你要转换成加法器怎么办呢?其实很简单只需要:1 + (-1) 就可以了,那么如果你现在要用原码来算呢?

1的原码: 00000000000000000000000000000001

-1的原码: 10000000000000000000000000000001

   结果:    10000000000000000000000000000010      所以,1+(-1) = -2吗?答案显然不是的

好!那现在如果我们用补码来算一下呢

1的补码:  1000 0000 0000 0000 0000 0000 0000 0001

-1的补码:  1111 1111 1111 1111 1111 1111 1111 1111 1111

   结果:   1 0000 0000 0000 0000 0000 0000 0000 0000

但是:我们整形当中只能存储的是32位,所以留下的是0,所以用补码进行运算的时候我们是可以算出一个正确的结过的,想到这,我真的觉得当时创作出这个算法的人估计是个神仙吧😯,乘法就是^几次放就加多少,也有可能是转换成某一个运算吧。但是原理都是一样的就是我只要有加法,这些事情我都可以办到。

大端小端介绍:

大端:存储模式是指内存中的低位保存在内存当中的高地址当中,而数据的高位,保存在内存的低地址当中。

小端:存储模式是指数据中的低位保存在内存当中的低地址当中,而数据的高位,保存在内存的低地址当中。

内存空间都是有编号的,我们都把内存的低位叫做低地址,编号大的话那么就是叫做高地址,数据是怎么样存储都是可以的,但是当返回到你的程序当中必须要是怎么样存储回来比如说你整形存储的是 11 22 44 33 (二进制转换十六进制 1个字节=4个bit位),那么你到时候就也是需要这样整形存储出来的 11 22 44 33 !但是我们通常都不会这样去存储内存。通常都是两种存储方法一种叫做大端的存储模式还有一种是小端的存储模式。

假设是:0x11223344,这个44就是低位,而11就是高位,那么这个低位要保存到内存的高地址数,而数据的高位保存在低地址处——大端

再次假设:0x44332211,这个44就是低位,而11就是高地址,低字节的数据保存在内存当中的低地址处,而高字节的数据就保存在高地址处——小端

判断大端小端

用代码实现判断大端小端:

解体思路:一个数字a,存储在内存当中,假设这个a是20的话,在不知情的情况下,不知道当前是大端还是小端的存储。但是,可以推测是不是大端还是小端,就像上面内容所说的那样。我们可以观察它们的第一个字节,就比如说:

int a = 1;

小端:0x01 00 00 00  

大端:0x00 00 00 01

代码演示  

#include<stdio.h>
int main(void)
{
  int a = 1;
  char *p = (char*)&a;
  if (*p == 1)
  {
    printf("小端\n");
  }
  else
  {
    printf("大端\n");
  }
  return 0;
}

自定义函数代码

#include<stdio.h>
int Testing()
{
  int a = 1;
  char * pb = (char*)&a;
  if (*pb == 1)
    return 1;
  else
    return 0;
}
int main(void)
{
  int ret = Testing();
  //返回1代表的是小端,返回0代表的是大端
  if (ret == 1)
  {
    printf("小端\n");
  }
  else
  {
    printf("大端\n");
  }
  return 0;
}

在这里说下指针类型的意义

指针类型决定了指针解引用访问多少个字节,比如:char *p;那么这里*p只能访问一个字节,根据你自己定义的数据类型💨

指针类型决定了指针+1,-1的是几个字节,比如:char * p + 1;那么跳过的是一个字节 根据数据类型来判断 int就是4字节

注意:整形提升补的是最高位的符号位,'0'为正,'1'为负 💨

浮点型在内存当中的存储

常见的浮点数:

3.14 、1E10(这个其实就是1.0✖10的10次方—E)

浮点数包括:

C语言中的浮点类型有float、double 和 long double 类型。

记数法实例:

image.png

第1列是一般记数法;

第2列是科学记数法;

第3列是指数记数法(或称为e记数法);

这是科学记数法在计算机中的写法,e后面的数字代表10的指数;

接下来给大家看一个代码:

#include <stdio.h>
int main(void)
{ 
  int n = 9;
  float *pFloat = (float *)&n;
  printf("*pFloat的值为:%d\n",n);
  printf("*pFloat的值为:%lf\n", *pFloat);
  *pFloat = 9.0;
  printf("num的值:%d\n", n);
  printf("*pFloat的值为:%lf\n",*pFloat);
  return 0;
}

运行结果:

image.png

从上述代码可以看出:浮点型和整形的内存的存储的形式不一样!

可能会有些小伙伴有些疑问,为什么第二行运行结果的*pFloat的答案是:0.000000,还有第三行的num的运行结果是:1091567616,我觉得因该是 9.000000 和 9啊。好,别着急现在就来说说为什么!

打印:0.000000是因为:整形的形式放进去的时候在以浮点数的形式往后拿的话,拿不到我们期望的一个结果,那是不是可以说明整形的存储结果和浮点型的存储的方式是不一样的,如果一样那就是一样的结果了✨

打印:1091567616是因为:*pFloat我们是用浮点数的形式存放进去的,然后以n的正数形式在拿的时候是整数的形式拿出来的,拿出来了一个错误的值✨

从这里就说明了整形的存储方式和浮点型的存储方它们是由区别的💨

浮点数二进制补码

例如:7.0 — 0111 — 0111.0(小数点后面给个0就可以了) 这就是7.0的二进制的表现形式😉

任何一个二进制的浮点数V可以表示成下面的形式:

(-1)^ M * 2 ^ E

(-1)^ s表示符号位,当s = 0的时候,V = 正数(除了0以外,任何数的0次方等于1)当s=1的时候,V = 负数

M表示的是有效数字,大于等于1,小于2

2 ^ E表示指数位

存储模式图:

image.png

如下实例:浮点数9.0

   1001

   1001.0

   1.001 * 2 ^ 3  —— 注意:这个是二进制

   (-1) ^ 0 * 1.001 * 2 ^ 3  = (-1)^ M * 2 ^ E

   0 10000010 00100000000000000000000  —— E = 3 + 127 = 130

   当成原码直接打印的就是我们上面说的数字 1091567616

   这样就可以确定的是 — s = 0 ,M = 1.001 ,E = 3 ,注意M = 1.001 实际上是:0001

如下实例:浮点数0.5

   0.5

   0.1 — 注意:这个是二进制当中的 -1 对于小数点来说后面的第一位数,是2的负一次方就是0.5

   1.0 *  2 ^ -1 —— 转换成科学计数法

   (-1 ^ 0) * 1.0 * 2 ^ -1  —— 注意:指数E为一个无符号数字来看待的

   s = 0,M = 1.0,E = -1

对于八位的E来说是,这个中间的数是:127,对于十一位的E来说是,这个中间数是1023,其实就是如果你的E是负数的话,就拿-1来举个例子 八位的就是:-1+127 = 126,11位的就是:-1+1023 = 1022

E不为全0也不为全1

浮点数 5.5

101.1   // 前面是101按照8421码来,后面的就是2的负一次方 等于 0.5

(-1) ^ 0 * 1.001 * 2 ^ 2

s = 0 ,M = 1.011 ,E = 2 (E+127=129)

0100 0000 1011 0000 0000 0000 0000 0000 ——这里E的存储是129,E的值还是129-127=2,如果你是double的数字那么这里要减去1023才能的到真实的E的值

0x40B00000 —— 转换出来的二进制转换十六进制数字

调试当中内存的结果:

E全为0 (了解即可)

这时,浮点数的指数E等于1-127(或者1-1023)即为真实值,有效数字M不再加上第一位的1,而是为了还原位0.xxxxxx的小数,这样做是为了表示±0,以及接近于0的很小数字。

E全为1 (了解即可)

这时,如果有效数字M全为0,表示±无穷打(正负取决于符号位s)

目录
相关文章
|
2月前
|
存储 编译器 C语言
C语言存储类详解
在 C 语言中,存储类定义了变量的生命周期、作用域和可见性。主要包括:`auto`(默认存储类,块级作用域),`register`(建议存储在寄存器中,作用域同 `auto`,不可取地址),`static`(生命周期贯穿整个程序,局部静态变量在函数间保持值,全局静态变量限于本文件),`extern`(声明变量在其他文件中定义,允许跨文件访问)。此外,`typedef` 用于定义新数据类型名称,提升代码可读性。 示例代码展示了不同存储类变量的使用方式,通过两次调用 `function()` 函数,观察静态变量 `b` 的变化。合理选择存储类可以优化程序性能和内存使用。
158 82
|
1月前
|
存储 C语言
【c语言】数据类型和变量
本文介绍了C语言中的数据类型和变量。数据类型分为内置类型和自定义类型,内置类型包括字符型、整型、浮点型等,每种类型有不同的内存大小和取值范围。变量分为全局变量和局部变量,它们在内存中的存储位置也有所不同,分别位于静态区和栈区。通过示例代码和图解,详细阐述了这些概念及其应用。
42 1
|
1月前
|
C语言
3.4 C语言基本数据类型2
在C语言中,声明一个整型(int)变量时,需先写入&#39;int&#39;关键字,后跟变量名并以分号结尾。若同时声明多个变量,可在&#39;int&#39;后用逗号分隔列出所有变量名。例如,`int erns;` 或 `int hogs, cows, goats;` 都是合法声明。变量声明后需通过赋值语句如 `cows = 112;` 或使用函数如 `scanf()` 来初始化其值。
44 10
|
1月前
|
存储 程序员 C语言
3.1 C语言基本数据类型
在C语言中,整数类型如`int`类型是很有用的,它属于有符号整型,意味着该类型的值必须是整数,并且可以是正整数、负整数或者零。`int`类型的数值范围依据计算机系统有所不同,通常取决于系统的位宽。例如,在早期16位的IBM PC兼容机上,`int`类型使用16位存储,取值范围为-32768至32767;而在当前32位系统中,使用32位存储,拥有更宽泛的取值范围。随着64位处理器的普及,`int`类型能够存储的整数范围将进一步扩大。根据ISO C标准,`int`类型的最小取值范围被规定为-32768到32767。系统通常会利用一个特殊的位来表示整数的正负。
34 10
|
1月前
|
C语言
3.1C语言基本数据类型
在C语言中,初始化变量是指为变量设定初始值,通常在声明时直接完成,例如 `int cows=32;`。应注意避免在同一语句中混合初始化与未初始化的变量,如 `int dogs, cats=94;` 这样的写法容易引起误解。此外,整型常量如21、32等在C语言中被视为int类型,但非常大的整数则不然,且带有小数点或指数的数值不属于整型常量。
28 9
|
1月前
|
存储 C语言
深入C语言内存:数据在内存中的存储
深入C语言内存:数据在内存中的存储
|
1月前
|
存储 C语言
初识C语言:常量与变量中寻找数据类型
初识C语言:常量与变量中寻找数据类型
|
2月前
|
存储 C语言 索引
C 语言数据类型详解
C语言中的数据类型主要包括基本数据类型、构造数据类型和用户定义数据类型。基本类型如整型(`int`)、字符型(`char`)、浮点型(`float`)、双精度浮点型(`double`)和无符号整型(`unsigned int`)。构造类型包括数组(`Array`)、结构体(`Struct`)、共用体(`Union`)和枚举(`Enum`)。用户定义类型则通过`typedef`为已有类型定义新名称,并可通过结构体和共用体自定义复合数据结构。此外,还有指针类型用于存储变量地址,以及`signed`、`unsigned`、`short`、`long`等类型修饰符。
95 11
|
2月前
|
存储 C语言
【C语言基础考研向】02 数据类型-常量-变量
本文介绍了编程中的基本概念,包括数据类型分类、常量与变量的定义及使用。首先概述了四大类数据类型:基本类型(整型、浮点、字符型)、构造类型(数组、结构体)、指针类型和空类型。接着阐述了常量与变量的区别及命名规则,并详细说明了整型、浮点型和字符型数据的特点与应用。最后总结了常见的易错点,如字符串与字符常量的区别及浮点数的默认输出格式。
|
2月前
|
存储 人工智能 C语言
数据结构基础详解(C语言): 栈的括号匹配(实战)与栈的表达式求值&&特殊矩阵的压缩存储
本文首先介绍了栈的应用之一——括号匹配,利用栈的特性实现左右括号的匹配检测。接着详细描述了南京理工大学的一道编程题,要求判断输入字符串中的括号是否正确匹配,并给出了完整的代码示例。此外,还探讨了栈在表达式求值中的应用,包括中缀、后缀和前缀表达式的转换与计算方法。最后,文章介绍了矩阵的压缩存储技术,涵盖对称矩阵、三角矩阵及稀疏矩阵的不同压缩存储策略,提高存储效率。
402 8