文章目录
- `sizeof` 和 `strlen`
- 数组和链表
- 总结
- #include <>和 #include ""
- #define 和typedef
- 内存对齐概述
- 对齐规则
- 示例:结构体的内存对齐
- 分析:
- 内存对齐的常见规则:
- 填充字节的计算
- 对齐影响的实际例子
sizeof
和 strlen
特性 | sizeof | strlen |
---|---|---|
定义 | 运算符,也是关键字,用于获取类型或变量所占的字节数 | 函数,用于计算 C 风格字符串的长度(不包括 '\0' ) |
用途 | 返回对象或数据类型在内存中占用的字节数 | 返回 C 风格字符串的字符数量(不包括 '\0' ) |
计算方式 | 在编译时确定,求值过程是静态的 | 在运行时计算,需遍历字符串逐字符计数 |
适用类型 | 适用于所有类型,包括数组、结构体、指针、基本数据类型等 | 仅适用于 C 风格字符串(以 '\0' 结尾的字符数组) |
返回值 | 返回的是字节数,通常是 size_t 类型 | 返回字符串中字符的数量,不包括 '\0' 字符 |
操作对象 | 数据类型、变量、数组、结构体等 | C 风格字符串(const char* 或 char[] ) |
是否包括 '\0' | 包括 '\0' (例如对字符数组使用 sizeof 会计算整个数组大小) | 不包括 '\0' (只计算实际字符数) |
适用场景 | 获取类型或数组的内存大小,计算静态数据结构的大小 | 获取字符串的实际长度(不包括结束符 '\0' ) |
示例代码 | sizeof(int) 返回 4 (通常情况下) | strlen("Hello") 返回 5 |
计算复杂度 | 常数时间复杂度,编译时计算 | 线性时间复杂度,需要遍历整个字符串 |
数组和链表
特性 | 数组 | 链表 |
---|---|---|
定义 | 数组是一种线性数据结构,它包含固定大小的连续元素 | 链表是一种线性数据结构,它由节点组成,每个节点包含数据和指向下一个节点的指针 |
内存结构 | 在内存中分配一个连续的块 | 每个节点在内存中不一定是连续的,节点通过指针连接 |
存储方式 | 静态存储方式(大小固定) | 动态存储方式(可以动态增加或删除节点) |
元素类型 | 所有元素类型相同(通常是基本数据类型) | 每个节点可以存储不同类型的数据,节点可以包含不同的结构 |
访问方式 | 通过索引直接访问元素,时间复杂度为 O(1) | 通过指针遍历,每次只能访问当前节点,时间复杂度为 O(n) |
插入与删除 | 插入或删除元素时需要移动元素,时间复杂度为 O(n) | 插入和删除操作在头部和尾部的时间复杂度为 O(1),在中间位置为 O(n) |
内存分配 | 在定义数组时就分配固定大小的内存 | 节点可以在运行时动态分配和释放内存 |
大小变动 | 大小固定,无法在运行时调整 | 可以动态增减节点,大小可以灵活变化 |
内存浪费 | 如果数组大小过大,可能会浪费内存 | 如果链表很长且有很多空节点,可能会浪费指针的内存 |
优缺点 | 优:访问快速;缺:插入和删除操作不灵活 | 优:插入和删除操作灵活;缺:访问速度较慢 |
总结
- 数组 是一种高效的、固定大小的线性数据结构,适合需要快速访问的场景,但它不适合频繁的插入和删除操作。
- 链表 适合需要频繁动态插入和删除的场景,尽管它的访问速度较慢,但它提供了更大的灵活性,尤其在内存使用方面。
#include <>和 #include “”
特性 | #include <> | #include "" |
---|---|---|
用途 | 用于包含系统或标准库的头文件 | 用于包含用户定义的头文件或当前目录下的头文件 |
查找顺序 | 编译器首先查找标准库路径中的头文件 | 编译器首先查找当前目录中的头文件,若找不到,再查找标准库路径 |
适用场景 | 用于包含标准库或第三方库的头文件(如 #include <iostream> ) | 用于包含项目中的自定义头文件(如 #include "myheader.h" ) |
#define 和typedef
#define
和 typedef
都是 C/C++ 中常用的预处理指令和关键字,主要用于定义常量、宏和类型别名。它们有不同的功能和使用方式,下面是详细的比较:
特性 | #define | typedef |
---|---|---|
用途 | 用于定义宏(常量、函数、代码片段) | 用于定义类型别名(为现有类型起别名) |
作用范围 | 在宏定义之后,它的作用范围是整个文件 | 在定义之后,它的作用范围通常是当前作用域或文件 |
类型检查 | 不进行类型检查,纯粹的文本替换 | 进行类型检查,确保新类型的合法性 |
宏定义的作用 | 定义常量、简单函数或复杂的代码块 | 不支持宏功能,只有类型别名 |
宏展开时机 | 宏在预处理阶段展开(编译前) | typedef 只是定义别名,不会进行宏展开 |
调试支持 | 宏没有调试信息(因为宏只是简单的文本替换) | typedef 可以像普通类型一样调试 |
示例 | #define PI 3.14 | typedef int Integer; |
内存对齐概述
内存对齐(Memory Alignment)是计算机体系结构中对数据存储方式的一种要求,它规定了数据类型的存储地址必须是某个特定值的倍数。
在现代计算机中,通常要求数据按照一定的对齐方式存储,例如 4 字节对齐、8 字节对齐等。对齐通常会影响结构体和数组的内存布局,从而决定其内存占用的大小。
对齐规则
-
基本对齐规则:
- 每个数据类型的存储地址应当是该数据类型大小的倍数。例如:
char
类型通常是 1 字节,通常可以存储在任何地址。int
类型通常是 4 字节,存储地址必须是 4 的倍数。double
类型通常是 8 字节,存储地址必须是 8 的倍数。
- 每个数据类型的存储地址应当是该数据类型大小的倍数。例如:
-
结构体对齐:
- 对结构体中的成员进行对齐时,结构体的总大小将是最大成员对齐要求的倍数。
- 结构体中每个成员的起始地址需要满足其对齐要求。如果某个成员的起始地址不符合其对齐要求,编译器会在它和下一个成员之间插入填充字节(padding bytes)来保证对齐。
-
结构体总大小:
- 结构体的总大小应该是最大对齐要求的倍数。如果结构体中的成员总和大小不满足最大对齐要求,编译器会在结构体末尾添加填充字节,以使结构体的总大小是对齐要求的倍数。
示例:结构体的内存对齐
考虑以下代码:
#include <stdio.h>
typedef struct {
char c; // 1 字节
int i; // 4 字节
double d; // 8 字节
} Example;
分析:
char c
占 1 字节。int i
占 4 字节。double d
占 8 字节。
在 Example
结构体中:
char c
需要 1 字节,但是由于int
需要 4 字节对齐,编译器会在char c
后插入 3 个填充字节,使int i
能够正确地以 4 字节对齐。int i
占 4 字节,按照 4 字节对齐。double d
占 8 字节,按照 8 字节对齐。- 结构体的总大小应是 8 的倍数(由于
double
的 8 字节对齐要求)。因此,结构体的总大小会扩展到 24 字节(1 + 3 + 4 + 8 + 8 的填充)。
结果:该结构体的大小是 24 字节,而不是成员大小的总和 13 字节。
内存对齐的常见规则:
数据类型 | 对齐方式 | 描述 |
---|---|---|
char | 1 字节 | char 类型的对齐方式为 1 字节。 |
short | 2 字节 | short 类型的对齐方式为 2 字节。 |
int | 4 字节 | int 类型的对齐方式为 4 字节。 |
float | 4 字节 | float 类型的对齐方式为 4 字节。 |
double | 8 字节 | double 类型的对齐方式为 8 字节。 |
long | 4 字节或8字节 | long 类型的对齐方式依赖于系统架构。 |
long long | 8 字节 | long long 类型的对齐方式为 8 字节。 |
填充字节的计算
考虑以下结构体定义:
typedef struct {
char c; // 1 字节
int i; // 4 字节
} MyStruct;
-
char c
占 1 字节,紧接着是int i
,但是int
类型要求 4 字节对齐。因此,编译器会在char
后插入 3 个填充字节,使int
的起始地址是 4 的倍数。 -
所以,
int i
占 4 字节,整个结构体的大小需要为 4 字节对齐。因此,结构体的总大小将是 8 字节。
对齐影响的实际例子
#include <stdio.h>
typedef struct {
char c;
int i;
double d;
} Example;
int main() {
printf("Size of Example: %zu\n", sizeof(Example));
return 0;
}
假设:
char c
占 1 字节。int i
占 4 字节(要求 4 字节对齐)。double d
占 8 字节(要求 8 字节对齐)。
计算结构体内存:
char c
占 1 字节。- 插入 3 字节填充,使
int i
能够 4 字节对齐。 int i
占 4 字节。double d
占 8 字节,且由于对齐要求,double
的起始地址必须是 8 的倍数。- 结构体的总大小会被扩展到 16 字节,以满足 8 字节对齐。
输出结果:
Size of Example: 16
以最大类型所占内存分配内存空间。