新手必看:C++10 组核心概念通俗解析(含指针、内存、绑定机制)

目录

1.  new和malloc的区别

2.  野指针和悬挂指针的区别

3.  指针常量和常量指针的区别

4.  虚拟内存和物理内存的区别

5.  struct和class的区别

6.  动态链接与静态链接的区别

7.  静态绑定和动态绑定的的区别

8.  mutable和volatile关键字的区别

9.  静态成员函数与普通成员函数的区别

10.  左值和右值的区别


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):右值表示暂时的、临时的值,不能出现在赋值语句的左边。右值在表达式中是短暂的,不具有地址,不能被修改。可以将其简单理解为"没有地址的表达式"。一般来说,常量、字面量、临时对象、表达式的结果等都可以被视为右值。

千题千解·嵌入式工程师八股文详解_时光の尘的博客-优快云博客

C++学习_时光の尘的博客-优快云博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时光の尘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值