嵌入式软件工程师面试题——2025校招社招通用(C/C++)(四十)

说明:

  • 面试群,群号: 228447240
  • 面试题来源于网络书籍,公司题目以及博主原创或修改(题目大部分来源于各种公司);
  • 文中很多题目,或许大家直接编译器写完,1分钟就出结果了。但在这里博主希望每一个题目,大家都要经过认真思考,答案不重要,重要的是通过题目理解所考知识点,好应对题目更多的变化;
  • 博主与大家一起学习,一起刷题,共同进步;
  • 写文不易,麻烦给个三连!!!

前面1-15已经是C/C++,但是由于前面写的比较混乱,把八股文和题目混在了一起,所以从这一篇开始重新整理重新写,前面1-15也就可以选看了,希望多多支持!

1.#define和const

答案:

define和const 都可以用于定义常量但以下区别(生效时间,内存占用情况,类型检查):

  1. define只是单纯的文本替换,define常量的生命周期止于编译器,不存在分配内存,存在与程序的代码段
  2. const生效于编译的阶段;define生效于预处理阶段
  3. const修饰的常量处于程序的数据段,在堆栈中分配空间
  4. const有数据类型检查,define没有
  5. #define不可调试,const能调试
  6. const定义的变量在C中不是真正的常量
  7. const 定义的常量不能作为数组的大小

2.typedef和define(原理、作用域,对指针操作不同)

答案:

1. 首先#define是预处理命令,在预处理阶段只是机械的替换带入字符串,并不会左类型检查,

2. typedef是关键字,作用是给自己的作用域内给一个已经存在的类型起个别名

3. #define没有作用域的限制,只要是之前预定义过的宏,在以后的程序中都可以使用,而typedef有自己的作用域

4. 对指针的操作不同 

比如: #define intper int *

         typedef int * pre

3.define的一些坑(缺点)

答案:

  1. 无法进行类型检查
  2. 运算优先级问题
  3. 无法调试
  4. 代码膨胀
  5. 无法操作类的私有数据成员

4.#include<头文件>,#include头文件的区别

答案:

对于#include<头文件>,表示是系统文件,编译会先从标准库路径下搜索-->编译器设置的头文件路径-->系统变量

对于#include”头文件”,当前头文件目录-->编译器设置的头文件路径-->系统变量

对于编译速度来说:

语句#include< stdlib.h >是正确的,而且程序编译速度比#include “stdlib.h”要快

5.定义一个常数,用以表明一年有多少秒(忽略闰年)

答案:

#define SECOND_PER_YEAR(60*60*24*365)UL

重点是看有没有加UL

6.简述C++从代码到可执行二进制文件的过程

答案:

预处理、编译、汇编、链接

预编译:这个过程主要的处理操作如下:

(1) 将所有的#define删除,并且展开所有的宏定义

(2) 处理所有的条件预编译指令,如#if、#ifdef

(3) 处理#include预编译指令,将被包含的文件插入到该预编译指令的位置。

(4) 过滤所有的注释

(5) 添加行号和文件名标识

编译:这个过程主要的处理操作如下:

(1) 词法分析:将源代码的字符序列分割成一系列的记号。

(2) 语法分析:对记号进行语法分析,产生语法树。

(3) 语义分析:判断表达式是否有意义。

(4) 代码优化:

(5) 目标代码生成:生成汇编代码

(6) 目标代码优化

汇编:这个过程主要是将汇编代码转变成机器可以执行的指令

链接:将不同的源文件产生的目标文件进行链接,从而形成一个可以执行的程序

7.在头文件中是否可以定义静态变量

答案:

不可以,因为静态变量是有记忆的,不会随函数结束而结束,所以,如果定义在头文件中,那么就会被多个文件开辟空间,浪费资源或者重新出错。

8.枚举和define区别

答案:

生效、类型、检查,调试,实体

  1. 枚举是在编译器生效,define是在预处理
  2. 枚举有类型,具有类型检查
  3. 枚举是实体,宏不是
  4. 枚举可以定义常量和变量,宏只能定义常量
  5. 枚举可以调试

9.宏函数和内联函数的区别

答案:

1.宏函数不是函数,是宏定义,只是使用起来像函数,宏函数是在预编译的时候把所有的宏名用宏体来替换,简单的说就是字符串替换。

2.内联函数,内联函数本质上是一个函数,内联函数一般用于函数体的代码比较简单的函数,不能包含复杂的控制语句,while、switch,并且内联函数本身不 能直接调用自身。

3.宏函数和内联函数如何提高效率?

内联函数是在编译的时候进行代码插入,编译器会在每处调用内联函数的地方直接把内联函数的内容展开,这样可以省去函数的调用的开销,提高效率。

宏函数则是在预处理的时候把宏体展开减去了参数压栈,函数调用,返回值等操作。

4.宏定义是没有类型检查的,无论对还是错都是直接替换;而内联函数在编译的时候会进行类型的检查,内联函数满足函数的性质,比如有返回值、参数列表。

10.内联函数和普通函数的区别(寻址,复制)

答案:

内联函数一般用于函数体的代码比较简单的函数,不能包含 复杂的控制语句,while、switch,并且内联函数本身不能直接调用自身。

最根本的区别是普通函数在调用时会调到函数入口,执行函数,再返回来,而内联函数不需要寻址,直接在该处将函数张开,如果N处调用了内联函数则会有n处复制该代码,而普通函数只有一个复制。

11.为什么析构函数必须是虚函数?

答案:

默认的类中的析构函数并不不是虚函数,之所以要是虚析构函数,主要是考虑继承时子类内存释放问题。

将可能会被继承的父类的析构函数设置为虚函数,可以保证当我们new一个子类,然后使用基类指针指向该子类对象,释放基类指针时可以释放掉子类的空间,防止内存泄漏。

举例说明:

当A为基类,B为A的继承类,考虑如下情况:

A *p = new B();

.....

delete p;

如果此时A的析构函数不是虚函数,那么在delete p的时候就会调用A的析构函数,而不会调用B的析构函数,这样就会造成B的资源没有释放。

而如果A的析构函数为虚函数,那么就会调用B的析构函数,一切正常。

12.为什么C++默认的析构函数不是虚函数

答案:

当类中有虚成员函数时,类会自动生成虚函数表和虚表指针,虚表指针指向虚函数表。每个类都有自己的虚函数表,虚函数表的作用就是保存本类中虚函数的地址,我们可以把虚函数表形象地看成一个数组,这个数组的每个元素存放的就是各个虚函数的地址。

这样一来,就会占用额外的内存,当们定义的类不被其他类继承时,这种内存开销无疑是浪费的。

最近更新

  1. TCP协议是安全的吗?

    2024-01-26 18:10:05       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-26 18:10:05       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-26 18:10:05       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-26 18:10:05       20 阅读

热门阅读

  1. spring(二):基于注解实现依赖注入

    2024-01-26 18:10:05       30 阅读
  2. C++提高编程——STL:函数对象

    2024-01-26 18:10:05       28 阅读
  3. 题记(30)--排名

    2024-01-26 18:10:05       32 阅读
  4. ArkTs 语法学习 ---- 组件相关装饰器

    2024-01-26 18:10:05       29 阅读
  5. SQL 系列教程(五)

    2024-01-26 18:10:05       28 阅读
  6. ==与equals

    2024-01-26 18:10:05       33 阅读
  7. hashmap中的put方法存放数据源码解析

    2024-01-26 18:10:05       27 阅读
  8. 4.Doris数据导入导出

    2024-01-26 18:10:05       60 阅读
  9. 设计模式-三大工厂模式

    2024-01-26 18:10:05       29 阅读
  10. C++笔记(五)

    2024-01-26 18:10:05       31 阅读
  11. 初级通信工程师-现代通信技术

    2024-01-26 18:10:05       25 阅读