C语言-数据的存储-整形的存储(8.1)

简介: C语言-数据的存储-整形的存储(8.1)

思维导图:



1.数据类型的基本归类

1.1类型的意义

C语言中的各种类型,所占的内存空间不同。


而类型的意义,就是在创建类型时


使用这个类型开辟的内存空间


以及看待内存的视角(不同类型在内存中存储的方式是不同的)


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]


char 也是整形家族的一员!!!


平时我们都直接使用short、int 等等,一般我们习惯将[ ]里 的省略,当然,不省也不会报错。


long long 也是同理



1.3浮点数家族

float

double


1.4构造类型

数组类型


结构体类型 struct

枚举类型 enum

联合类型 union


数组类型也属于构造类型


例:


int arr[10]
  int[10]
  int a[11]
  int[11]

int arr[10] 的类型其实是 int [10]


同理int a[11] 的类型时 int [11]


每个不同的数组都是不同的类型。



1.5指针类型

int *p
char *p
float* p
void* p



1.6空类型

void 表示空类型(无类型)

通常应用于函数的返回类型、函数的参数、指针类型


例:


#include 
void test()
{
  printf("hehe\n");
}
int main()
{
  test();
  return 0;
}

输出:


输出:hehe

2. 整形在内存中的存储

大致了解C语言中的数据类型后,我们重点学习整形家族在内存中的存储。



2.1 原码、反码、补码

一个变量的创建是要在内存中开辟空间的,


而开辟空间的大小是有类型决定的,


那么,数据究竟是如何在内存中存储的呢?


计算机中的整数有三种二进制的表示方法:


即:


1.原码


直接将数值按照正负数的形式翻译成二进制就可以得到原码。


int a = 1;//原码:00000000000000000000000000000001

2.反码


将原码的符号位不变,其他位依次按位取反就可以得到反码。


int b = -1;//原码:10000000000000000000000000000001

           //反码:11111111111111111111111111111110

3.补码


反码+1就得到补码。


int b = -1;//原码:10000000000000000000000000000001

           //反码:11111111111111111111111111111110

     //补码:11111111111111111111111111111111

三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,


第一位就是符号位,剩下是数值位。


正数的原、反、补码都相同。


我们到内存中看看:



我们发现内存是以补码的形式存储的


而且我们发现a的地址有些奇怪,为什么好像是反着存的,又不完全反着。



2.2 大小端介绍

其实,在计算机中是存在大小端的存储方式的


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



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


大小端字节序存储是以字节为单位存储的:


例:



上文中&a在内存中存储的方式是 01 00 00 00 以字节为单位逆序存储,是小端存储的方式。


那我们该如何判断所处环境究竟是大端还是小段呢?


例1:


#include 
int main()
{
  int a = 1;
  char* pa = (char*)&a;
  if (*pa == 1)//通过观察内存中第一个字节是否为1
  {            //从而判断大小端
  printf("小端\n");
  }
  else
  {
  printf("大端\n");
  }
  return 0;
}


我使用的VS2019是小端环境


输出:

输出:小端

例2:

#include 
int check()
{
  int a = 1;
  return *(char*)&a;//如果是小端返回1
}                     //如果大端则返回0
int main()
{
  int ret = check();
  if (ret == 1)
  {
  printf("小端\n");
  }
  else
  {
  printf("大端\n");
  }
  return 0;
}

当然,我们也可以使用函数的方法实现:


/

输出:


输出:小端


2.3 练习、巩固、提高

练习1:


//输出什么?
#include 
int main()
{
  char a = -1;
  signed char b = -1;//在这里的 signed char b 和 char a 其实是相同的
  unsigned char c = -1;
  //signed char 能够存储的大小是 -127 ~ 128
  //unsigned char 能够存储的大小是 0 ~ 255
  //如果遇到-1:
  //原码:10000000000000000000000000000001
  //反码:11111111111111111111111111111110
  //补码:11111111111111111111111111111111
  //截断:11111111
  //对于无符号类型来说,原返补码相同
  //所以最后的大小为 11111111
  //用十进制输出则为 255
  printf("a=%d,b=%d,c=%d", a, b, c);
  return 0;
}


输出:


输出:a=-1,b=-1,c=255

练习2:


#include 
int main()
{
  char a = -128;
  //原码:10000000000000000000000010000000
  //反码:11111111111111111111111101111111
  //补码:11111111111111111111111110000000
  //截断:10000000
  printf("%u\n", a);
  //通过无符号整形的方式打印
  //整形提升:
  //高位补符号位:11111111111111111111111110000000
  return 0;
}


输出:


输出:4294967168

练习3:



/

#include 
int main()
{
  char a = 128;
  //原码:00000000000000000000000010000000
  //反码:00000000000000000000000010000000
  //补码:00000000000000000000000010000000
  //截断:10000000
  printf("%u\n", a);
  //通过无符号整形的方式打印
  //整形提升:
  //高位补符号位:11111111111111111111111110000000
  return 0;
}

输出:


输出:4294967168

练习4:


#include 
int main()
{
  int i = -20;
  //原码:10000000000000000000000000010100
  //反码:11111111111111111111111111101011
  //补码:11111111111111111111111111101100
  unsigned int j = 10;
  //补码:00000000000000000000000000001010
  //补码相加:11111111111111111111111111110101
  //以整形原码打印:10000000000000000000000000001010
  printf("%d\n", i + j);//转成十进制:-10
  return 0;
}


输出:


输出:-10

练习5:


#include 
int main()
{
  unsigned int i;
  for (i = 9; i >= 0; i--)
  {
  printf("%u ", i);//会先打印 9 8 7 6 5 4 3 2 1 0
  }                    //当-1时,用unsigned int形式打印会进入死循环打印很大的数
  return 0;            //i永远无法小于0
}

输出:



练习6:


#include 
int main()
{
  char a[1000];
  int i;
  for (i = 0; i < 1000; i++)
  {                 //char 类型大小:-127~128
  a[i] = -1 - i;//i从0 1 2...128 -127 -126...-3 -2 到-1时,arr[i]=0
  }                 //总共是255个数
  printf("%d", strlen(a));//strlen 遇到'\0'就会停下
  return 0;
}

输出:


输出:255

练习7:


#include 
unsigned char i = 0;
int main()
{
  for (i = 0; i <= 255; i++)
  {
  printf("hello world\n");//因为 unsigned char 的范围是 0~255
  }                           //所以 i 永远无法大于255,导致死循环
  return 0;
}

输出:


输出:死循环打印 hello world

写在最后:

以上就是本篇文章的内容了,感谢你的阅读。


如果喜欢本文的话,欢迎点赞和评论,写下你的见解。


如果想和我一起学习编程,不妨点个关注,我们一起学习,一同成长。



相关文章
|
1月前
|
存储 程序员 编译器
C 语言中的数据类型转换:连接不同数据世界的桥梁
C语言中的数据类型转换是程序设计中不可或缺的一部分,它如同连接不同数据世界的桥梁,使得不同类型的变量之间能够互相传递和转换,确保了程序的灵活性与兼容性。通过强制类型转换或自动类型转换,C语言允许开发者在保证数据完整性的前提下,实现复杂的数据处理逻辑。
|
1月前
|
存储 数据管理 C语言
C 语言中的文件操作:数据持久化的关键桥梁
C语言中的文件操作是实现数据持久化的重要手段,通过 fopen、fclose、fread、fwrite 等函数,可以实现对文件的创建、读写和关闭,构建程序与外部数据存储之间的桥梁。
|
2月前
|
存储 数据建模 程序员
C 语言结构体 —— 数据封装的利器
C语言结构体是一种用户自定义的数据类型,用于将不同类型的数据组合在一起,形成一个整体。它支持数据封装,便于管理和传递复杂数据,是程序设计中的重要工具。
|
2月前
|
存储 编译器 数据处理
C 语言结构体与位域:高效数据组织与内存优化
C语言中的结构体与位域是实现高效数据组织和内存优化的重要工具。结构体允许将不同类型的数据组合成一个整体,而位域则进一步允许对结构体成员的位进行精细控制,以节省内存空间。两者结合使用,可在嵌入式系统等资源受限环境中发挥巨大作用。
79 11
|
3月前
|
存储 C语言 C++
深入C语言,发现多样的数据之枚举和联合体
深入C语言,发现多样的数据之枚举和联合体
深入C语言,发现多样的数据之枚举和联合体
|
3月前
|
存储 C语言
C语言中的浮点数存储:深入探讨
C语言中的浮点数存储:深入探讨
|
3月前
|
存储 C语言
深入C语言内存:数据在内存中的存储
深入C语言内存:数据在内存中的存储
|
3月前
|
C语言
回溯入门题,数据所有排列方式(c语言)
回溯入门题,数据所有排列方式(c语言)
|
8月前
|
存储 C语言
C语言中的数据输入输出
C语言中的数据输入输出
107 0
|
缓存 C语言
C语言——数据的输入输出
C语言——数据的输入输出