嵌入式面试(笔试)笔记1
本文是对于下面链接的B站系列视频的学习笔记
语言笔试题,C++笔试题,嵌入式笔试题,面试题,难点疑点解析(持续更新)
在另外一篇文章的基础上增加或者强调一些对自己更重点的知识
另一篇文章的链接:
【常见c语言笔试题嵌入式软件开发1】
P6:下面代码是否有问题,如果有问题,那么编译运行后的结果是什么,并说明问题的原因是什么,该怎么修改
#include<stdio.h>
char *get_str(void);
int main(void)
{
char *p = get_str();
printf("p = %s\n",p);
return 0;
}
char *get_str(void)
{
char str[] = "abcd";
return str;
}
错误原因:str是局部变量,保存在栈中,当get_str执行完str就会被释放,指针p中的地址无法保存下str的值
修改方式:
char *get_str(void)
{
//第一种方式,定义一个常数指针,数据保存在static区,不会被释放
char *str = "abcd";
//第二种方式,加一个static,让这个变量不会因为函数的结束而释放
static char
return str;
}
P7:下面所示代码的运行结果是什么
int main(void)
{
unsigned int a = 6;
int b = -20;
(a+b>6)? puts(">6"):puts("<6");
return 0;
}
有符号整型和无符号整型相加,有符号整型将会自动转化成无符号整形,数字在计算机中以补码形式存在,-20为:
原码:1000 0000 0000 0000 0000 0000 0001 0100
反码:1111 1111 1111 1111 1111 1111 1110 1011
补码:1111 1111 1111 1111 1111 1111 1110 1100
所以无法得到想要的-14结果。
printf("a+b = %d\n",a+b); //输出-14,因为%d是有符号数,会将结果转化成有符号
printf("a+b = %ud\n",a+b);//输出4294967282,因为%ud是无符号数
P8:什么是大端模式,什么是小端莫斯,编写代码测试你的计算机是大端模式还是小端模式?
大端模式:数据的低位存放在高地址中,数据的高位存放在低地址中
小端模式:数据的低位存放在低地址中,数据的高位存放在高地址中。
#include <stdio.h>
int main(void)
{
union T
{
unsigned int n;
char arr[4];
}t;
t.n = 0x12345678;
int i = 0;
for(i = 0;i<4;i++)
{
printf("&arr[%d] = %p,arr[%d] = 0x%x\r\n",i,&t.arr[i],i,t.arr[i]);
}
}
补充:关于union
联合体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。
例:在项目中给一个uint32数赋值,但是之后可能会用到他的uint16或者uint8形式
union bit32
{
uint32 u32;
struct u16ViewInt32
{
uint16 _0;
uint16 _1;
}w,u16View;
struct u8ViewInt32
{
uint8 _0;
uint8 _1;
uint8 _2;
uint8 _3;
}B,u8View;
struct F32
{
uint32 _0 : 1;
uint32 _1 : 1;
uint32 _2 : 1;
...
uint32 _31 : 1;
}F;
};
P10: 考虑下面的代码,其作用是在数组中查找一个特定的元素,如果将&&写成了&下面两种方式是否都可以实现?
//方式一
i = 0;
while(i < arrsize && arr[i] != x)
i++;
//方式二
i = 0;
while(i < arrsize & arr[i] != x)
i++;
在本例中,两种方式均可以得到正确的结果,但是方式二是有问题的,
情况1:
5&&10 --> 1
5&10 -->0101 & 1010 -->0000
情况2:
当使用&&时,若前面的条件不满足,则直接返回0不会再继续看后面的条件,但是使用&时,两个条件都会计算,所以可能产生i越界的情况。
P13:举例说明"##"运算符的作用
##预处理的 粘合剂 将2个符号转成一个符号
#include <stdio.h>
#define XNAME(n) x##n
int main(void)
{
//int x1 = 10;
int XNAME(1) = 10 ; //x1 ---> int x1 = 10;
printf("%d\n",x1);
return 0;
}
注:如果n的后面还有有别的字符,那么n的后面也需要加##
#include <stdio.h>
#define XNAME(n) x##n##2
int main(void)
{
//int x1 = 10;
int XNAME(1) = 10 ; //x12 ---> int x12 = 10;
printf("%d\n",x12);
return 0;
}
P18:哨兵思想
哨兵顾名思义是处于边界的兵,它的作用是简化边界条件的处理,降低时间复杂度里面的常数因子。
比如:
假如有100个纸箱,每个箱子里面都有一张纸条,纸条上写有1 ~ 10000这些数字,数字不会重复。现在给了一个随机的数字,我们需要在这100个箱子里找到与这个数字相同的纸条。
面对这个问题,最直觉的想法就是:从头开始,遍历这100个箱子,检查其中的纸条上数字是否与目标相同。这种方式在最差的情况下需要判断200次,因为每个箱子需要判断两次,一是检查这个箱子的纸条中的数字是否为我们想要的那个,二是判断遍历数是否大于100.
使用哨兵思想则是:在最后额外添加一个纸箱,并且在其中存放我们查找的目标数字,这样就不需要每次循环都判断遍历数是否大于100,只需要在找到想要的纸条后判断一次这个箱子是不是我们添加的那个就可以了,最差的情况下只需要判断101次,减少了时间复杂度。
P20: 64位和32位系统字节对齐问题
#include<stdio.h>
//#pragma pack(4)
typedef struct s
{
union
{
int a;
char b[10];
};
struct s* next;
}S;
int main()
{
printf("%lu\n", sizeof(struct s));
//#define offsetof(TYPE,MEMBER) ((size_t)&((TYPE*)0)->MEMBER)
printf("%ld\n",((size_t)&((S*)0)->next));
return 0;
}
如果没有struct s* next;
,那么printf("%lu\n", sizeof(struct s));
为12,因为此时struct中最大数据类型为int,则此时进行4字节对齐
如果加上struct s* next;
,那么printf("%lu\n", sizeof(struct s));
为24(16+8),因为此时struct中最大数据类型为struct s*
,则此时进行8字节对齐
关于字节对齐这部分我写了另一篇文章来学习:字节对齐学习笔记