嵌入式笔试面试刷题(day12)


前言

本篇文章继续带大家来刷题,秋招也快到了大家坚持刷题,相信大家都可以找到好工作。

一、SDK是什么

SDK是软件开发工具包(Software Development Kit)的缩写,它是一组用于开发软件应用程序的工具、库和文档的集合。SDK通常由软件开发平台或框架提供,旨在帮助开发人员更轻松、高效地创建应用程序。

SDK通常包含以下主要组件:

1.API(Application Programming Interface):SDK会提供一组API,即一组定义了如何与某个特定平台、操作系统或服务进行交互的编程接口。

2.工具和实用程序:SDK通常提供用于开发、构建、调试和测试应用程序的工具和实用程序,例如编译器、调试器、模拟器、测试框架等。

3.示例代码和示例应用程序:SDK通常提供一些示例代码和示例应用程序,以帮助开发人员理解和使用API和工具。

4.文档和教程:SDK通常提供详细的文档和教程,包括API文档、编程指南、开发者手册等,以帮助开发人员了解如何使用SDK中的组件和工具。

二、内存分配最小单位

当涉及内存分配时,有两个相关的概念需要区分:内存分配单位和内存分配函数。

1.内存分配单位:内存分配单位是指内存管理的最小单位。在操作系统中,内存通常以页面(Page)为最小分配单位。页面的大小通常是4KB或者更大,具体取决于操作系统和硬件。

2.内存分配函数:内存分配函数是编程语言提供的用于动态分配内存的函数。其中,malloc函数是C语言和C++语言中的一个常用内存分配函数。malloc函数通过请求操作系统为程序分配指定大小的连续字节的内存块。

区别:内存分配单位与内存分配函数之间的区别在于:

1.内存分配单位:指操作系统和硬件层面上内存管理的最小单位,通常是页面大小,如4KB。操作系统会根据页面的大小进行内存管理和分配,以支持虚拟内存等机制。

2.内存分配函数:是编程语言提供的接口,用于在程序运行时请求操作系统分配一定大小的内存。其中,malloc函数是一种常见的内存分配函数,它按字节为单位动态分配内存块。

3.内存分配函数(如malloc)使用字节作为分配单位,但在操作系统层面,内存管理以页面为最小分配单位。这是由于操作系统需要管理和映射页面,而应用程序通常只需要通过内存分配函数来分配适当大小的内存块,以满足其数据结构或算法的需求。

三、内联函数和宏函数的区别

内联函数和宏函数是两种在编程中实现函数展开的方式,它们有一些区别,包括以下几个方面:

1.语法和类型安全性:

内联函数是C++语言提供的一种函数声明方式,使用关键字inline进行声明。内联函数具有函数的语法结构,支持参数的类型检查和类型安全。内联函数可以像普通函数一样进行重载,可以包含复杂的语句和控制流程。
宏函数则是预处理器进行文本替换的方式,使用宏定义声明。宏函数是简单的文本替换,没有函数的语法结构,不进行类型检查。宏函数展开时只是进行简单的文本替换,可能会导致意外的副作用。

2.展开方式和底层实现:

内联函数在编译期间进行函数展开,将函数的实际代码嵌入到调用处,避免了函数调用的开销。内联函数的展开是由编译器控制的,并且可以对其进行内联优化。
宏函数在预处理阶段进行文本替换,将宏的实际文本替换到调用处。宏函数没有函数调用的开销,但可能会产生较大的代码体积。

3.命名空间和作用域:

内联函数位于命名空间中,具有自己的作用域。可以通过静态链接在多个源文件之间共享。内联函数也可以在类中定义,对于类的成员函数,可以在类声明中直接定义内联函数。
宏函数没有自己的作用域和命名空间,它是简单的文本替换。宏定义的作用范围是全局的,可能会导致命名冲突或不可预期的副作用。

4.调试和错误信息:

内联函数在调试过程中可以单步执行和观察,可以提供更好的调试信息和错误提示,因为内联函数是编译器处理的一部分。
宏函数无法单步执行和观察,可能会导致调试和错误定位困难,因为宏函数只是简单的文本替换。

总的来说,内联函数比宏函数更安全、更灵活,可以进行类型检查,有自己的作用域和命名空间,提供更好的调试和错误信息。而宏函数则更接近于简单的文本替换,没有类型检查和作用域的概念,可能会产生不可预期的副作用。因此,推荐在C++中使用内联函数,除非特殊情况下需要使用宏函数的特性和灵活性。

四、空指针和野指针的区别

1.空指针(Null Pointer):

空指针表示指针不指向任何有效的对象或函数。在C和C++中,空指针通常使用特殊的值0来表示,也可以使用宏定义NULL或C++11引入的nullptr关键字。
空指针指向的是一个已知的特殊地址,该地址被保留给表示空指针的目的。对空指针进行解引用操作(如访问指针指向的内存)将产生未定义的行为。

2.野指针(Dangling Pointer):

野指针是指指针变量持有一个无效的、未定义的内存地址。野指针可能是一个已被释放的内存地址,或者指向还未分配给有效对象的内存区域。
野指针是一种危险的编程错误,使用野指针可能导致程序崩溃、内存错误和不可预测的行为。

五、访问野指针和空指针会发生什么

访问野指针:

可能导致程序崩溃或异常终止。
可能读取到不可预测或无效的数据,导致意外结果。
可能引发安全漏洞,如信息泄露或缓冲区溢出。

访问空指针:

可能导致段错误(Segmentation Fault)或空指针异常,终止程序。
可能出现未定义的行为,造成程序行为无法预测。

六、C++面向对象的三要素

1.封装(Encapsulation):

封装是一种将数据和操作捆绑在一起的机制,以创建一个类(Class)。类将数据(成员变量)和操作(成员函数)组合在一起,可以隐藏实现的细节,只暴露必要的接口给外部使用。
封装通过访问控制(public、private、protected)提供了对数据的保护,使得数据只能通过类的接口进行访问和修改。
封装可以实现信息隐藏和数据隔离,提高代码的可维护性、灵活性和安全性。

2.继承(Inheritance):

继承是一种机制,允许一个类(称为子类或派生类)基于另一个类(称为父类或基类)建立,并且可以继承父类的属性和行为。
通过继承,子类可以重用父类的代码,避免代码的重复编写,并且可以扩展或修改父类的行为。
继承实现了类之间的关系,如“is-a”关系,其中子类可以视为父类的一种类型。

3.多态(Polymorphism):

多态是指能够使用基类(父类)的指针或引用来引用派生类(子类)对象,并根据上下文自动选择正确的方法执行。
多态允许使用相同的接口处理不同的对象,通过重写(覆盖)基类的虚函数实现特定类的行为。
多态提高了代码的可扩展性和灵活性,使得程序可以根据不同的对象类型采取适当的动作。

七、if(0 == x) 和 if(x == 0)

一般来说很多人习惯使用if(x == 0),但是也有一些人是使用if(0 == x)的,使用if(0 == x)这种写法能够保证 == 不被误写为 = 导致出现错误。

八、二维数组地址是否连续

一个二维数组的地址在内存中是连续的。二维数组在内存中以行主序(row-major order)连续存储其元素。

int arr[3][4];

在内存中,它会以如下的方式连续存储:

arr[0][0]   arr[0][1]   arr[0][2]   arr[0][3]   arr[1][0]   arr[1][1]   arr[1][2]   arr[1][3]   arr[2][0]   arr[2][1]   arr[2][2]   arr[2][3]

因此,二维数组的地址是连续的,可以通过指针算术运算来访问数组中的元素。

例如,可以使用指针来访问二维数组中的元素:

int arr[3][4] = {
    
    {
    
    1, 2, 3, 4}, {
    
    5, 6, 7, 8}, {
    
    9, 10, 11, 12}};
int *ptr = &arr[0][0];

for (int i = 0; i < 12; i++) {
    
    
    printf("%d ", *(ptr + i));
}

以上代码将打印出连续存储的二维数组的元素值:

1 2 3 4 5 6 7 8 9 10 11 12

所以,对于连续分配的二维数组,其地址是连续的,可以通过指针算术运算来访问和操作二维数组的元素。

总结

本篇文章就讲解到这里。

猜你喜欢

转载自blog.csdn.net/m0_49476241/article/details/132395760