2021-09-03

嵌入式C语言面试题(一)

在网上看到有一系列的嵌入式C语言面试题,不少题出得还不错,但是解答有的比较粗糙,有的未解释那么透彻,还有少部分存在一些漏洞和瑕疵,这里从中筛选出部分题目,写出我认为的答案,供大家参考,有说得不正确或者错误的,欢迎大家留言批评指正.

1.关键字static的作用

  1. 在函数里面的static 局部变量,其值在下次调用函数时仍然保留上次调用函数结束后的值,这意味着增加了static声明的函数局部变量,其数值在函数重入时可以保留. 静态局部变量和函数的普通局部变量不一样,他们存储在进程的静态存储区.
  2. 当在全局变量定义前增加static关键字,将表示这个全局变量仅仅能被当前模块(当前文件)所访问,其他模块或其他文件无法访问.
  3. 当在当前模块(文件)的函数前增加static关键字,则表示这个函数仅仅能被当前模块(当前文件)所调用,其他模块或其他文件无法调用.

2.“引用“与”指针“的差别

相同点:
1.指针指向一块内存,它的值是其指向的某个变量在内存中的地址;而引用是某个变量的别名。
2.指针和引用作为函数形参,两者都可以修改实参的值.
不同点:
1.指针是一个实体,而引用是一个别名;
2.引用只能在定义时初始化(必须初始化),而指针定义后随时都可以修改.
3.引用不能为空,但指针可以为空.
4.sizeof(引用)得到的是变量的大小,而sizeof(指针)得到的是指针占据的字节数.
5.C语言不支持引用,但C++支持引用.
6.C/C++的指针作为参数时,是值传递;而引用作为参数时,是引用(地址)传递,就是当引用作为函数形式参数时,被调函数对形式参数的任何修改都影响主调函数中的实参变量.

3.全局变量和局部变量在内存中是否有区别?如果有,是什么区别?全局变量和局部变量能否重名?

Linux进程的内存空间分配如下:
1.程序段(Text):程序代码在内存中的映射,存放函数体的二进制代码。
2.初始化过的数据(Data):在程序运行初已经对变量进行初始化的数据。
3.未初始化过的数据(BSS):在程序运行初未对变量进行初始化的数据。
4.栈 (Stack):存储局部、临时变量,函数调用时,存储函数的返回指针,用于控制函数的调用和返回。在程序块开始时自动分配内存,结束时自动释放内存,其操作方式类似于数据结构中的栈。
5.堆 (Heap):存储动态内存分配,需要程序员手工分配,手工释放.注意它与数据结构中的堆是两回事,分配方式类似于链表.
从上分析可以看到,局部变量保存在stack里面,函数调用后释放;全局变量放在Data段或者BSS段中,只有进程结束才会释放. 而heap则用于运行时内存分配(malloc,new).

可以,但是,当重名时,当执行到局部变量的有效区域(空间)时,局部变量将屏蔽全局变量,因此,程序设计时需要留意这汇总屏蔽行为是否为程序设计的初衷.
如果要区分,则使用::符号

4.堆栈溢出一般是由什么原因导致的?

1.堆栈溢出的原因一般是:递归过程的局部变量过多、递归深度过大,是造成系统栈溢出的原因,特别是递归列循环时肯定会发生系统栈溢出。
2.没有回收动态申请的内存.

5.不能做switch的参数?

switch()后面的参数只能是int,char,unsigned int,signed int.

6.全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?

可以.全局变量定义一次,但可以声明多次,对于常规的全局变量,如果定义在一个.h文件中,多个C文件include此头文件,在编译的时候不会出错,但在链接的时候会提示“重复定义”.
如果在.h文件中定义全局变量的地方增加static修饰符,则编译链接都可以通过,但是失去了全局变量的意义了.

7.什么是预编译,何时需要预编译?

预编译又称为预处理 , 是做些代码文本的替换工作。
处理以# 开头的指令 , 比如拷贝 #include 包含的文件代码,#define 宏定义的替换,条件编译等,就是为编译做的预备工作的阶段。
主要处理#开始的预编译指令,预编译指令指示了在程序正式编译前就由编译器进行的操作,可以放在程序中的任何位置。
C 编译系统在对程序进行通常的编译之前,首先进行预处理。
C提供的预处理功能主要有以下三种:
1)宏定义 
2)文件包含 
3)条件编译
何时需要预编译:
总是使用不经常改动的大型代码体。
程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。在这种情况下,可以将所有包含文件预编译为一个“预编译头”.

8.关键字const是什么含意?指针常量和常量指针的区别是什么?

const限制一个变量是常量,不能修改,程序中使用const可以在一定程度上提高程序的健壮性,const变量必须在定义的时候初始化.
需要区分指针常量和常量指针两个概念.
指针常量:即指针本身的值是不可改变的,而指针指向的变量的值是可以改变的;
常量指针:即指针指向的变量的值是不可改变的,而指针本身的值是可以改变的;
1 int a=3;
2 const intp=&a;//常量指针
3 int const
p1=&a;//常量指针
4 p=4;//error,常量指针,常量的值不能修改.
5 a=4;
这里有一个规则,大家可以参考下:如果const在’
‘左边,则表示指针指向的变量的值不可变(常量指针);如果const在’'右边,则表示指针的值是不可变的(指针常量);“
第2行,const在
左边,证明为常量指针,则p=4出错,第三行,const在""左边,证明为常量指针,指针指向的变量值不可修改.
下面10行代码
1 int a=1;//OK
2 int b=2;//OK
3 const intp;//const在’‘左边,则表示指针指向的变量的值不可变(常量指针).OK.建议初始化赋值.
4 int const* p1;//const在’'左边,则表示指针指向的变量的值不可变(常量指针).OK.建议初始化赋值.
5 int
const p2;//const 在* 右边,则表示指针本身的值不可变(指针常量),OK.建议初始化赋值.
6 int* const p3=&b;//const在* 右边,则表示指针本身的值不可变(常量指针),初始化赋值OK
7 p=&a;//p指向a,OK
8 p1=&a;//p1指向a,p1为常量指针,p1定义的时候未给定常量的值,在这里初始化赋值.OK
9 p2=&b;//p2为指针常量,在定义的时候未赋值,现在赋值,在gcc里面显示出错(assignment of read-only variable ‘p2’).error!
10 p3=&a;//p3的值不可修改,已经=&b,指针本身的值不可变,故error!
因此,这里有一个编译器优化的问题,按照我们的理解,无论是指针常量还是常量指针,在定义的时候都要初始化.但类似p2(指针常量)这种情况,在定义的时候未初始化,后面初始化则出错.但p1(常量指针)在定义的时候也没有初始化,后面再赋值(p1=&a)为什么可以呢?原因很简单,因为p1是指向常量的指针,但是指针本身是可以变化的,只是指针指向的变量的值不变.

9.关键字volatile有什么含意 请给出三个不同的例子.

volatile告诉编译器,当前修饰的变量的值,很可能随时都会修改,请每次读取其数值时从内存读取,不要优化读取(比如从寄存器中取值).
1、多任务环境下各任务间共享的标志应该加volatile;2、中断服务程序中修改的供其它程序检测的变量需要加volatile;3、存储器映射的硬件寄存器通常也要加voliate,因为每次对它的读写都可能有不同意义.

10.请说出const与#define 相比,有何优点?

1.const是常量,在定义时需初始化,后续其内容不能修改,修改则编译出错,因此,被Const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性.
2.#define只是一个宏,在预编译的时候,编译器会用其后面的值代替,不能起到类型安全检查的效果.

11.分别写出BOOL,int,float,指针类型的变量a与“零”的比较语句

BOOL a;
int a;
float a
int *a;
if (a)
if (a!=0)
if (abs(a-0)<0.00001)
if (a==’\0’)

12.论述含参数的宏与函数的优缺点?

带参宏 函数

处理时间: 编译时 程序运行时
参数类型: 没有参数类型问题 定义实参、形参类型
处理过程: 不分配内存 分配内存
程序长度: 变长 不变
运行速度: 不占运行时间 调用和返回占用时间

13.用两个栈实现一个队列的功能?要求给出算法和思路

建立2个栈,分别为A,B, 一开始均为空.按以下步骤操作:
1)入队列(入堆栈A)
2)数据依次PUSH入堆栈A,从堆栈A POP数据到堆栈B(PUSH到B),然后从B堆栈POP数据.
这样,最初PUSH入堆栈A的数据,POP出来PUSH到堆栈B,然后从B POP,那么,最先PUSH入A的数据,最后POP出A,最后PUSH到B,最先POP出B,因此,最先PUSH入A的数据,最先POP出B.-------这样就形成了一个queue(队列).

14.位操作(Bit manipulation) 嵌入式系统总是要用户对变量或寄存器进行位操作。给定一个整型变量a,写两段代码,第一个设置a的bit 3,第二个清除a 的bit 3。在以上两个操作中,要保持其它位不变.

1.使用C语言的位操作符,int a,第一段代码设置a的bit 3.
int a;
a = a|0b1000;

第二段清除a的bit3
int a;
a = a&FFFFFF7;
2. #define BIT3(0x1<<3)
a|= BIT3;
a&= ~BIT3;

15.访问固定的内存位置(Accessing fixed memory locations)

嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。在某工程中,要求设置一绝对地址为0x67a9的整型变量的值为0xaa66。编译器是一个纯粹的ANSI编译器。写代码去完成这一任务.

如果OS是big_ending(低地址存放高位数据).
short *p = 0x67a9;
*p = 0xaa;
p=0x67aa;
*p = 0x66;

如果OS是little_ending
short *p = 0x67a9;
*p = 0x66;
p=0x67aa;
*p = 0xaa;

16.一个单向链表,不知道头节点,一个指针指向其中的一个节点,问如何删除这个指针指向的节点?

假设指向此节点的指针为p,则将p->next的节点值copy到当前节点,然后把p->next=p->next->next,最后删除p->next.
int *p;//指向此节点
if §
int *p1 = p->next;
if (p1)
{
p->value = p1->value;
p->next = p1->next;
}
else
{
//无法删除最后一个节点.
}

17.写一个“标准”宏

#define swap(a,b) {a=ab;b=ab;a=b^a;}
#define swap(a,b) {a=a-b;b=a-b;a=a-b;}
#define MAX(a,b) ((a)>(b))?(a):(b)

18.解释局部变量、全局变量和静态变量的含义

1.局部变量:在函数内部定义的变量,仅仅在函数内有效,当其定义时前面没有加static修饰词时,局部变量由进程在函数调用时通过栈申请内存,函数调用结束则相关内存释放,当再次调用函数时局部变量将重新申请
2.全局变量:在函数外部定义的变量,当前面没有加static修饰词时,通过在引用此全局变量的模块中进行声明可以在整个程序中访问;当全局变量已初始化,其全局变量在静态存储区Data段,当全局变量未初始化,
则存储在静态存储区域bss段.
3.静态变量:静态变量分为静态局部变量和静态全局变量.静态局部变量在函数内定义,但不通过栈申请内存,而存储在静态存储区(data段或者bss段);静态全局变量仅仅只能被当前文件或当前模块访问.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用python中的pymsql完成如下:表结构与数据创建 1. 建立 `users` 表和 `orders` 表。 `users` 表有用户ID、用户名、年龄字段,(id,name,age) `orders` 表有订单ID、订单日期、订单金额,用户id字段。(id,order_date,amount,user_id) 2 两表的id作为主键,`orders` 表用户id为users的外键 3 插入数据 `users` (1, '张三', 18), (2, '李四', 20), (3, '王五', 22), (4, '赵六', 25), (5, '钱七', 28); `orders` (1, '2021-09-01', 500, 1), (2, '2021-09-02', 1000, 2), (3, '2021-09-03', 600, 3), (4, '2021-09-04', 800, 4), (5, '2021-09-05', 1500, 5), (6, '2021-09-06', 1200, 3), (7, '2021-09-07', 2000, 1), (8, '2021-09-08', 300, 2), (9, '2021-09-09', 700, 5), (10, '2021-09-10', 900, 4); 查询语句 1. 查询订单总金额 2. 查询所有用户的平均年龄,并将结果四舍五入保留两位小数。 3. 查询订单总数最多的用户的姓名和订单总数。 4. 查询所有不重复的年龄。 5. 查询订单日期在2021年9月1日至9月4日之间的订单总金额。 6. 查询年龄不大于25岁的用户的订单数量,并按照降序排序。 7. 查询订单总金额排名前3的用户的姓名和订单总金额。 8. 查询订单总金额最大的用户的姓名和订单总金额。 9. 查询订单总金额最小的用户的姓名和订单总金额。 10. 查询所有名字中含有“李”的用户,按照名字升序排序。 11. 查询所有年龄大于20岁的用户,按照年龄降序排序,并只显示前5条记录。 12. 查询每个用户的订单数量和订单总金额,并按照总金额降序排序。
最新发布
06-03

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值