嵌入式面试八股文之C语言

C语言

1、const

主要用于定义常量,起到强制保护的作用,确保不会被意外修改。

有以下三个用法:

(1)修饰常量

(2)修饰形参

(3)修饰类型成员函数

2、static

主要用于以下三种:

(1)静态局部变量-生周期延长到程序结束。

(2)静态全局变量-限制作用域在本文件。

(3)静态函数-限制作用域为本文。

局部变量存放到哪里:.bss(未初始化)/.data(已初始化)。

3、volatile

主要用于:告诉编译器此变量有可能会意外被修改,不要优化对它的读写。

在嵌入式中常用于:

(1)硬件寄存器。

(2)中断服务程序修改的全局变量。

(3)多线程/RTOS共享的变量。

(4)DMA传输的缓冲区。

4、指针

指针是一个变量,它存储的值是另一个变量的内存地址。

5、函数指针

函数指针就是存储函数的入口地址,通过它可以间接调用函数。也就是说:是一个指针,指向函数的地址。

在嵌入式常用于:回调函数,状态机、函数跳转表

1
2
3
4
5
//定义一个函数
int add(int a,int b) {return a + b;}
//声明函数指针变量
int (*fun)(int,int);
fun=add;

6、指针函数

指针函数就是它是一个函数,函数的返回值是一个地址。

1
2
3
4
5
6
7
8
9
10
//定义一个函数,返回值为指针
int *fun(int a,int b){
static int result;
result = a + b;
return &result;
}
//调用后得到的是地址
int *p = fun(2,3);
//取值
print("%d\n",*p);

7、指针数组

指针数组就是由指针组成的数组。

1
2
//5个 int *指针组成的数组
int *p1[5];

8、数组指针

数组指针就是指向数组的指针

1
int (*p2)[5];

9、返回函数指针的函数

返回函数指针的函数就是返回值为函数指针的函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
//定义普通函数
int add(int a,int b){return a + b;}
//定义一个返回函数指针的函数
int (*get_fun(char op))(int,int)
{
if(op == '+') return add;
return NULL;
}
//调用得到的是函数指针
int (*fun)(int,int);
fun = get_fun('+');
//通过函数指针调用函数
printf("%d\n",fun(2,3));

10、struct 与 union

struct:所有成员各占独立内存

union:所有成员共用一块内存,大小是最大成员

11、结构体

结构体就是把不同类型的数据打包成一个整体。

在嵌入式中常用于:组织寄存器映射,协议帧、配置参数等复合数据。

1
2
3
4
5
6
7
8
typedef struct{
char name[20];
int age;
float score;
}Student;
Student s1 = {"Alice",20,95.5};
Student *ps = &s1;
printf("%s %d %f\n",ps->name,ps->age,ps->score);

12、链表

链表就是用指针把分散的内存块串起来的数据结构:访问慢(必须从头找),但插入删除快(只改指针),且大小可以动态增长(随用随 malloc)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

//链表节点:数据 + 指向下一个节点的指针
struct node {
int data; //数据域
struct node *next; //指针域,指向下一个节点
};

//手动构建一个链表:1 -> 2 -> 3 -> NULL
struct node n1 = {1, NULL};
struct node n2 = {2, NULL};
struct node n3 = {3, NULL};
n1.next = &n2; //n1 指向 n2
n2.next = &n3; //n2 指向 n3

//遍历链表
struct node *p = &n1; //p 是头指针
while(p != NULL){
printf("%d\n", p->data);
p = p->next; //走到下一个节点
}


//头插法动态创建链表(新节点插到链表头部)
struct node *head = NULL;

void insert_head(int val)
{
struct node *new_node = malloc(sizeof(struct node));
new_node->data = val;
new_node->next = head; //新节点指向原来的头
head = new_node; //头指针更新为新节点
}

//删除指定值的节点
void delete_node(int val)
{
struct node *p = head, *prev = NULL;
while(p && p->data != val){ //找到目标节点
prev = p;
p = p->next;
}
if(p == NULL) return; //没找到
if(prev == NULL) head = p->next; //删的是头节点
else prev->next = p->next;//中间/尾部节点
free(p); //释放内存
}