数据类型存储空间大小详解(C语言)

内存空间运算符sizeof

每⼀种数据类型都有⾃⼰的⻓度,使⽤不同的数据类型,能够创建出⻓度不同的变量,变量⻓度的不
同,存储的数据范围就有所差异,存储单位是字节,一个字节为8个bit。

size_t sizeof( a variable or a type (including aggregate types) )

sizeof是⼀个关键字,也是操作符,专门是⽤来计算sizeof操作符数的类型⻓度的,单位是字节。

sizeof操作符的操作数可以是数据类型,也可是变量、字面值。

The sizeof keyword gives the amount of storage, in bytes, associated with a variable or a type (including aggregate types). This keyword returns a value of type size_t.

sizeof(类型);
sizeof 变量或字面值;	//变量或字面值可以省略括号

如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{	
	double a = 0;
	printf("%zd\n", sizeof(int));
	printf("%zd\n", sizeof(char*));
	printf("%zd\n", sizeof a);	//变量或字面值可以省略括号

	return 0;
}

运行结果:

4
4
8

基本数据类型和指针类型

int :4个字节
char :1个字节
float :4个字节
double :8个字节

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{	
	printf("sizeof(int):%zd\n", sizeof(int));
	printf("sizeof(char):%zd\n", sizeof(char));
	printf("sizeof(float):%zd\n", sizeof(float));
	printf("sizeof(double):%zd\n", sizeof(double));
    //在x64环境中,指针类型永远占8个字节;在x86环境中,指针类型永远占4个字节
    //1个字节 = 8个bit
	printf("sizeof(char*):%zd\n", sizeof(char*));

	return 0;
}

运行结果:

sizeof(int):4
sizeof(char):1
sizeof(float):4
sizeof(double):8
sizeof(char*):4

构造数据类型

数组

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{	
    //数组的存储空间 = 数组长度 * 数组所存放的数据类型的存储空间,单位是字节
	int arr1[6] = { 0 };
	printf("%zd = %zd * %zd\n", sizeof(arr1), 6, sizeof(int));

	char* arr2[10] = { NULL };
	printf("%zd = %zd * %zd\n", sizeof(arr2), 10, sizeof(char*));

	return 0;
}

运行结果:

24 = 6 * 4
40 = 10 * 4

结构体

结构体的内存对齐

结构体对齐规则
  1. 结构体的第⼀个成员对齐到和结构体变量起始位置偏移量为0的地址处
  2. 其他成员变量要对齐到相应的对齐数的整数倍的地址处
  3. 结构体的总大小为最大对齐数的整数倍。其中,最大对齐数为每一个成员变量的对齐数中的最大值。

注:对齐数:成员变量的第一个字节的地址相对于结构体首成员的第一个字节的地址(偏移量为0的地址处)的偏移量,这个可以类比数组的下标。
如何知道每个成员的对齐数?
对齐数 = 该成员变量所对应的类型的大小 与 编译器默认的一个对齐数 中的一个较小值
注:VS编译器的默认对齐数是8;Linux环境下的gcc编译器没有默认的对齐数,则对齐数为该成员变量的大小。

对齐规则应用

抛砖:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
struct S1
{
	char c1;
	int i;
	char c2;
};
struct S2
{
	char c1;
	char c2;
	int i;
};

int main()
{	
	printf("%d\n", sizeof(struct S1));
	printf("%d\n", sizeof(struct S2));

	return 0;
}

运行结果:

12
8

奇了怪了,我滴乖乖,这两个结构体的成员变量的类型和数量不都是一样的吗?

  1. 为啥最后的输出结果表示两者所占的内存空间不同?
  2. char占1个字节,int占4个字节,那么结构体不是应该占6个字节吗?

引玉:

image.png

为啥要内存对齐?

大部分的参考资料都是这么说的

  1. 平台原因 (移植原因):
    不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定
    类型的数据,否则抛出硬件异常。
  2. 性能原因:
    数据结构(尤其是栈)应该尽可能地在⾃然边界上对⻬。原因在于,为了访问未对⻬的内存,处理器需要
    作两次内存访问;⽽对⻬的内存访问仅需要⼀次访问。假设⼀个处理器总是从内存中取8个字节,则地
    址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对⻬成8的倍数,那么就可以
    ⽤⼀个内存操作来读或者写值了。否则,我们可能需要执⾏两次内存访问,因为对象可能被分放在两
    个8字节内存块中。


总的来说:结构体的内存对⻬是拿空间来换取时间的做法,所以说我们在设计结构体的时候要让占用空间小的成员尽量集中起来,减少空间的冗余。

如何修改对齐数?

预处理指令#pragma,可以修改编译器的默认对齐数

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#pragma pack(1)
struct S2
{
	char c1;
	char c2;
	int i;
};

int main()
{	
	printf("%d\n", sizeof(struct S2));

	return 0;
}

运行结果:

6

联合体

也称为共用体,顾名思义,联合体的内部成员共享同一块内存空间。
联合体的内存对齐规则:

  1. 联合体内任意成员变量对齐到和联合体变量起始位置偏移量为0的地址处
  2. 联合体的总大小为最大对齐数(即各成员变量类型所占空间的最大值)的整数倍。

如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
union Un1
{
	char c[5];
	int i;
};
union Un2
{
	short c[7];
	int i;
};
int main()
{	
	printf("%d\n", sizeof(union Un1));
	printf("%d\n", sizeof(union Un2));

    //通过查看在联合体变量Un1中数组变量c[5]和整型变量i的地址,发现两者地址一致
	union Un1 uu;
	printf("%p\n", &(uu.c[0]));
	printf("%p\n", &(uu.i));

	return 0;
}

运行结果:

8
16
0056F9D4
0056F9D4

解释:
image.png

枚举

“枚举类型的尺寸是以能够容纳最大枚举子的值的整数的尺寸”,同时在标准中也说明:“枚举类型中的枚举子的值必须要能够用一个int类型表述”,也就是说,枚举类型的尺寸不能够超过int类型的尺寸。

但是是不是必须和int类型具有相同的尺寸呢?

上面的标准已经说得很清楚了,只要能够容纳最大的枚举子的值的整数就可以了。
所以其实可以说一个枚举类型所占空间的大小即为一个常数所占内存空间的大小,即一个int型所占内存空间的大小。
如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
enum Color
{
	RED,
	GREEN,
	BLUE
}color;
int main()
{	
	printf("%d\n", sizeof(color));

	return 0;
}

运行结果:

4
  • 20
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
前言 1 章 绪论1 本章概略1 1.1 针对考研数据结构的代码书写规范以及C 与C 语言基础1 1.1.1 考研综合应用题中算法设计部分的代码书写规范1 1.1.2 考研中的C 与C 语言基础3 1.2 算法的时间复杂度与空间复杂度分析基础 12 1.2.1 考研中的算法时间复杂度分析 12 1.2.2 例题选讲 12 1.2.3 考研中的算法空间复杂度分析 14 1.3 数据结构和算法的基本概念 14 1.3.1 数据结构的基本概念 14 1.3.2 算法的基本概念 15 习题 16 习题答案 17 2 章 线性表 20 大纲要求 20 考点与要点分析 20 核心考点 20 基础要点 20 知识点讲解 20 2.1 线性表的基本概念与实现 20 2.2 线性表的结构体定义和基本操作 24 2.2.1 线性表的结构体定义 24 2.2.2 顺序表的操作 26 2.2.3 单链表的操作 29 2.2.4 双链表的操作 33 2.2.5 循环链表的操作 35 ▲真题仿造 35 真题仿造答案与讲解 36 习题 真题精选 37 习题答案 真题精选答案 41 3 章 栈和队列 55 大纲要求 55 考点与要点分析 55 核心考点 55 基础要点 55 知识点讲解 55 2019 版数据结构高分笔记 X 3.1 栈和队列的基本概念 55 3.1.1 栈的基本概念 55 3.1.2 队列的基本概念 56 3.2 栈和队列的存储结构、算法与应用 56 3.2.1 本章所涉及的结构体定义 56 3.2.2 顺序栈 57 3.2.3 链栈 59 3.2.4 栈的应用 60 3.2.5 顺序队 64 3.2.6 链队 66 3.3 抽象数据类型 69 ▲真题仿造 71 真题仿造答案与讲解 71 习题 真题精选 74 习题答案 真题精选答案 79 4 章 串 91 知识点讲解 91 4.1 串数据类型的定义 91 4.1.1 串的定义 91 4.1.2 串的存储结构 91 4.1.3 串的基本操作 92 4.2 串的模式匹配算法 95 4.2.1 简单模式匹配算法 95 4.2.2 KMP 算法 96 4.2.3 KMP 算法的改进 99 习题 102 习题答案 103 5 章 数组、矩阵与广义表 113 知识点讲解 113 5.1 数组 113 5.2 矩阵的压缩存储 114 5.2.1 矩阵 114 5.2.2 特殊矩阵和稀疏矩阵 115 5.3 广义表 121 习题 122 习题答案 123 6 章 树与二叉树 132 大纲要求 132 考点与要点分析 132 核心考点 132 基础要点 132 知识点讲解 132 6.1 树的基本概念 132 6.1.1 树的定义 132 6.1.2 树的基本术语 132 6.1.3 树的存储结构 133 6.2 二叉树 134 6.2.1 二叉树的定义 134 6.2.2 二叉树的主要性质 135 6.2.3 二叉树的存储结构 137 6.2.4 二叉树的遍历算法 137 6.2.5 二叉树遍历算法的改进 146 6.3 树和森林与二叉树的互相转换 155 6.3.1 树转换为二叉树 155 6.3.2 二叉树转换为树 156 6.3.3 森林转换为二叉树 156 6.3.4 二叉树转换为森林 157 6.3.5 树和森林的遍历 157 6.4 树与二叉树的应用 158 6.4.1 二叉排序树与平衡二叉树 158 6.4.2 赫夫曼树和赫夫曼编码 159 ▲真题仿造 162 真题仿造答案与解析 162 习题 真题精选 163 习题答案 真题精选答案 168 7 章 图 183 大纲要求 183 考点与要点分析 183 核心考点 183 基础要点 183 知识点讲解 183 7.1 图的基本概念 183 7.2 图的存储结构 184 7.2.1 邻接矩阵 185 7.2.2 邻接表 186 7.2.3 邻接多重表 187 7.3 图的遍历算法操作 188 7.3.1 深度优先搜索遍历 188 7.3.2 广度优先搜索遍历 189 7.3.3 例题选讲 190 7.4 小(代价)生成树 193 7.4.1 普里姆算法和克鲁斯卡尔算法 193 7.4.2 例题选讲 197 7.5 短路径 198 7.5.1 迪杰斯特拉算法 198 7.5.2 弗洛伊德算法 204 7.6 拓扑排序 207 7.6.1 AOV 网 207 7.6.2 拓扑排序核心算法 207 7.6.3 例题选讲 209 7.7 关键路径 209 7.7.1 AOE 网 209 7.7.2 关键路径核心算法 210 ▲真题仿造 213 真题仿造答案与解析 213 习题 真题精选 215 习题答案 真题精选答案 221 8 章 排序 234 大纲要求 234 考点与要点分析 234 核心考点 234 基础要点 234 知识点讲解 235 8.1 排序的基本概念 235 8.1.1 排序 235 8.1.2 稳定性 235 8.1.3 排序算法的分类 235 8.2 插入类排序 236 8.2.1 直接插入排序 236 8.2.2 折半插入排序 237 8.2.3 希尔排序 238 8.3 交换类排序 240 8.3.1 起泡排序 240 8.3.2 快速排序 241 8.4 选择类排序 243 8.4.1 简单选择排序 243 8.4.2 堆排序 244 8.5 二路归并排序 247 8.6 基数排序 248 8.7 外部排序 252 8.7.1 概念与流程 252 8.7.2 置换-选择排序 253 8.7.3 佳归并树 254 8.7.4 败者树 255 8.7.5 时间与空间复杂度相关问题 257 8.8 排序知识点小结 258 ▲真题仿造 259 真题仿造答案与解析 259 习题 真题精选 260 习题答案 真题精选答案 265 9 章 查找 275 大纲要求 275 考点与要点分析 275 核心考点 275 基础要点 275 知识点讲解 275 9.1 查找的基本概念、顺序查找法、折半查找法 275 9.1.1 查找的基本概念 275 9.1.2 顺序查找法 276 9.1.3 折半查找法 277 9.1.4 分块查找 279 9.2 二叉排序树与平衡二叉树 280 9.2.1 二叉排序树 280 9.2.2 平衡二叉树 283 9.3 B-树的基本概念及其基本操作、B 树的基本概念 286 9.3.1 B-树(B 树)的基本概念 286 9.3.2 B-树的基本操作 288 9.3.3 B 树的基本概念 292 9.4 散列表 293 9.4.1 散列表的概念 293 9.4.2 散列表的建立方法以及冲突解决方法 293 9.4.3 散列表的性能分析 297 ▲真题仿造 298 真题仿造答案与解析 298 习题 真题精选 299 习题答案 真题精选答案 304 10 章 考研中某些算法的分治法解释 318

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值