读书感悟[2]
1. 元素不能重复的数据结构有哪些?
std::set
:基于红黑树实现,元素有序且唯一。插入、删除和查找操作的时间复杂度为 O (log n)。
std::unordered_set
:基于哈希表实现,元素无序但唯一。平均插入、删除和查找操作的时间复杂度为 O (1)。
std::map
/std::unordered_map
:键(key)必须唯一。若仅需存储唯一元素,可使用值(value)为占位符的 map。
2. new
和 malloc
的区别
对比项 | new | malloc |
---|---|---|
数据类型 | 自动计算所需内存大小,返回特定类型指针。 | 返回 void* ,需手动转换为目标类型。 |
内存分配 | 调用构造函数初始化对象。 | 仅分配内存,不执行初始化。 |
内存释放 | 使用 delete 释放,调用析构函数。 | 使用 free 释放,不调用析构函数。 |
失败处理 | 失败时抛出 std::bad_alloc 异常。 | 失败时返回 NULL 。 |
重载支持 | 可重载 operator new 和 operator delete 。 | 不可重载。 |
3. new int()
括号为空时的初始化值
new int
:分配内存但不初始化,值为未定义(垃圾值)。
new int()
:值初始化,内置类型(如 int
)初始化为 0。
new int(42)
:显式初始化为指定值(如 42)。
4. 数组元素的表示方法(以 p
为首元素地址)
假设 p
是数组首元素地址(如 int* p = arr;
),以下是等价的元素访问方式:
下标法:p[i]
等价于 *(p + i)
。
指针偏移:*(p + i)
等价于 p[i]
。
数组名:若 arr
是数组,则 arr[i]
等价于 *(arr + i)
。
5. 引用(别名)的语法形式
引用的语法为 类型& 引用名 = 变量;
,例如:
int a = 10;
int& ref = a; // ref 是 a 的别名
设计原因:
与指针区分:引用必须初始化且不可重新绑定,而指针可空且可变。
语法简洁:避免显式解引用(如 *p
),提高代码可读性。
语义明确:常用于函数参数(如 void func(int& x)
)以实现传引用。
6. &
和 *
修饰形参的区别
形参类型 | 语义 | 示例 |
---|---|---|
值传递 | 传递变量的副本,函数内修改不影响原值。 | void func(int x) |
指针传递 | 传递变量的地址,需显式解引用。 | void func(int* p) |
引用传递 | 传递变量的别名,直接操作原变量。 | void func(int& ref) |
void byPtr(int* p) { *p = 10; } // 修改需解引用
void byRef(int& ref) { ref = 10; } // 直接修改int a = 5;
byPtr(&a); // 传地址
byRef(a); // 直接传变量,更简洁
7. 指针常量与常量指针的区别
类型 | 定义形式 | 语义 |
---|---|---|
常量指针 | const int* p | 指针指向的内容不可修改,但指针本身可修改。 |
指针常量 | int* const p | 指针本身不可修改,但指向的内容可修改。 |
指向常量的指针常量 | const int* const p | 指针和指向的内容均不可修改。 |
int a = 10, b = 20;
const int* p1 = &a; // 常量指针:*p1 = 20; 错误
int* const p2 = &a; // 指针常量:p2 = &b; 错误
const int* const p3 = &a; // 均不可修改