C++校招面经(三)

欢迎关注 0voice · GitHub
11 、指针和引⽤的区别
指针和引⽤都是⼀种内存地址的概念,区别呢,指针是⼀个实体,引⽤只是⼀个别名。
在程序编译的时候,将指针和引⽤添加到符号表中。
指针它指向⼀块内存,指针的内容是所指向的内存的地址,在编译的时候,则是将 指针变ᰁ名 - 指针变ᰁ的地址
加到符号表中,所以说,指针包含的内容是可以改变的,允许拷⻉和赋值,有 const 和⾮ const 区别,甚⾄可以为
空, sizeof 指针得到的是指针类型的⼤⼩。
⽽对于引⽤来说,它只是⼀块内存的别名,在添加到符号表的时候,是将 " 引⽤变ᰁ名 - 引⽤对象的地址 " 添加到符号
表中,符号表⼀经完成不能改变,所以引⽤必须⽽且只能在定义时被绑定到⼀块内存上,后续不能更改,也不能为
空,也没有 const 和⾮ const 区别。
sizeof 引⽤得到代表对象的⼤⼩。⽽ sizeof 指针得到的是指针本身的⼤⼩。另外在参数传递中,指针需要被解引⽤
后才可以对对象进⾏操作,⽽直接对引⽤进⾏的修改会直接作⽤到引⽤对象上。
作为参数时也不同,传指针的实质是传值,传递的值是指针的地址;传引⽤的实质是传地址,传递的是变ᰁ的地址
12 、 ᰀ (wild) 指针与悬空 (dangling) 指针有什么区别?如何避免?
ᰀ指针 (wild pointer) :就是没有被初始化过的指针。⽤ gcc -Wall 编译 , 会出现 used uninitialized 警告。
悬空指针:是指针最初指向的内存已经被释放了的⼀种指针。
⽆论是ᰀ指针还是悬空指针,都是 指向⽆效内存区域 ( 这⾥的⽆效指的是 " 不安全不可控 ") 的指针 。 访问 " 不安全可
"(invalid) 的内存区域将导致 "Undefined Behavior"
如何避免使⽤ᰀ指针? 在平时的编码中,养成在定义指针后且在使⽤之前完成 初始化 的习惯或者使⽤智能指针。
13 、说⼀下 const 修饰指针如何区分?
下⾯都是合法的声明,但是含义⼤不同:
const int * p1; // 指向 整形常ᰁ 的指针,它指向的值不能修改
int * const p2; // 指向整形的 常ᰁ指针 ,它不能在指向别的变ᰁ,但指向(变ᰁ)的值可以修改。
const int *const p3; // 指向 整形常ᰁ 常ᰁ指针 。它既不能再指向别的常ᰁ,指向的值也不能修改。
理解这些声明的技巧在于,查看关键字 const 右边来确定什么被声明为常ᰁ ,如果该关键字的右边是类型,则值是
常ᰁ;如果关键字的右边是指针变ᰁ,则指针本身是常ᰁ。
14 、简单说⼀下函数指针
从定义和⽤途两⽅⾯来说⼀下⾃⼰的理解:
⾸先是定义:函数指针是指向函数的指针变ᰁ。函数指针本身⾸先是⼀个指针变ᰁ,该指针变ᰁ指向⼀个具体的函
数。这正如⽤指针变ᰁ可指向整型变ᰁ、字符型、数组⼀样,这⾥是指向函数。
在编译时,每⼀个函数都有⼀个⼊⼝地址,该⼊⼝地址就是函数指针所指向的地址。有了指向函数的指针变ᰁ后,
可⽤该指针变ᰁ调⽤函数,就如同⽤指针变ᰁ可引⽤其他类型变ᰁ⼀样,在这些概念上是⼤体⼀致的。
其次是⽤途:调⽤函数和做函数的参数,⽐如回调函数。
示例:
15 、堆和栈区别
由编译器进⾏管理,在需要时由编译器⾃动分配空间,在不需要时候⾃动回收空间,⼀般保存的是局部变ᰁ和函数
参数等。
连续的内存空间,在函数调⽤的时候,⾸先⼊栈的主函数的下⼀条可执⾏指令的地址,然后是函数的各个参数。
⼤多数编译器中,参数是从右向左⼊栈(原因在于采⽤这种顺序,是为了让程序员在使⽤ C/C++ 函数参数⻓度可
这个特性时更⽅便。如果是从左向右压栈,第⼀个参数(即描述可变参数表各变ᰁ类型的那个参数)将被放在
栈底,由于可变参的函数第⼀步就需要解析可变参数表的各参数类型,即第⼀步就需要得到上述参数,因此,将它
放在栈底是很不⽅便的。)本次函数调⽤结束时,局部变ᰁ先出栈,然后是参数,最后是栈顶指针最开始存放的地
址,程序由该点继续运⾏,不会产⽣碎⽚。
栈是⾼地址向低地址扩展,栈低⾼地址,空间较⼩。
由程序员管理,需要⼿动 new malloc delete free 进⾏分配和回收,如果不进⾏回收的话,会造成内存泄漏的问
题。
不连续的空间,实际上系统中有⼀个空闲链表,当有程序申请的时候,系统遍历空闲链表找到第⼀个⼤于等于申请
⼤⼩的空间分配给程序,⼀般在分配程序的时候,也会空间头部写⼊内存⼤⼩,⽅便 delete 回收空间⼤⼩。当然
如果有剩余的,也会将剩余的插⼊到空闲链表中,这也是产⽣内存碎⽚的原因。
堆是低地址向⾼地址扩展,空间交⼤,较为灵活。
16 、函数传递参数的⼏种⽅式
值传递: 形参是实参的拷⻉,函数内部对形参的操作并不会影响到外部的实参。
指针传递: 也是值传递的⼀种⽅式,形参是指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进
⾏操作。
引⽤传递: 实际上就是把引⽤对象的地址放在了开辟的栈空间中,函数内部对形参的任何操作可以直接映射到外部
的实参上⾯。
17 new / delete malloc / free 区别
都可以⽤来在堆上分配和回收空间。 new /delete 是操作符, malloc/free 是库函数。
执⾏ new 实际上执⾏两个过程 1. 分配未初始化的内存空间( malloc ); 2. 使⽤对象的构造函数对空间进⾏初始
化;返回空间的⾸地址。如果在第⼀步分配空间中出现问题,则抛出 std::bad_alloc 异常,或被某个设定的异常处
理函数捕获处理;如果在第⼆步构造对象时出现异常,则⾃动调⽤ delete 释放内存。
执⾏ delete 实际上也有两个过程 1. 使⽤析构函数对对象进⾏析构; 2. 回收内存空间( free )。
以上也可以看出 new malloc 的区别, new 得到的是经过初始化的空间,⽽ malloc 得到的是未初始化的空间。
所以 new new ⼀个类型,⽽ malloc 则是 malloc ⼀个字节⻓度的空间。 delete free 同理, delete 不仅释放
空间还析构对象, delete ⼀个类型, free ⼀个字节⻓度的空间。
为什么有了 malloc free 还需要 new delete 因为对于⾮内部数据类型⽽⾔,光⽤ malloc free ⽆法满⾜动
态对象的要求。对象在创建的同时需要⾃动执⾏构造函数,对象在消亡以前要⾃动执⾏析构函数。由于 mallo
free 是库函数⽽不是运算符,不在编译器控制权限之内,不能够把执⾏的构造函数和析构函数的任务强加于
malloc free ,所以有了 new delete 操作符。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值