嵌入式面试八股文·C语言高频面经(一)

发布于:2025-02-28 ⋅ 阅读:(14) ⋅ 点赞:(0)

在这里插入图片描述

1. 全局变量和局部变量的区别

1.1 全局变量

① 在函数外部声明的变量,整个程序都可以访问;
② 声明时会被默认初始化,可以在任何函数中使用;
③ 生命周期长,整个程序执行期间都存在;
④ 全局变量存储在全局数据区(data)中。

1.2 局部变量

① 在函数内部或代码块内部声明的变量,只能在所属的函数或代码块中访问;
② 声明时没有默认初始化,需要手动赋值才能使用;
③ 生命周期短,只在所属的函数或代码块的执行期间存在;
④ 局部变量存储在栈区(stack)。

2. 内存布局

代码段(Text Segment):存储程序的机器码,通常是只读的,因为程序的指令在执行过程中不应该被修改。
数据段(Data Segment):存储已初始化的全局变量和静态变量,这些变量在程序开始运行时已经赋予了初始值。
BSS段(Block Started by Symbol):存储未初始化的全局变量和静态变量,它们在程序开始运行时会自动初始化为0或者空指针。
堆(Heap):用于动态内存分配,用于存放程序运行时动态申请的内存。(程序员可以通过函数(如malloc、calloc等)或者操作系统提供的接口来申请和释放堆内存,堆从低地址向高地址增长。)
栈(Stack):存放函数的局部变量、函数参数值以及函数调用和返回时的相关信息。栈区是按照“先进后出”的原则进行管理,内存的分配和释放是自动进行的,栈从高地址向低地址增长。是一块连续的空间。
共享区:也称为文件映射或共享内存,用于实现不同进程之间的内存共享。
在这里插入图片描述

3. static关键字

① 声明静态变量,使其生命周期延长或作用域限定在当前文件内;
② 声明静态函数,使其作用域限定在当前文件内;
③ 声明静态成员变量,使其属于类本身而不是对象,多个对象共享同一份内存;
④ 使用静态限定符,控制变量的初始化和生命周期。

4. const关键字

① 值不可修改:一旦常量被赋值后,其值将保持不变,不能再对其进行修改;
② 作用域限制:常量的作用域通常被限制在声明时所在的作用域内部;
③ 编译时确定:常量的值在编译时就已确定,并在运行时保持不变。

5. const 和 #define的区别

① const是一种编译器关键字,而#define是预处理器指令。const在编译阶段进行处理,而#define在预处理阶段进行处理;
② const定义的常量具有类型,而#define没有。const在声明时需要指定常量的类型,编译器会进行类型检查。而#define只是简单的文本替换,没有类型检查;
③ const定义的常量有作用域限制,可以根据声明位置的不同而有不同的作用域。而#define定义的常量没有作用域限制,整个程序中都有效;
④ const生成符号表中的一个符号,有明确的名字和类型,可以进行调试和符号查找。而#define没有生成符号表,不会产生对应的符号。

6. extern关键字

① 声明一个在其他文件中定义的外部变量或函数;
② 告诉编译器在链接过程中需要找到对应的定义;
③ 允许在当前文件中使用这些外部变量或函数而不需要重新定义。

7. #include<> 和 #include""的区别

7.1 使用 #include<>

① 用于包含系统提供的标准库头文件;
② 在编译器的搜索路径中寻找头文件;
③ 编译器会先在系统的标准头文件目录中查找,如果找不到则报错。

7.2 使用 #include""

① 用于包含用户自定义的头文件或项目中使用的其他非系统头文件;
② 在当前源文件的相对路径或指定的绝对路径中寻找头文件;
③ 编译器会首先在当前源文件所在目录中查找,如果找不到再根据指定的路径查找。

8. 头文件#ifndef/#define/#endif的作用

① #ifndef:用于判断当前头文件是否已经被包含。如果该宏之前没有被定义过,则继续编译下面的代码。如果该宏之前已被定义过,则跳过下面的代码,直接到 #endif;
② #define:用于定义一个宏。通过定义一个特定的宏名称,例如MY_HEADER_H表示头文件已被包含;
③ #endif:用于结束 #ifndef / #define / #endif 块。标记了头文件的结束位置。

#ifndef MYHEADER_H     // 如果 MYHEADER_H 还没有被定义
#define MYHEADER_H     // 定义 MYHEADER_H

void sayHello();       // 函数声明

const int MAX_VALUE = 100;  // 常量定义

#endif               // 结束条件编译

9. volatile声明的作用

volatile声明的变量是指可能会被意想不到地改变的变量,这样编译器就不会轻易优化该变量。它主要用于多线程编程中,用来保证共享变量的内存可见性。(注:指针也可用volatile)
三个常见场景:
① 多线程中的共享变量
② 中断程序中访问到的非自动变量
③ 并行设备的硬件寄存器

10. strcpy与memcpy的区别

10.1 strcpy

① 用于字符串拷贝。
② 源字符串中的内容会被复制到目标字符串中,直到遇到字符串结束符 ‘\0’。
③ 目标字符串必须有足够的空间来存储被复制的内容,否则可能导致缓冲区溢出。

10.2 memcpy

① 用于字节级别的内存拷贝。
② 可以拷贝任意类型的内存块,不仅限于字符串。
③ 不会检查字符串结束符,通过指定要拷贝的字节数进行拷贝。
④ 可以用于拷贝部分或完整的数组、结构体等。

11. 数组名与指针的区别

11.1 数组名

① 是一个常量指针,指向数组的首元素。
② 大小固定为整个数组的大小。
③ 无法被改变或重新赋值。
④ 无法进行指针运算。

11.2 指针

① 是一个变量,存储一个内存地址。
② 大小固定为指针类型的大小。
③ 可以指向任意类型的对象。
④ 可以被改变或重新赋值。
⑤ 可以进行指针运算,如加法、减法等。

12. 结构体和共用体的区别

12.1 结构体

① 成员在内存中独立存储,每个成员占用独立的内存空间。
② 内存占用是成员之和,每个成员都占用独立的空间。
③ 成员可以同时被访问,通过成员名字来访问。
④ 适合存储和处理多个不同类型的数据,如员工信息、图形对象等。

12.2 共用体

① 成员共享同一块内存空间,只能存储一个成员的值。
② 内存占用是最大成员的大小,


网站公告

今日签到

点亮在社区的每一天
去签到