嵌入式面试题

Posted kunx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了嵌入式面试题相关的知识,希望对你有一定的参考价值。

来自互联网,2020整理

1、

int a[10]={1,2,3,4,5,6,7,8,9,0};
int *p=&a[1];
   则p[6]等于?

答:8;这个还是很好理解的p[0]=2嘛

2、整数数组清零的函数有?

#include <strings.h>

void bzero(void *s, size_t n);

void * memset ( void * ptr, int value, size_t num );

3、sizeof();的作用

功能是返回一个变量或者类型的大小(以字节为单位);

4、考查指针

main()
{
    char* str[] = { "ab","cd","ef","gh","ij","kl" };
    char* t;
    t = (str + 4)[-1];
    printf("%s", t);
}
结果是?

答:

gh;用第1题的思想

5、例如:int a=0x12345678;(a首地址为0x2000),问大端怎么存储?
答:
小端:低位字节数据存储在低地址   
大端:高位字节数据存储在低地址  

0x2000  0x2001  0x2002  0x2003  
0x12    0x34    0x56    0x78      大端格式

6、异步IO和同步IO区别?

如果是同步IO,当一个IO操作执行时,应用程序必须等待,直到此IO执行完,相反,

异步IO操作在后台运行,IO操作和应用程序可以同时运行,提高系统性能,提高IO流量;

在同步文件IO中,线程启动一个IO操作然后就立即进入等待状态,直到IO操作完成后才醒来继续执行,

而异步文件IO中,线程发送一个IO请求到内核,然后继续处理其他事情,内核完成IO请求后,将会通知线程IO操作完成了。

7、返回什么?

int foo(void)
{
    int i;
    char c = 0x80; //1000 0000-取反+1 是 11000 0000=-128
    i = c;
    if (i > 0)
        return 1;
    return 2;
}

答:返回值为2;因为i=c=-128;如果c=0x7f,则i=c=127。

 

8、效率最高的算法

a = b * 2; 
    a = b / 4; 
    a = b % 8; 
    a = b / 8 * 8 + b % 4; 
    a = b * 15;

a = b * 2->a = b << 1;
    a = b / 4->a = b >> 2;
    a = b % 8->a = b & 7;
    a = b / 8 * 8 + b % 4->a = ((b >> 3) << 3) + (b & 3)
    a = b * 15->a = (b << 4) - b

 

 

9、c关键字有?

 c的关键字共32个
 *数据类型关键字(12char,short,int,long,float,double,unsigned,signed,union,enum,void,struct
 *控制语句关键字(12if,else,switch,case,default,for,do,while,break,continue,goto,return
 *存储类关键字(5)
 auto,extern,register,static,const
 *其他关键字(3sizeof,typedef,volatile

 

 

10、返回什么

int main(void)
{
    unsigned int a = 6;
    int b = -20;
    char c;
    (a + b > 6) ? (c = 1) : (c = 0);
}

答:c=1,

a+b=-14;如果a为int类型则c=0。
 原来有符号数和无符号数进行比较运算时(==,<,>,<=,>=),有符号数隐式转换成了无符号数(即底层的补码不变,但是此数从有符号数变成了无符号数),
 比如上面 (a+b)>6这个比较运算,a+b=-14,-14的补码为1111111111110010。此数进行比较运算时,
 被当成了无符号数,它远远大于6,所以得到上述结果。

插入一个和此题无关知识点:所谓的函数是可重入的(也可以说是可预测的);宏定义是在预编译阶段被处理的

11、

输出什么

int main()
{
    int j = 2;
    int i = 1;
    if (i = 1) j = 3;
    if (i = 2) j = 5;
    printf("%d", j);
}

 输出为5;如果再加上if(i=3)j=6;则输出6。

12、Norflash与Nandflash的区别


 (1)、NAND闪存的容量比较大
 (2)、由于NandFlash没有挂接在地址总线上,所以如果想用NandFlash作为系统的启动盘,就需要CPU具备特殊的功能,
         如s3c2410在被选择为NandFlash启动方式时会在上电时自动读取NandFlash的4k数据到地址0的SRAM中。
 (3)、NAND Flash一般地址线和数据线共用,对读写速度有一定影响。NOR Flash闪存数据线和地址线分开,
         所以相对而言读写速度快一些。

 反码:对原码除符号位外的其余各位逐位取反就是反码
 补码:负数的补码就是对反码加1
 正数的原码、反码、补码都一样

13、内存管理MMU的作用
  *内存分配和回收
  *内存保护
  *内存扩充
  *地址映射 

 

14、printf可以接受多个参数,为什么,请写出printf的原型。

int printf ( const char * format, ... );

 

 

15、位转换,如1000 0000输出0000 0001

unsigned char  bit_reverse(unsigned char  c)
{
    unsigned char buf = 0;
    int bit = 8;
    while (bit)
    {
        bit--;
        buf |= ((c & 1) << bit);
        c >>= 1;
    }
    return buf;
}

 

 

16、字符串倒序

void inverted_order(char* p)
{
    char* s1, * s2, tem;
    s1 = p;
    s2 = s1 + strlen(p) - 1;
    while (s1 < s2)
    {
        tem = *s1;
        *s1 = *s2;
        *s2 = tem;
        s1++;
        s2--;
    }
}

 

17、引用和指针的区别

    (1). 指针是一个实体,而引用仅是个别名;
   (2). 引用使用时无需解引用(*),指针需要解引用;
   (3). 引用只能在定义时被初始化一次,之后不可变;指针可变;
   (4). 引用没有 const,指针有 constconst 的指针不可变;
   (5). 引用不能为空,指针可以为空;
   (6). “sizeof 引用”得到的是所指向的变量(对象)的大小,
    而“sizeof指针”得到的是指针本身(所指向的变量或对象的地址)的大小;
   (7). 指针和引用的自增(++)运算意义不一样;

 

18、队列和栈的区别

队列是先进先出,只能在一端插入另一端删除,可以从头或尾进行遍历(但不能同时遍历),
栈是先进后出,只能在同一端插入和删除,只能从头部取数据

19、TCP通信建立和结束的过程?端口的作用

三次握手和四次挥手;

端口是一个软件结构,被客户程序或服务进程用来发送和接收信息。

一个端口对应一个16比特的数。服务进程通常使用一个固定的端口。
    21端口:21端口主要用于FTP(File Transfer Protocol,文件传输协议)服务。  

20、物理地址转换成IP地址的协议?反之?

地址解析协议(ARP)的作用是将IP地址转换成物理地址;

反地址解析协议(RARP)则负责将物理地址转换成IP地址。

21、全局变量和局部变量的区别。

全局变量,储存在静态区.进入main函数之前就被创建.生命周期为整个源程序; 
 局部变量,在栈中分配.在函数被调用时才被创建.生命周期为函数内。

22、写一个程序, 要求功能:求出用1,2,5这三个数不同个数组合的和为100的组合个数。
   如:100个1是一个组合,5个1加19个5是一个组合。。。。 请用C++语言写。

答案:最容易想到的算法是:
 设x是1的个数,y是2的个数,z是5的个数,number是组合数
 注意到0<=x<=100,0<=y<=50,0<=z=20,所以可以编程为:

int number = 0;
    for (int x = 0; x <= 100; x++)
        for (int y = 0; y <= 50; y++)
            for (int z = 0; z <= 20; z++)
                if ((x + 2 * y + 5 * z) == 100)
                    number++;

 

23、内存对齐问题的原因?

平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据;
 性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐,因为为了访问未对齐的内存,处理器需要做两次内存访问,
     而对齐的内存访问仅需要一次。

24、比较一下进程和线程的区别?

(1)、调度:线程是CPU调度和分派的基本单位
 (2)、拥有资源:
  *  进程是系统中程序执行和资源分配的基本单位
  *  线程自己一般不拥有资源(除了必不可少的程序计数器,一组寄存器和栈),但他可以去访问其所属进程的资源,
     如进程代码,数据段以及系统资源(已打开的文件,I/O设备等)。
 (3)系统开销:
  *  同一进程中的多个线程可以共享同一地址空间,因此它们之间的同步和通信的实现也比较简单
  *  在进程切换的时候,涉及到整个当前进程CPU环境的保存以及新被调度运行的进程的CPU环境的设置;
     而线程切换只需要保存和设置少量寄存器的内容,并不涉及存储器管理方面的操作,从而能更有效地使用系统资源和
     提高系统吞吐量。

25、请问运行Test函数会有什么样的结果?

char* GetMemory(void)
{
    char p[] = "hello world";
    return p;
}
void Test(void)
{
    char* str = NULL;
    str = GetMemory();
    printf("%s
",str);
}

 答:可能是乱码。因为GetMemory返回的是指向“栈内存”的指针,该指针的地址不是 NULL,
 但其原现的内容已经被清除,新内容不可知。

26、请问运行Test函数会有什么样的结果?

void Test(void)
{
    char* str = (char*)malloc(100);
    strcpy(str, "hello");
    free(str);
    if (str != NULL)
    {
        strcpy(str, "world");
        printf("%s
",str);
    }
}

 答:篡改动态内存区的内容,后果难以预料,非常危险。因为free(str);之后,str成为野指针,
 if(str != NULL)语句不起作用。
 野指针不是NULL指针,是指向被释放的或者访问受限内存指针。
 造成原因:指针变量没有被初始化任何刚创建的指针不会自动成为NULL;
     指针被free或delete之后,没有置NULL;
     指针操作超越了变量的作用范围,比如要返回指向栈内存的指针或引用,因为栈内存在函数结束时会被释放。

27、

    unsigned char *p=(unsigned char *)0x0801000
    unsigned char *q=(unsigned char *)0x0810000

 p+5 =?    0x0801005
 q+5 =?    0x0810005

 

28、进程间通信方式:管道、命名管道、消息队列、共享内存、信号、信号量、套接字。

 (1)、 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。
       进程的亲缘关系通常是指父子进程关系。
 (2)、有名管道 (named pipe) :有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
 (3)、信号量( semophore ) :信号量是一个计数器,可以用来控制多个进程对共享资源的访问。
      它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。
      因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
 (4)、消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。
      消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
 (5)、信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
 (6)、共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,
      这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,
      如信号两,配合使用,来实现进程间的同步和通信。
 (7)、套接字( socket ) : 套接字也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。 

 

29、宏和函数的优缺点?

(1)、函数调用时,先求出实参表达式的值,然后带入形参。而使用带参数的宏只是进行简单的字符替换。
 (2)、函数调用是在程序运行时处理的,分配临时的内存单元;而宏展开则是在编译时进行的,在展开时并不分配内存单元,
   不进行值的传递处理,也没有“返回值”的概念。
 (3)、对函数中的实参和形参都要定义类型,二者的类型要求一致,应进行类型转换;而宏不存在类型问题,宏名无类型,
   它的参数也是无类型,只是一个符号代表,展开时带入指定的字符即可。宏定义时,字符串可以是任何类型的数据。
 (4)、调用函数只可得到一个返回值,而宏定义可以设法得到几个结果。
 (5)、使用宏次数多时,宏展开后源程序长,因为每次展开一次都使程序增长,而函数调用不使源程序变长。
 (6)、宏替换不占运行时间,只占编译时间;而函数调用则占运行时间(分配单元、保留现场、值传递、返回)。

 

30、5["abcdef"]能够编译通过,请问编译后的结果是什么?

printf("%d ",5["abcdef"]);输出‘f‘的ACSII值,如果是4["abcdef"]则输出‘e‘的ACSII的值。

31、下面都输出什么结果

sscanf("123456 ", "%4s", buf); //1234

sscanf("1234576 asdfga", "%[^ ]", buf); //1234576

sscanf("123456aafsdfADDEFFjj", "%[1-9a-z]", buf); //123456aafsdf

sscanf("123afsdfADJKLJpp", "%[^A-Z]", buf); //123afsdf

 

32、数组a[N],存放了1至N-1个数,其中某个数重复一次。写一个函数,找出被重复的数字.时间复杂度必须为o(N)函数原型:
  int do_dup(int a[],int N)   

int do_dup(int a[], int N)
{
    int* p = (int*)malloc(N * sizeof(int));
    for (int j = 0; j < N; j++)
    {
        p[j] = 0;
    }

    int result;
    for (int i = 0; i < N; i++)
    {
        if (p[a[i]] == 0)
        {
            p[a[i]] = a[i];
        }
        else
        {
            result = a[i];
            cout << "the repeated num is " << result << endl;;
            return result;
        }
    }
    free(p);
    return 0;
}

 

33、输出什么

char a = 100;
    char b = 150;//10010110//01101010
    unsigned char c;
    c = (a < b) ? a : b;

答:c=150

34、在C语言中memcpy和memmove是一样的吗?

memmove()与memcpy()一样都是用来拷贝src所指向内存内容前n个字节到dest所指的地址上,不同是,

当src和dest所指的内存区域重叠时,memmove()仍然可以正确处理,不过执行效率上略慢些。

35、C语言程序代码优化方法

  * 选择合适的算法和数据结构
  * 使用尽量小的数据类型
  * 使用自加、自减指令
  * 减少运算的强度
   求余运算(a=a%8改为a=a&7)
   平方运算(a=pow(a,2.0)改为a=a*a)
   用移位实现乘除法运算
  * 延时函数的自加改为自减
  * switch语句中根据发生频率来进行case排序

36、找出一个字符串中一个最长的连续的数字,并标注出位置和个数。

void main()
{
    char input[100];
    char output[100] = { 0 };
    int  count = 0, maxlen = 0, i = 0;
    char* in = input, * out = output, * temp = NULL, * final = NULL;

    printf("Please input string(length under 100):
");
    scanf("%s", input);
    printf("Input string is %s
", input);

    while (*in != )
    {
        if (*in >= 0 && *in <= 9)
        {
            count = 0;
            temp = in;
            for (; (*in >= 0) && (*in <= 9); in++)
                count++;
            if (maxlen < count)
            {
                maxlen = count;
                final = temp;
            }
        }
        in++;
    }

    for (i = 0; i < maxlen; i++)
        * (out++) = *(final++);
    *out = ;

    printf("Maxlen is %d
", maxlen);
    printf("Output is %s
", output);
}

 

37、

  int *a = (int *)2;
  printf("%d",a+3); 

答案是2+3*4=14;int类型地址加1 相当于加4个字节

38、输出什么

int main()
{
    
    char* p1 = (char*)"name";
    char* p2;
    p2 = (char*)malloc(20);
    memset(p2, 0, 20);
    while (*p2++ = *p1++) ;
    printf(" %s
", p2);
    return 0;
}

答案:Answer:empty string. 因p2++已经指到了‘‘了;

39、输出什么

#define N 500
unsigned char count;
for (count = 0; count < N; count++)
{
    printf("---%d---
", count);
}

死循环,因为unsigned char 最大为255

40、sizeof App =

struct App
{
    char t : 4; //4位
    char k : 4;// 4位
    unsigned short i : 8; //8位
    unsigned long m; // 偏移2字节保证4字节对齐
};

8

 


以上是关于嵌入式面试题的主要内容,如果未能解决你的问题,请参考以下文章

嵌入式工程师 面试题 集-C语言

嵌入式软件开发 C语言笔试面试题

Java工程师面试题,二级java刷题软件

听说是华为嵌入式软件工程师面试题

嵌入式开发—C语言面试题

高级嵌入式软件面试题专栏目录