大疆笔试题

第一套

(1)缓存和寄存器哪个比较快
CPU <— > 寄存器<— > 缓存<— >内存

(2)波特率是以什么为单位,比特率又是以为什么为单位
1波特即指每秒传输1个码元符号(通过不同的调制方式,可以在一个码元符号上负载多个bit位信息),1比特每秒是指每秒传输1比特(bit)。

用实际使用中,最常用的串口通讯协议举例,注意前置条件为:1 个起始位,8 个数据位,0 个校验位,1 个停止位,也就是我们常说的:8,N,1;8 个数据位,一个停止位,无校验位。
这个条件分析一下就是,如果我要传输一个字节(8 位)的数据,则我应该在总线上产生 10 个电平变换,也就是串行总线上,需要 10 位,才能发送 1 个字节数据。
1 秒可以发送 9600 位,那么用 9600/10 ,就是1秒可以发送 960 个字节数据,则每发送一个字节需要的时间就是:1/960 ~= 0.00104166…s ~= 1.0416667 ms。
此时就可以得出一个结论,在 9600 波特率下,大概 1ms 发送 1 个字节的数据。

(3)对ARM处理器异常的理解
外部中断,内部异常,系统调用都属于

(4)Cotex_M基础知识的掌握

(5)LDR R0,=0x12345678是直接将值赋给R0吗
就是把0x12345678这个地址中的值存放到r0中。

(6)IO密集型类知识

(7)支持优先级继承调度器会动态改变任务优先级?

(8)git命令相关知识

(9)哪些不是实时操作系统
需要注意的是带有RT的基本上都是实时性操作系统
WIN,Linux都是分时操作系统

(10)ARM_V8支持64位?
大致来说,ARMv8架构跟AMD和Intel的做法一样,采取64位兼容32位的方式。应用程序可以以32位模式执行,也可以以64位模式执行。

(11)NEON,PMIPB等操作

(12)SPI有几种工作模式
SPI总线有四种工作方式(SP0, SP1, SP2, SP3),其中使用的最为广泛的是SPI0和SPI3方式。

(13)栈空间大小会不会影响编译出来的bin固件大小
这个。。暂时还没听说过

(14)00编译优化是不是默认不优化

(15)inline内联基础知识及其作用
在 c/c++ 中,为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题,特别的引入了 inline 修饰符,表示为内联函数。栈空间就是指放置程序的局部数据(也就是函数内数据)的内存空间。

(16)给图片大小和码率还是啥,求带宽多少Gbps

(17)VTOR作用,普通中断是不是只把R0-R3数据压栈,PRIMASK作用
VTOR中断向量表偏移寄存器

cortex-M3 中断调用过程
入栈
中断发生后,中断服务函数运行前,会先把xPSR, PC, LR, R12以及R3‐R0总共8个寄存器由硬件自动压入适当的堆栈中(中断前使用的MSP就压入MSP,中断前使用的是PSP就压入PSP

(18)内联函数的作用
避免函数调用的开销

(19)ARM Cotex -M 都是哈佛体系?-A冯诺依曼体系?
有一些ARM(Cortex-M系列)是哈佛结构,而另一些ARM(Cortex-A)是冯诺依曼结构(或者更准确说是混合结构)。

(20)I2S总线相关知识
I2S特点
①支持全双工和半双工通信。(单工数据传输只支持数据在一个方向上传输;半双工数据传输允许数据在两个方向上传输,但是在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信;全双工数据通信允许数据同时在两个方向上传输,因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。
②支持主/从模式。(主模式:就是主CPU作为主机,向从机(挂载器件)发送接收数据。从模式:就是主CPU作为从机,接收和发送主机(挂载器件)数据。而主从机的分别其实是一个触发的作用,主机主动触发,从机只能被动响应触发。)

I2S总线拥有三条数据信号线:
1、SCK: (continuous serial clock) 串行时钟
对应数字音频的每一位数据,SCK都有1个脉冲。SCK的频率=2×采样频率×采样位数。
2、WS: (word select) 字段(声道)选择
用于切换左右声道的数据。WS的频率=采样频率。
命令选择线表明了正在被传输的声道。
WS为“1”表示正在传输的是左声道的数据。
WS为“0”表示正在传输的是右声道的数据。
WS可以在串行时钟的上升沿或者下降沿发生改变,并且WS信号不需要一定是对称的。在从属装置端,WS在时钟信号的上升沿发生改变。WS总是在最高位传输前的一个时钟周期发生改变,这样可以使从属装置得到与被传输的串行数据同步的时间,并且使接收端存储当前的命令以及为下次的命令清除空间。
3、SD: (serial data) 串行数据
用二进制补码表示的音频数据。 I2S格式的信号无论有多少位有效数据,数据的最高位总是被最先传输(在WS变化(也就是一帧开始)后的第2个SCK脉冲处),因此最高位拥有固定的位置,而最低位的位置则是依赖于数据的有效位数。也就使得接收端与发送端的有效位数可以不同。如果接收端能处理的有效位数少于发送端,可以放弃数据帧中多余的低位数据;如果接收端能处理的有效位数多于发送端,可以自行补足剩余的位(常补足为零)。这种同步机制使得数字音频设备的互连更加方便,而且不会造成数据错位。为了保证数字音频信号的正确传输,发送端和接收端应该采用相同的数据格式和长度。当然,对I2S格式来说数据长度可以不同。

(21)I2C主机发送__作为初始信号
起始信号:SCL为高电平期间,SDA线由高电平向低电平的变化

问答:
(1)栈空间大小多大,往一个数组写4K btye数据栈会不会溢出?如果会还有哪些情况会溢
出?如果不会溢出会发生什么问题?
自行测试linux的栈的默认空间在7~8Mbyte之间接近8M,通过ulimit -s可以知道理论值是8M
但是栈的空间是不固定的,我们可以用ulimit -s 10240 更改其栈空间,单位KByte
当然不同系统的默认栈值可能不一样,比如win系统的栈不到1M

对于堆内存来说,可以申请的内存非常大,几乎可以申请超万个G我也不知道为什么。
当一个进程退出后,不管是正常退出或者是异常退出,操作系统都会释放这个进程的资源。包括这个进程分配的内存。

(2)写一个宏定义,给一个结构体成员地址,返回结构体的首地址

编程题:
(1)给一个正整数n,求从1-n这些数字总共出现’1’的次数

#include <stdio.h>
int countnumOne(int n) {
    int count = 0;
    int fact = 1; // 位因子,从个位依次递增
    int lowpit = 0; // 低位数字
    while (n >= fact) {
        int cur = (n / fact) % 10; // 当前位数字
        if (cur > 1) {
            count += (n / (10 * fact) + 1) * fact;
        }
        else if (cur == 1) {
            count += (n / (10 * fact)) * fact + lowpit + 1;
        }
        else {
            count += (n / (10 * fact)) * fact;
        }
        lowpit += cur * fact;
        fact *= 10;
    }
    return count;
}
int main(void) {
    int n;
    printf("请输入正整数n:");
    scanf("%d", &n);
    printf("从1到%d,总共出现%d个1。\n", n, countnumOne(n));
    return 0;
}

(2)求圆周率的N位精度,这个N可能非常非常大

#include <stdio.h>
int a = 10000, b, c = 2800, d, e, f[2801], g;
main() {
    int i;
    for (i = 0; i < c; i++)
        f[i] = a / 5;
    while (c != 0)
    {
        d = 0;
        g = c * 2;
        b = c;
        while (1)
        {
            d = d + f[b] * a;
            g--;
            f[b] = d % g;
            d = d / g;
            g--;
            b--;
            if (b == 0) break;
            d = d * b;
        }
        c = c - 14;
        printf("%.4d", e + d / a);
        e = d % a;
    }
}

第二套

1.在32位系统中有如下定义,则sizeof(data_t)的值是()

    typedef struct data{
        char m:3;
        char n:5;
        short s;
        union{
            int a;
            char b;
        };
        int h;
    }__attribute__((packed)) data_t; 

sizeof(data_t) = 11;

2.程序按64位编译,运行下列程序代码,打印输出结果是多少

 #define CALC(x,y)  (x*y)
 
int main(void) { 
    int i=3;
    int calc;
    char **a[5][6];
 
    calc = CALC(i++, sizeof(a)+5);
    printf("i=%d, calc=%d\n", i, calc);
    return 0;
}

输出结果为:i=4, calc=725

注意在宏定义中带参数时括号的用法,在本题中#define CALC(x, y)    (x*y)的结果是725,但是如果这样写:#define  CALC(x,y)  (x)*(y) 的结果就是735

一般32位机器就是5*6*4 = 120,64位则是5*6*8=240 ,char *a是字符型指针,char **a是指针的指针,在64位和32位中指针的大小是不一样的

1、比较输入字符串s1和s2前n个字符,忽略大小写,如果字符串s1和s2相同则返回0,不同则返回第一个不同字符的差值。

tolower是一种函数,功能是把字母字符转换成小写,非字母字符不做出处理。

#include <stdio.h>  
#include <string.h>  
#include <ctype.h>  

int compare(const char* s1, const char* s2, unsigned int n)
{
    int c1, c2;
    do {
        c1 = tolower(*s1++);
        c2 = tolower(*s2++);
    } while ((--n > 0) && c1 == c2 && c1 != 0);
    return c1 - c2;
}
int main(void)
{
    int n = 4;
    char str3[100];
    char str4[100];
    scanf("%s %s", &str3, &str4);
    printf("compare(str3, str4, n) = %d", compare(str3, str4, n));
    return 0;
}

2、N X N数组,输出行中最小,列中最大的数的位置,比如:

1 2 3
4 5 6
7 8 9

输出:row=2,col=0

分析:

在矩阵中,一个数在所在行中是最大值,在所在列中是最小值,则被称为鞍点。

鞍点C++实现

#include <stdio.h>
#define N 3
int a[N][N]={1,2,3,4,5,6,7,8,9};
int main()
{
    int i,j,t,minj;
    for(i=0;i<N;i++)
    {
        t=a[i][0];
        minj=0;
        for(j=1;j<N;j++)//行上最小
        {
            if(a[i][j]<t)
            {
                t=a[i][j];
                minj=j;//找到了行上最小的数所在的列
            }
        }

        int k;
        for(k=0;k<N;k++)
            if(a[k][minj]>t)//判断是否列上最大
                break;
        if(k<N) continue;//接着查找下一行
        printf("所求点是:a[%d][%d]:%d\n",i,minj,t);
    }
    return 0;
}

 1、已知循环缓冲区是一个可以无限循环读写的缓冲区,当缓冲区满了还继续写的话就会覆盖我们还没读取到的数据。下面定义了一个循环缓冲区并初始化,请编写它的Write函数:

typedef struct RingBuf {
	char *Buf;
	unsigned int Size;
	unsigned int RdId;
	unsigned int WrId;
}RingBuf;
 
void Init(RingBuf *ringBuf, char *buf, unsigned int size) {
	memset(ringBuf, 0, sizeof(RingBuf));
	ringBuf->Buf = buf;
	ringBuf->Size = size;
	ringBuf->RdId = 0;
	ringBuf->WrId = strlen(buf);
}
 
void Write(RingBuf *ringBuf, char *buf, unsigned int len) {
	unsigned int pos = ringBuf->WrId;
 
	while (pos + len > ringBuf->Size) {
		memcpy(ringBuf->Buf + pos, buf, ringBuf->Size - pos);
		buf += ringBuf->Size - pos;
		len -= ringBuf->Size - pos;
		pos = 0;
	}
 
	memcpy(ringBuf->Buf + pos, buf, len);
	ringBuf->WrId = pos + len;
}
 
void Print(RingBuf *ringBuf) {
	for (int i = 0; i < ringBuf->Size; i++) {
		cout << ringBuf->Buf[i];
	}
	cout << endl;
}
 
int main()
{
	RingBuf *rb = (RingBuf *)malloc(sizeof(RingBuf));
	char init_str[] = "ABC";
	int size = 6;
	Init(rb, init_str, size);
 
	char p[] = "1234567";
	Write(rb, p, 7);
	Print(rb);
 
	return 0;
}

2、已知两个已经按从小到大排列的数组,将它们中的所有数字组合成一个新的数组,要求新数组也是按照从小到大的顺序。请按照上述描述完成函数:

int merge(int *array1, int len1, int *array2, int len2, int *array3); 

int merge(int *array1, int len1, int *array2, int len2, int *array3) {
	int retn = len1 + len2;
	if ((*array1 < *array2 || len2 == 0) && len1 > 0) {
		*array3 = *array1;
		merge(++array1, --len1, array2, len2, ++array3);
	}
	if ((*array1 >= *array2 || len1 == 0)  && len2 > 0) {
		*array3 = *array2;
		merge(array1, len1, ++array2, --len2, ++array3);
	}
	return retn;
}

第一题
求出数组中两个不重叠的连续子数组的最大和。

输入:

10
1 -1 2 2 3 -3 4 -4 5 -5

输出:
13
子串为:[2 2 3 -3 4]、[5]

求最大子序和的升级版,实质上就是将数组分成两个数组,分别求出最大子序和,之后再求和,求出最大值.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include <limits.h>
 
int max(int a,int b)
{
    return a>b?a:b;
}
//用两个dp数组,一个正方向,一个逆方向,并把每个下标对应的最大子序和存储在对应的maxNum数组中
int solve(int* data,int N)
{
    int dp[N];
    int Inv_dp[N];
    dp[0]=data[0];
    int maxNum[N];
    int Inv_maxNum[N];
    maxNum[0]=data[0];
    //dp[i]:以第 i 个数结尾的「连续子数组的最大和」
    //maxNum[i]:前i个数的最大子序和
    for(int i=1;i<N;i++)
    {
        dp[i]=max(dp[i-1]+data[i],data[i]);
        maxNum[i]=max(dp[i],maxNum[i-1]);
    }
    //Inv_dp[i]:逆序,倒着看,以第i个数为结尾的最大和,
    //Inv_maxNum[i]:逆序的最大子序和
    Inv_dp[N-1]=data[N-1];
    Inv_maxNum[N-1]=data[N-1];
    for(int i=N-2;i>=0;i--)
    {
        Inv_dp[i]=max(Inv_dp[i+1]+data[i],data[i]);
        Inv_maxNum[i]=max(Inv_dp[i],Inv_maxNum[i+1]);
 
    }
    int res=INT_MIN;
    //求出最大值
    for(int i=1;i<=N-1;i++)
    {
        int left=maxNum[i-1];
        int right=Inv_maxNum[i];
        res=max(res,left+right);
    }
    return res;
}
 
int main()
{
    int data[10]={-1 ,-1 ,-1 ,-1 ,-1, -1, -1, -1 ,-1 ,-1};
    //int data[5]={-5, 9 ,-5, 11 ,20};
    printf("%d\n",solve(data,10));
    return 0;
 
}

第二题
现有一个收费服务方案:在时间1<=t<6内,每单位时间收费10元;6<=t<10内,收费5元,10<=t,收2元。同一时间只能为一位服务,
有一批用户要该服务,选出若干客户服务并使收费最大。记得不是很清楚,

样例:

1 1 4, 2 2 6, 3 3 12, 4 6 10
输出:

60, 2 4
逗号之后有空格,每三个数表示,id号,起始时间和终止时间,可以求出所需要的金额。

1 1 4

id,起始时间,停止时间。

输出是最大金额,之后是被服务的用户序列

思路:

首先对数据进行处理,求出每个用户收费的时间,之后构造图,求出入度为0到出度为0的每条路径,之后求出路径收费的最大值。
 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include <ctype.h>
 
struct Node
{
    int id;
    int start;
    int end;
    int money;
};
 
int compute(int start, int end)
{
    if (start < 6)
    {
        if (end < 6)
        {
            return (end - start) * 10;
        }
        else if (end < 10)
        {
            return (6 - start) * 10 + (end - 6) * 5;
        }
        else
        {
            return (end - 10) * 2 + 20 + (6 - start) * 10;
        }
    }
    else if (start < 10)
    {
        if (end < 10)
        {
            return (end - start) * 5;
        }
        else
        {
            return (end - 10) * 2 + (10 - start) * 5;
        }
    }
    else
    {
        return (end - start) * 2;
    }
}
 
int res = 0;
//存储所有路径
int road[1000][100];
int myindex;
//用栈存储路径
int stack[100];
int top = -1;
//邻接矩阵图
int G[1000][1000];
//入度数组和出度数组
int indegree[1000];
int outdegree[1000];
int num;
struct Node user[1000];
void dfs(int start)
{
    if(outdegree[start]==0)
    {
        //路径数组中,第0个元素,为收费总和,第1个元素为栈内元素的个数
        road[myindex][1]=top+1;
        int sum=0;
        for(int i=0,j=2;i<=top;i++,j++)
        {
            sum+=user[stack[i]].money;
            road[myindex][j]=stack[i];
        }
        road[myindex][0]=sum;
        myindex++;
        return;
    }
    for(int i=1;i<num;i++)
    {
        if(G[start][i]==1)
        {
            stack[++top]=i;
            dfs(i);
            top--;
        }
    }
}
 
int main()
{
    char data[1000];
    gets(data);
     num= 1; //id从1开始
    int pos = 0;
    int len = strlen(data);
    while (pos < len)
    {
        int tmp = 0;
        while (isdigit(data[pos]))
        {
            tmp = 10 * tmp + data[pos] - '0';
            pos++;
        }
        user[num].id = tmp;
        pos++;
        tmp = 0;
        while (isdigit(data[pos]))
        {
            tmp = 10 * tmp + data[pos] - '0';
            pos++;
        }
        user[num].start = tmp;
        pos++;
        tmp = 0;
        while (isdigit(data[pos]))
        {
            tmp = 10 * tmp + data[pos] - '0';
            pos++;
        }
        user[num].end = tmp;
        pos++;
        pos++;
        user[num].money = compute(user[num].start, user[num].end);
        num++;
    }
    //一共有num-1个节点
    memset(G, 0, sizeof(G));
    memset(indegree, 0, sizeof(indegree));
    memset(outdegree, 0, sizeof(outdegree));
    for (int i = 1; i < num; i++)
    {
        for (int j = 1; j < num; j++)
        {
            if (user[j].start >= user[i].end)
            {
                G[i][j] = 1;
                indegree[j]++;
                outdegree[i]++;
            }
        }
    }
 
    myindex=0;
    for (int i = 1; i < num; i++)
    {
        if (indegree[i] == 0)
        {
            stack[++top] = i;
            dfs(i);
            top--;
        }
    }
    int max=0;
    for(int i=0;i<myindex;i++)
    {
        if(road[i][0]>max)
        {
            max=road[i][0];
            res=i;
        }
    }
    printf("%d,",road[res][0]);
    for(int i=0;i<road[res][1];i++)
    {
        printf(" %d",road[res][i+2]);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值