嵌入式软件常用面试题汇总之 C/C++ 语言相关(2)

C/C++之指针相关的面试题汇总

对校招来说这部分考的非常频繁,应届生务必要熟悉!!

1.指针与引用的区别

  • 初始化要求不同:引用在创建的同时必须初始化,就是它必须引用到一个有效的对象;而指针在定义的时候不必初始化,可以在定义后面的任何地方重新赋值。
  • 可修改性不同:引用一旦被初始化为指向一个对象,它就不能被改变为另一个对象的引用;而指针在任何时候都可以改变为指向另一个对象。给引用赋值并不是改变它和原始对象的绑定关系
  • 不存在NULL引用:引用不能使用指向空值的引用,它必须总是指向某个对象;而指针则可以是NULL,不需要总是指向某些对象,可以把指针指向任意的对象,所以指针更加灵活,也更容易出错。
  • 测试需求区别:由于引用不会指向空值,这意味着使用引用之前不用测试它是否合法;而指针则需要经常进行测试。因此使用引用的代码效率比使用指针的要高。
  • 应用的区别:如果我们想要一旦指向一个对象就不再改变指向,那么应该使用引用。如果有存在指向NULL(不指向任何对象)或在不同的时刻指向不同的对象这些可能性,应该使用指针。

总体来说,引用既具有指针的效率,又具有变量使用的方便性和直观性。

2.野指针是指什么?如何避免?

野指针就是访问了不该访问的内存或者访问了已经释放的内存,野指针的成因主要有两种:

  • 指针变量没有被初始化,任何指针变量刚被创建时不会自动生成NULL指针。它的默认值是随机的,它会乱指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存
  • 指针p被free或者delete之后,没有置为NULL,让人误以为p是一个合法的指针。free或者delete只是把指针所指的内存给释放掉,但是并没有把指针本身给干掉,用调试器跟踪可以发现p被free之后其地址仍然不变(非NULL),只是改地址对应的内存是垃圾,p成了野指针。如果此时不把p设置为NULL,会让人误以为p是一个合法的指针,如果程序比较长,我们有时记不住p所指向的内存是否已经被释放,在继续使用p之前,通常会用语句if(p!= NULL)进行防错处理,很遗憾,此时if语句起不到防错作用,因为即便p不是NULL指针,也不指向合法的内存块

我们在编写程序的时候养成良好的编程习惯就能避免野指针的出现:

  • 凡定义的指针变量初始化为NULL
  • 指针变量被free或delete之后将其值赋为NULL
  • if(ptr == NULL) 使用之前先判断

3.写出数组指针的定义,指针数组的定义,函数指针的定义,指针函数的定义,函数指针数组的定义

  • 数组指针:int (*p)[ ];(一个指向数组的指针)
  • 指针数组:int *p[ ];(一个数组,数组内存放着指针)
  • 函数指针:int (*p)(int);(一个指向函数地址的指针)
  • 指针函数:int* p(int); (一个返回指针的函数)
  • 函数指针数组:int (*p[ ])(int);(一个数组,数组内存放着指向函数地址的指针)

4.区别下函数指针和指针函数,分别怎么定义和使用?

函数指针:

  • 函数指针是指向函数的指针,它存储了函数的地址。
  • 声明函数指针时,需要指定函数的返回类型和参数列表,以便与函数的类型匹配。
  • 通过函数指针可以调用相应的函数。
声明形式如下:
returnType (*pointerName)(parameterTypes);

// 声明一个函数指针,指向返回值为int,参数为两个int的函数
int (*funcPtr)(int, int);

// 初始化函数指针,使其指向某个函数
funcPtr = &add;

// 使用函数指针调用函数
int result = (*funcPtr)(10, 20);

指针函数:

  • 是一个函数,其返回值是指针类型。
  • 指针函数的声明形式与普通函数类似,只是其返回值是指针类型。
  • 指针函数可以返回指向不同类型的指针,具体返回何种类型的指针取决于函数的实现。
  • 使用指针函数时,需要注意返回的指针是否有效,以避免悬挂指针等问题。
// 声明一个指针函数,返回值为int*
int* pointerFunction(int x) {
    // 函数实现
    return new int(x);
}

// 调用指针函数
int* ptr = pointerFunction(10);

5.指针与数组的区别和联系?

指针(Pointer)和数组(Array)是 C 和 C++ 中两种不同的数据类型。

联系:

  • 指针和数组都可以用来存储一组相同类型的数据。
  • 指针可以指向数组的第一个元素,也可以通过指针算术运算来遍历数组的所有元素。
  • 数组名本身也可以被视为指向数组第一个元素的指针,即数组名是数组首元素的地址。
  • 指针和数组都支持下标运算符 [] 来访问元素。
  • 对于指针来说,使用 *(ptr + i) 或 ptr[i] 都可以访问第 i 个元素。
  • 对于数组来说,直接使用 array[i] 即可访问第 i 个元素。
  • 在函数参数传递中,数组名会被隐式转换为指向数组首元素的指针。
  • 当数组作为函数参数传递时,实际上传递的是数组首元素的地址,而不是整个数组的拷贝。

区别:

  • 数据类型:
  • 指针是一个变量,用来存储内存地址,可以指向任意类型的数据。
  • 数组是一个集合,存储一系列相同类型的数据,其大小在编译时确定。
  • 内存分配:
  • 指针需要显式地进行内存分配和释放,可以使用 new 和 delete 运算符动态分配内存。
  • 数组的内存分配是静态的,在编译时就已经确定了大小,并且分配的内存空间在程序运行期间不会改变。
  • 语法操作:
  • 指针可以进行指针算术运算,可以通过指针进行间接访问内存。
  • 数组名不能进行指针算术运算,它只是一个常量指针,指向数组首元素的地址,不能被修改。
  • 参数传递:
  • 指针作为函数参数时,可以传递空指针,也可以修改指针指向的对象。
  • 数组作为函数参数时,会被隐式地转换为指向数组首元素的指针,函数无法获取数组的大小。

6.按值传递与按地址传递的区别

按值传递参数:按值传递参数时,是将实在参数的值复制一个形式参数中,如果在调用过程中改变了形式参数的值,不会影响实在参数本身,即实在参数保持调用前的值不变。

按地址传递:按地址传递参数时,把实在参数的地址传送给被调用过程,形式参数和实在参数共用内存的同一地址。在被调用过程中,形式参数的值一旦改变,相应实参的值也跟着改变。

7.指针的强制类型转换

可以使用强制类型转换来将指针从一种类型转换为另一种类型,一般经常用的有如下的方法。

C 风格的强制类型转换:

int* ptr = new int;
float* floatPtr = (float*)ptr;

reinterpret_cast:该运算符用于将指针转换为其他指针类型,通常用于不同类型之间的指针转换,例如指针和整数之间的转换。但要注意,reinterpret_cast 并不检查转换的安全性,因此可能会导致未定义的行为

int* ptr = new int;
float* floatPtr = reinterpret_cast<float*>(ptr);

static_cast:用于执行具有明确定义的类型转换,通常用于基本类型之间的转换或者向上或向下的类继承关系转换。与 reinterpret_cast 相比,static_cast 更安全,因为它只能进行已定义的转换。

int num = 10;
double convertedNum = static_cast<double>(num);

8.C++的智能指针是什么?

智能指针是一种 C++语言特有的指针,它是对常规指针的封装,提供了自动内存管理的功能,能够在对象不再被使用时自动释放其所占用的内存,避免了手动管理内存所带来的错误和麻烦。智能指针的设计思想是资源管理类(RAII)的一种应用,通过将对象的生命周期与智能指针的生命周期绑定,实现对对象的自动管理。

C++标准库提供了几种智能指针,其中最常用的是std::unique_ptr和std::shared_ptr。

std::unique_ptr:

  • 是一种独占所有权的智能指针,它确保动态分配的内存只有一个指针可以访问,并且在指针离开作用域时自动释放其所管理的内存。
  • 禁止拷贝和赋值操作,因此不支持多个指针共享同一块内存。
  • 通常用于在函数中传递和返回动态分配的对象,以确保内存的正确释放。

std::shared_ptr:

  • 是一种共享所有权的智能指针,允许多个指针共享动态分配的内存,内存会在所有指针都释放后才会被释放。
  • 使用引用计数来跟踪内存的使用情况,当引用计数为零时,表示没有指针在管理内存,内存会被释放。
  • 允许拷贝和赋值操作,因此可以多个指针共享同一块内存。

除了这两种常用的智能指针外,C++标准库还提供了std::weak_ptr,它是std::shared_ptr的弱引用,用于解决循环引用的问题。

觉得本文有用的话,给博主点个赞吧!!谢谢大家!

#嵌入式##嵌入式面试##面经##笔试##嵌入式软件技能#

该专栏是我整理的一些嵌入式软件笔面试常见的题目,在有一定计算机基础上,再过一遍该专栏的内容,对应届生校招来说基本上笔面试就没什么问题了! 有任何疑问可随时与我联系,一起交流一起进步。

全部评论
觉得本文有用的话,给博主点个赞吧!!谢谢大家!!
1
送花
回复
分享
发布于 04-05 20:24 广东

相关推荐

4.1025min1、自我介绍2、常用的编程语言是哪个,自学的还是学校教的?3、ansible自动化配置简单讲讲(项目问题)4、lnmp配置具体出现了什么问题,怎么解决的(php的www.conf和nginx的conf里的用户和组不是一个,导致无法动态转发,通过浏览器返回渲染和nginx日志排错)5、讲讲操作系统的内存管理(我以为是讲讲linux的free命令,罗里吧嗦说了一堆,结果是让讲一些概念,页式存储和段页式存储等)6、TCP三次握手流程7、讲讲容器化技术,镜像和容器分别的概念和区别8、讲讲对k8s的了解9、讲讲你最熟悉哪一块的运维知识(nginx配置相关,面试官提问如果两个url分别访问服务器不同的静态文件该如何实现:include&nbsp;conf&nbsp;分别写server模块,或者并入nginx主配置文件,但是好像不是这个意思,具体还需学习;nginx的黑名单和白名单如何实现,忘了。。;https和http的区别是什么样的,在nginx配置文件里怎样实现https,也忘了。。。)10、讲讲容器和虚拟机的区别、优点和缺点11、讲讲grep命令,讲讲正则(?和*代表什么),讲讲用shell写过什么样的脚本12、讲讲对zabbix监控系统的理解13、你更想学习、做哪种路线的运维14、你将来的规划是什么样的?15、了解过我们公司业务吗,玩过手游吗,讲讲对游戏业务运维的理解反问环节:1、对容器化技术和k8s的理解程度需要多深?2、有无培训机制?3、常用的linux命令需要多广多深,具体在哪些方面需要多学习一些?更新:4.16收到感谢信
点赞 评论 收藏
转发
14 12 评论
分享
牛客网
牛客企业服务