嵌入式笔试【1】

1.递归函数定义没有问题,递归深层次后易引发什么问题?

递归函数定义没有问题,但是递归深度过深时,可能会引发以下问题:

  1. 栈溢出问题:每当一个函数被调用时,操作系统会为该函数创建一个新的栈帧,以存储该函数的局部变量和参数等。递归函数在深度过深的情况下,会导致系统栈空间被快速耗尽,从而引发栈溢出错误。
  2. 时间和空间效率低下:对于深度递归,系统需要频繁地创建和销毁栈帧,这会消耗大量的CPU时间和内存。如果递归深度过深,或者递归算法本身就不高效,那么这种时间和空间效率的消耗会变得非常明显。
  3. 可读性和可维护性降低:深度递归可能会使得代码难以理解和维护。在阅读递归函数时,我们需要理解每个递归步骤是如何对问题进行分解的,这可能需要花费大量的时间和精力。此外,如果递归深度过深,那么函数中的控制流程可能会变得异常复杂,这也会使得代码更难维护。
  4. 陷入死循环:如果递归没有正确的终止条件,或者在递归过程中遇到了无法解决的情况,那么递归可能会陷入无限循环中。这会使得程序无法正常运行,甚至可能导致系统崩溃。

因此,虽然递归是一种强大的编程工具,但在使用时需要注意其可能带来的问题,并尽量避免使用深度递归。如果必须使用深度递归,那么应该注意检查和优化算法的效率,并提供足够的栈空间以防止栈溢出错误。

 2、堆与栈的区别?

堆和栈是两种不同的数据结构,它们在计算机内存中的使用方式和管理方式都有所不同。以下是它们的主要区别:

  1. 分配方式:堆是动态分配的,而栈是静态分配的。这意味着堆的空间是在运行时动态分配和释放的,而栈的空间是在编译时确定并静态分配的。
  2. 存储方式:堆是存储全局变量和动态内存分配的区域,而栈是存储局部变量和函数参数的区域。这意味着堆主要用于存储程序中动态分配的内存,而栈主要用于存储程序中局部变量和函数调用相关的信息。
  3. 空间大小:堆的大小通常比栈大,因为堆用于存储大量的数据和对象。而栈的大小则受限于操作系统给定的栈空间大小,通常只有几MB。
  4. 内存管理:堆需要程序员手动管理内存的分配和释放,如果不正确地使用会导致内存泄漏或野指针。而栈则由编译器自动管理内存的分配和释放,不需要程序员手动干预。
  5. 访问速度:栈的访问速度比堆快,因为栈中的数据存储在内存的连续区域,可以被CPU直接访问。而堆的数据则可能分散在内存的各个位置,访问速度相对较慢。
  6. 使用场景:堆通常用于实现动态内存分配和对象实例化,例如在C++中使用new和delete操作符。而栈则通常用于存储程序中的局部变量和函数调用相关的信息,例如在函数调用时存储参数和局部变量。

总之,堆和栈是两种不同的数据结构,它们在内存中用于不同的目的,具有不同的管理方式和访问速度。正确地使用它们可以提高程序的效率和稳定性。

3、循环控制条件关键字goto被经常使用,但是goto的使用场合为什么受到局限? 

因为goto会破坏程序的栈逻辑

4、循环控制条件关键字goto的使用场景有哪些? 

尽管 goto 语句在编程中被广泛认为是不良的实践,因为它可能破坏程序的结构,导致资源泄露,引发无限循环等问题,但是在一些特定场景中,使用 goto 仍然是合理的。这些场景包括:

  1. 错误处理和资源清理:在 C 和 C++ 等语言中,goto 常常被用于错误处理和资源清理。例如,在打开文件或分配内存后,如果发生错误,goto 可以用于跳转到标签,进行资源清理和错误报告。然而,这种用法在面向对象的编程语言中较少使用,因为它们有更高级的错误处理机制和垃圾回收功能。
  2. 跳出多重循环:在一些情况下,当需要在嵌套循环中满足某个条件时,可以使用 goto 直接跳转到循环之外。然而,这种用法要谨慎,因为过度使用可能导致代码难以理解和维护。通常,使用条件语句来替代 goto 是更好的选择。
  3. 实现非线性控制流程:在一些特殊情况下,goto 可以用于实现非线性控制流程,例如用于算法的某些特殊步骤,或者实现类似于事件驱动的系统。然而,这种用法应尽可能地避免,因为它们通常会使程序变得难以理解和维护。

总的来说,尽管 goto 在某些特定场景中可能有其用途,但在大多数情况下,应避免使用 goto,而应优先考虑使用结构化的控制流语句(如 if、for、while 等)来组织代码。

5. 有以下程序段, 执行后,mul 的值为  105 。

int a[ ]={1,3,5,7,9}; 
int mul, *data, x;
mul=1; 
data=&a[1]; 
for(x=0; x<3; x++) 
mul *= *(data+x);

该程序段使用指针data遍历数组a中的元素,然后将这些元素相乘,最后将结果存储在变量mul中。

程序执行流程如下:

  1. 定义一个数组a,包含5个元素:1, 3, 5, 7, 9。
  2. 定义一个整数变量mul,初始化为1。
  3. 定义一个指向数组a的指针data,并将其指向数组的第二个元素(即a[1])。
  4. 使用for循环遍历数组a的前三个元素(从索引0到2),并将它们相乘。
  5. 在每次循环中,使用指针data访问当前索引的元素,并将其乘以mul。然后将结果存储在mul中。
  6. 循环结束后,mul的值将是 3 * 5 * 7 = 105。

因此,执行完这段程序后,变量mul的值为105。

6. 请声明Func函数:返回值为“int *”类型,两个形参为“double”和“char *”;并定义Func函数的函数指针p,将Func函数的首地址赋给指针变量p。

// 声明Func函数  
int* Func(double d, char* str);  
  
// 定义Func函数  
int* Func(double d, char* str) {  
    // 在这里,你可以根据d和str的值创建一个int数组,并返回它的地址。  
    // 这里只是一个示例,返回一个固定值的指针。  
    static int arr[2] = {1, 2};  
    return arr;  
}  
  
// 定义Func函数的指针p  
int (*p)(double, char*) = Func;

7.什么是进程、线程,有什么区别?

进程是资源(CPU、内存等)分配的基本单位,线程是CPU调度和分配的基本单位。统一时间,如果CPU是单核,只有一个进程在执行。所谓并发,也是顺序,只不过由于切换速度太快,你以为这些进程在同步执行而已,多核CPU可以同一个时间点,有多进程在执行。

你可能感兴趣的:(嵌入式知识点,c++,iot,单片机,mcu,物联网,51单片机,stm32)