
目录
1. new和malloc的区别
new的定义:new是C++的关键字,用于动态分配内存并创建对象。它可以根据类型自动计算所需内存空间,并调用对象的构造函数进行初始化。在使用new分配内存后,需要使用delete来释放这些内存空间,以防止内存泄漏。
malloc的定义:malloc是C语言的库函数,用于动态分配一块指定大小的内存块,并返回其地址。需要注意的是,使用malloc分配内存后,需要使用free来释放这些内存空间,以防止内存泄漏。
new与malloc的区别:
- 语法:new是C++的关键字,而malloc是C语言的库函数。
- 类型安全:new操作符会根据类型自动计算所需内存大小,并进行类型匹配,返回的是对象类型指针;而malloc需要手动计算内存大小,并使用强制类型转换,返回的是void指针。
- 构造函数与析构函数的调用:new会自动调用对象的构造函数进行初始化,而malloc不会调用构造函数,得到的内存空间内容是未初始化的。
- 内存泄漏的检测:new可以通过异常机制检测内存分配失败,而malloc在分配失败时返回NULL,需要手动检查。
- 重载和自定义类型:new操作符可以重载,并能够与自定义类型的构造函数和析构函数配合使用;而malloc是库函数,不会调用自定义类型的构造和析构函数。
2. 野指针和悬挂指针的区别
野指针(Dangling Pointer):指的是没有初始化过的指针,它指向的地址是未知的、不确定的、随机的。产生野指针的原因主要是指针未初始化,防止的措施就是指针初始化(包括及时初始化或置空)。
int main() {
// 情况1:声明后未初始化
int* wild_ptr; // 野指针!指向随机地址
// cout << *wild_ptr << endl; // 危险!可能导致程序崩溃
// 情况2:释放后未置空
int* ptr = new int(100);
delete ptr; // 内存已被释放
// 此时 ptr 变成了野指针,因为它还指向刚才被释放的内存地址
// cout << *ptr << endl; // 危险!访问已释放内存
// 正确做法:释放后立即置空
ptr = nullptr; // 现在不是野指针了
return 0;
}
悬挂指针(Dangling Reference):指针最初指向的内存已经被释放了的一种指针。指针指向的内存已释放,但指针的值没有被清零,对悬空指针操作的结果不可预知。
int main() {
int* ptr1 = new int(200);
int* ptr2 = ptr1; // ptr1 和 ptr2 指向同一块内存
cout << "ptr1指向的值: " << *ptr1 << endl; // 输出 200
cout << "ptr2指向的值: " << *ptr2 << endl; // 输出 200
delete ptr1; // 释放内存
ptr1 = nullptr; // ptr1 安全了
// 但 ptr2 现在变成了悬挂指针!
// 它仍然指向刚才被释放的内存地址
// cout << *ptr2 << endl; // 危险!悬挂指针访问
// 函数返回局部变量地址的例子
auto badFunc = []() -> int* {
int local_var = 300;
return &local_var; // 返回局部变量的地址
}; // 函数结束时,local_var 被销毁
int* dangling_ptr = badFunc(); // dangling_ptr 是悬挂指针
// cout << *dangling_ptr << endl; // 危险!
return 0;
}
简单比喻
野指针:像一个没有登记在册的“黑户”。它指向哪里,系统根本不知道,也无法预料它会干什么。
悬挂指针:像一个地址已失效的“前住户”。它指向的房子已经被拆了或者住了别人。
3. 指针常量和常量指针的区别
指针常量(Pointer to a constant):指针常量是指指针本身是不可更改的,即指针变量自身的值不能被修改,但指向的值可以修改。
int* const ptr; // ptr 是指向常量的指针
常量指针(Constant pointer):常量指针是指指针指向的地址不能更改,即指针变量指向的地址不能被修改,但可以通过指针修改指向的值。
int x = 5;
const int * ptr = &x; // ptr 是常量指针
4. 虚拟内存和物理内存的区别
虚拟内存(Virtual Memory)和物理内存(Physical Memory)是计算机系统中存储和管理数据的两个概念:
- 物理内存是计算机中的实际硬件内存,由RAM芯片组成。
- 虚拟内存是对物理内存的扩展,使用磁盘空间来模拟更大的内存容量。
它们之间的区别包括:
- 大小:物理内存的容量是固定的,而虚拟内存的大小可以超过物理内存的容量。
- 访问速度:物理内存的访问速度较快,而虚拟内存的访问速度相对较慢,因为它需要与磁盘进行交互。
- 地址空间:物理内存使用物理地址进行访问,而虚拟内存使用虚拟地址,通过内存管理单元(MMU)映射到物理内存。
- 管理方式:物理内存的管理相对简单,而虚拟内存的管理涉及页表和页面置换等技术。
- 可用空间:物理内存的可用空间有限,而虚拟内存可以提供更大的可用空间,因为它可以使用磁盘空间作为扩展。
5. struct和class的区别
- 默认访问权限:struct中的成员默认为公共(public),而class中的成员默认为私有(private)。
- 默认继承方式:struct中的继承方式默认为公共(public),class中的继承方式默认为私有(private)。
- 使用习惯:struct适合用于简单的数据结构,class适合用于复杂的数据类型和实现面向对象编程。
- 成员变量和成员函数:struct中的成员变量和成员函数默认为公共,而class中的成员变量和成员函数默认为私有。
- 访问控制:struct中的成员在外部可直接访问,而class中的成员需要使用公共的成员函数来访问。
- 默认的构造函数和析构函数:class中会自动生成默认的构造函数和析构函数,而struct中不会。
6. 动态链接与静态链接的区别
动态链接:
- 在程序运行时链接,加载共享库文件。
- 节省空间,可多个程序共享库文件。
- 灵活性高,可以动态加载不同版本的库。
- 维护方便,只需更新库文件本身。
静态链接:
- 在编译时链接,将库函数复制到可执行文件中。
- 独立可执行文件,不依赖外部库。
- 可执行文件较大,可能有冗余代码。
- 维护复杂,更新库需重新编译和分发。
7. 静态绑定和动态绑定的的区别
- 静态类型:对象在声明时使用的类型,在编译期就已经确定。
- 动态类型:指针变量或引用变量所指向对象的类型,在运行期才能确定。
- 静态绑定:绑定的是静态类型,对象的函数和属性依赖于绑定的静态类型,发生在编译期。
- 动态绑定:绑定的是动态类型,对象的函数和属性依赖于绑定的动态类型,发生在运行期。
而非虚函数一般都是静态绑定,虚函数则是动态绑定。
8. mutable和volatile关键字的区别
mutable关键字:
- 定义:mutable关键字用于修饰类的成员变量,在常量成员函数中允许被修改。
- 特性:默认情况下,常量成员函数不允许修改类的成员变量,而使用 mutable 关键字可以解除这个限制,允许在常量成员函数中修改被 mutable 修饰的成员变量。
- 适用场景:mutable 关键字适用于需要在常量成员函数中更新的内部状态,例如缓存结果或记录操作次数等。
volatile关键字:
- 定义:volatile关键字用于修饰变量,在多线程、硬件 I/O 和中断处理等场景中,告诉编译器该变量的值可能发生变化,需要特殊对待。
- 防止优化:为了告诉编译器不要对该变量进行优化,以防止对变量的读取和写入的优化可能导致错误的行为。
- 适用场景:volatile 适用于与外部环境进行交互的变量,比如硬件寄存器的状态和多线程操作的标记等。
9. 静态成员函数与普通成员函数的区别
调用方式:
- 静态成员函数可以直接通过类名来调用,无需创建类的对象。
- 普通成员函数必须通过类的对象或指针来调用。
访问权限:
- 静态成员函数只能直接访问静态成员变量和静态成员函数,不能直接访问非静态成员变量和非静态成员函数。
- 普通成员函数可以直接访问类的所有成员,包括静态成员和非静态成员。
存储方式:
- 静态成员函数不会影响类的对象的大小,它们存储在类的命名空间中,所有对象共享同一个静态成员函数。
- 普通成员函数被存储在类的对象中,每个对象都有自己的成员函数。
this 指针:
- 普通成员函数有一个隐含的指向当前对象的指针,即 this 指针,可以在函数中使用 this 指针访问对象的成员。
- 静态成员函数没有 this 指针,无法直接访问非静态成员。
类作用域:
- 静态成员函数属于类的作用域,可以直接访问类的静态成员变量和静态成员函数,无需通过对象或指针。
- 普通成员函数属于对象的作用域,可以直接访问类的静态成员和非静态成员,需要通过对象或指针来访问。
10. 左值和右值的区别
左值(L-value):左值表示一个内存位置的标识符,可以出现在赋值语句的左边或右边。左值在表达式中是持久的,具有地址,并且可以被修改。可以将其简单理解为"可以取址的表达式"。一般来说,变量、函数或内存中的对象都可以是左值。
右值(R-value):右值表示暂时的、临时的值,不能出现在赋值语句的左边。右值在表达式中是短暂的,不具有地址,不能被修改。可以将其简单理解为"没有地址的表达式"。一般来说,常量、字面量、临时对象、表达式的结果等都可以被视为右值。




被折叠的 条评论
为什么被折叠?



