嵌入式软件工程师笔试题Word文档下载推荐.docx

上传人:b****6 文档编号:20344551 上传时间:2023-01-22 格式:DOCX 页数:13 大小:28.31KB
下载 相关 举报
嵌入式软件工程师笔试题Word文档下载推荐.docx_第1页
第1页 / 共13页
嵌入式软件工程师笔试题Word文档下载推荐.docx_第2页
第2页 / 共13页
嵌入式软件工程师笔试题Word文档下载推荐.docx_第3页
第3页 / 共13页
嵌入式软件工程师笔试题Word文档下载推荐.docx_第4页
第4页 / 共13页
嵌入式软件工程师笔试题Word文档下载推荐.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

嵌入式软件工程师笔试题Word文档下载推荐.docx

《嵌入式软件工程师笔试题Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《嵌入式软件工程师笔试题Word文档下载推荐.docx(13页珍藏版)》请在冰豆网上搜索。

嵌入式软件工程师笔试题Word文档下载推荐.docx

/*Filename:

 

*Cheaderfile 

*/#ifndefHELLO_H#defineHELLO_H#ifdef__cplusplusextern"

C"

{#endif 

voidprint_hello();

#ifdef__cplusplus}#endif#endif

*Csourcefile. 

*/#include"

"

#include<

voidprint_hello(){ 

puts("

Hello,world!

);

}

*C++sourcefile. 

intmain(){ 

print_hello();

return0;

建立一个新的目录,然后把这三个文件拷贝到目录中,也把Makefile文件拷贝到目录中。

之后,对Makefile的相关项目进行如下设置:

PROGRAM 

:

=hello 

#设置运行程序名SRCDIRS 

=. 

#源程序位于当前目录下SRCEXTS 

=.c.cxx 

#源程序文件有.c和.cxx两种类型CFLAGS 

:

=-g 

#为C目标程序包含GDB可用的调试信息CXXFLAGS 

#为C++目标程序包含GDB可用的调试信息

由于这个简单的程序只使用了C标准库的函数(puts),所以对于CFLAGS和CXXFLAGS没有过多的要求,LDFLAGS和CPPFLAGS选项也无需设置。

经过上面的设置之后,执行make命令就可以编译程序了。

如果没有错误出现的话,./hello就可以运行程序了。

如果修改了源程序的话,可以看到只有和修改有关的源文件被编译。

也可以再为程序添加新的源文件,只要它们的扩展名是已经在Makefile中设置过的,那么就没有必要修改 Makefile。

1.引言  本文的写作目的并不在于提供C/C++程序员求职面试指导,而旨在从技术上分析面试题的内涵。

文中的大多数面试题来自各大论坛,部分试题解答也参考了网友的意见。

  许多面试题看似简单,却需要深厚的基本功才能给出完美的解答。

企业要求面试者写一个最简单的strcpy函数都可看出面试者在技术上究竟达到了怎样的程度,我们能真正写好一个strcpy函数吗?

我们都觉得自己能,可是我们写出的strcpy很可能只能拿到10分中的2分。

读者可从本文看到strcpy函数从2分到10分解答的例子,看看自己属于什么样的层次。

此外,还有一些面试题考查面试者敏捷的思维能力。

  分析这些面试题,本身包含很强的趣味性;

而作为一名研发人员,通过对这些面试题的深入剖析则可进一步增强自身的内功。

  2.找错题  试题1:

voidtest1(){ charstring[10];

 char*str1="

09"

;

 strcpy(string,str1);

}

  试题2:

voidtest2(){ charstring[10],str1[10];

 inti;

 for(i=0;

i<

10;

i++) {  str1[i]='

a'

 } strcpy(string,str1);

  试题3:

voidtest3(char*str1){ charstring[10];

 if(strlen(str1)<

=10) {  strcpy(string,str1);

 }}

  解答:

  试题1字符串str1需要11个字节才能存放下(包括末尾的’\0’),而string只有10个字节的空间,strcpy会导致数组越界;

  对试题2,如果面试者指出字符数组str1不能在数组内结束可以给3分;

如果面试者指出strcpy(string,str1)调用使得从str1内存起复制到string内存起所复制的字节数具有不确定性可以给7分,在此基础上指出库函数strcpy工作方式的给10分;

  对试题3,if(strlen(str1)<

=10)应改为if(strlen(str1)<

10),因为strlen的结果未统计’\0’所占用的1个字节。

  剖析:

  考查对基本功的掌握:

  

(1)字符串以’\0’结尾;

  

(2)对数组越界把握的敏感度;

  (3)库函数strcpy的工作方式,如果编写一个标准strcpy函数的总分值为10,下面给出几个不同得分的答案:

  2分

voidstrcpy(char*strDest,char*strSrc){ while((*strDest++=*strSrc++)!

=‘\0’);

  4分

voidstrcpy(char*strDest,constchar*strSrc)0’

0’

.

功题  试题1:

分别给出BOOL,int,float,指针变量与“零值”比较的if语句(假设变量名为var)  解答:

   BOOL型变量:

if(!

var)   int型变量:

if(var==0)   float型变量:

   constfloatEPSINON=;

   if((x>

=-EPSINON)&

(x<

=EPSINON)   指针变量:

  if(var==NULL)  剖析:

  考查对0值判断的“内功”,BOOL型变量的0判断完全可以写成if(var==0),而int型变量也可以写成if(!

var),指针变量的判断也可以写成if(!

var),上述写法虽然程序都能正确运行,但是未能清晰地表达程序的意思。

  一般的,如果想让if判断一个变量的“真”、“假”,应直接使用if(var)、if(!

var),表明其为“逻辑”判断;

如果用if判断一个数值型变量(short、int、long等),应该用if(var==0),表明是与0进行“数值”上的比较;

而判断指针则适宜用if(var==NULL),这是一种很好的编程习惯。

  浮点型变量并不精确,所以不可将float变量用“==”或“!

=”与数字比较,应该设法转化成“>

=”或“<

=”形式。

如果写成if(x==,则判为错,得0分。

以下为WindowsNT下的32位C++程序,请计算sizeof的值

voidFunc(charstr[100]){ sizeof(str)=?

}void*p=malloc(100);

sizeof(p)=?

sizeof(str)=4sizeof(p)=4

  Func(charstr[100])函数中数组名作为函数形参时,在函数体内,数组名失去了本身的内涵,仅仅只是一个指针;

在失去其内涵的同时,它还失去了其常量特性,可以作自增、自减等操作,可以被修改。

  数组名的本质如下:

  

(1)数组名指代一种数据结构,这种数据结构就是数组;

  例如:

charstr[10];

cout<

<

sizeof(str)<

endl;

  输出结果为10,str指代数据结构char[10]。

  

(2)数组名可以转换为指向其指代实体的指针,而且是一个指针常量,不能作自增、自减等操作,不能被修改;

str++;

.*/#ifdef__cplusplus}#endif#endif/*__INCvxWorksh*/

  头文件中的编译宏

#ifndef __INCvxWorksh#define __INCvxWorksh#endif

  的作用是防止被重复引用。

  作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。

函数被C++编译后在symbol库中的名字与C语言的不同。

例如,假设某个函数的原型为:

voidfoo(intx,inty);

  该函数被C编译器编译后在symbol库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。

_foo_int_int这样的名字包含了函数名和函数参数数量及类型信息,C++就是考这种机制来实现函数重载的。

  为了实现C和C++的混合编程,C++提供了C连接交换指定符号extern"

来解决名字匹配问题,函数声明前加上extern"

后,则编译器就会按照C语言的方式将该函数编译为_foo,这样C语言中就可以调用C++的函数了。

试题5:

编写一个函数,作用是把一个char组成的字符串循环右移n个。

比如原来是“abcdefghi”如果n=2,移位后应该是“hiabcdefgh”  函数头是这样的:

.}

  正确解答1:

voidLoopMove(char*pStr,intsteps){ intn=strlen(pStr)-steps;

 chartmp[MAX_LEN];

巧题  试题1:

请写一个C函数,若处理器是Big_endian的,则返回0;

若是Little_endian的,则返回  解答:

intcheckCPU(){ {  unionw  {   inta;

   charb;

  }c;

  =1;

0X00000001四个字节,为一个字节  return==1);

大端的为00,小端的为01?

 }

1l

1l

  void的出现只是为了一种抽象的需要,如果你正确地理解了面向对象中“抽象基类”的概念,也很容易理解void数据类型。

正如不能给抽象基类定义一个实例,我们也不能定义一个void(让我们类比的称void为“抽象数据类型”)变量。

关于CONST的用法

const在C语言中算是一个比较新的描述符,我们称之为常量修饰符,意即其所修饰的对象为常量(immutable)。

我们来分情况看语法上它该如何被使用。

1、函数体内修饰局部变量。

例:

voidfunc(){constinta=0;

}首先,我们先把const这个单词忽略不看,那么a是一个int类型的局部自动变量,我们给它赋予初始值0。

然后再看const.const作为一个类型限定词,和int有相同的地位。

constinta;

intconsta;

是等价的。

于是此处我们一定要清晰的明白,const修饰的对象是谁,是a,和int没有关系。

const要求他所修饰的对象为常量,不可被改变,不可被赋值,不可作为左值(l-value)。

这样的写法也是错误的。

a=0;

这是一个很常见的使用方式:

constdoublepi=;

在程序的后面如果企图对pi再次赋值或者修改就会出错。

然后看一个稍微复杂的例子。

constint*p;

还是先去掉const修饰符号。

注意,下面两个是等价的。

int*p;

int*p;

其实我们想要说的是,*p是int类型。

那么显然,p就是指向int的指针。

同理constint*p;

其实等价于constint(*p);

intconst(*p);

即,*p是常量。

也就是说,p指向的数据是常量。

于是p+=8;

代表什么。

如果去掉const,我们可以看出char*argv[];

argv是一个数组,它的每个元素都是char*类型的指针。

如果加上const.那么const修饰的是谁呢?

他修饰的是一个数组,argv[],意思就是说这个数组的元素是只读的。

那么数组的元素的是什么类型呢?

是char*类型的指针.也就是说指针是常量,而它指向的数据不是。

于是argv[1]=NULL;

用extern例如/**/externconstdoublepi;

/**/constdoublepi=;

然后其他需要使用pi这个变量的,包含#include"

或者,自己把那句声明复制一遍就好。

这样做的结果是,整个程序链接完后,所有需要使用pi这个变量的共享一个存储区域。

2.使用static,静态外部存储类/**/staticconstpi=;

需要使用这个变量的*.c文件中,必须包含这个头文件。

前面的static一定不能少。

否则链接的时候会报告说该变量被多次定义。

这样做的结果是,每个包含了的*.c文件,都有一份该变量自己的copy,该变量实际上还是被定义了多次,占用了多个存储空间,不过在加了static关键字后,解决了文件间重定义的冲突。

坏处是浪费了存储空间,导致链接完后的可执行文件变大。

但是通常,这个,小小几字节的变化,不是问题。

好处是,你不用关心这个变量是在哪个文件中被初始化的。

最后,说说const的作用。

const的好处,是引入了常量的概念,让我们不要去修改不该修改的内存。

直接的作用就是让更多的逻辑错误在编译期被发现。

所以我们要尽可能的多使用const。

但是很多人并不习惯使用它,更有甚者,是在整个程序编写/调试完后才补const。

如果是给函数的声明补const,尚好。

如果是给全局/局部变量补const,那么……那么,为时已晚,无非是让代码看起来更漂亮了。

c语言中的结构(struct)和联合(union)简介

联 

合(union) 

1.联合说明和联合变量定义 

联合也是一种新的数据类型,它是一种特殊形式的变量。

联合说明和联合变量定义与结构十分相似。

其形式为:

union联合名{ 

数据类型成员名;

... 

}联合变量名;

联合表示几个变量公用一个内存位置,在不同的时间保存不同的数据类型和不同长度的变量。

下例表示说明一个联合a_bc:

uniona_bc{ 

inti;

charmm;

};

再用已说明的联合可定义联合变量。

例如用上面说明的联合定义一个名为lgc的联合变量,可写成:

uniona_bclgc;

在联合变量lgc中,整型量i和字符mm公用同一内存位置。

当一个联合被说明时,编译程序自动地产生一个变量,其长度为联合中最大的变量长度。

联合访问其成员的方法与结构相同。

同样联合变量也可以定义成数组或指针,但定义为指针时,也要用"

->

符号,此时联合访问成员可表示成:

联合名->

成员名 

另外,联合既可以出现在结构内,它的成员也可以是结构。

例如:

struct{ 

intage;

char*addr;

union{ 

char*ch;

}x;

}y[10];

若要访问结构变量y[1]中联合x的成员i,可以写成:

y[1].;

若要访问结构变量y[2]中联合x的字符串指针ch的第一个字符可写成:

*y[2].;

若写成"

y[2].x.*ch;

是错误的。

2.结构和联合的区别 

结构和联合有下列区别:

1.结构和联合都是由多个不同的数据类型成员组成,但在任何同一时刻,联合转只存放了一个被选中的成员,而结构的所有成员都存在。

2.对于联合的不同成员赋值,将会对其它成员重写,原来成员的值就不存在了,而对于结构的不同成员赋值是互不影响的。

下面举一个例了来加对深联合的理解。

例4:

main(){ 

union{ 

/*定义一个联合*/ 

struct{ 

/*在联合中定义一个结构*/ 

charfirst;

charsecond;

}half;

}number;

=0x4241;

/*联合成员赋值*/ 

printf("

%c%c\n"

 

'

/*联合中结构成员赋值*/ 

b'

%x\n"

;

getch();

输出结果为:

AB 

6261 

从上例结果可以看出:

当给i赋值后,其低八位也就是first和second的值;

当给first和second赋字符后,这两个字符的ASCII码也将作为i的低八位和高八位。

Volatile关键字告诉编译器不要持有变量的临时性拷贝。

一般用在多线程程序中,以避免在其中一个线程操作该变量时,将其拷贝入寄存器。

请看以下情形:

A线程将变量复制入寄存器,然后进入循环,反复检测寄存器的值是否满足一定条件(它期待B线程改变变量的值。

在此种情况下,当B线程改变了变量的值时,已改变的值对其在寄存器的值没有影响。

所以A线程进入死循环。

volatile就是在此种情况下使用。

一、预备知识—程序的内存分配 

一个由c/C++编译的程序占用的内存分为以下几个部分 

1、栈区(stack)—由编译器自动分配释放,存放函数的参数值,局部变量的值等。

其操作方式类似于数据结构中的栈。

2、堆区(heap)—一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。

注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。

3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。

-程序结束后有系统释放 

4、文字常量区—常量字符串就是放在这里的。

程序结束后由系统释放 

5、程序代码区—存放函数体的二进制代码。

例子程序这是一个前辈写的,非常详细另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。

但是速度快,也最灵活。

堆和栈中的存储内容栈:

在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。

注意静态变量是不入栈的。

当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。

堆:

一般是在堆的头部用一个字节存放堆的大小。

堆中的具体内容有程序员安排。

存取效率的比较chars1[]="

aaaaaaaaaaaaaaa"

char*s2="

bbbbbbbbbbbbbbbbb"

aaaaaaaaaaa是在运行时刻赋值的;

而bbbbbbbbbbb是在编译时就确定的;

但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。

比如:

#includevoidmain(){chara=1;

charc[]="

90"

char*p="

a=c[1];

a=p[1];

return;

}对应的汇编代码10:

a=c[1];

004010678A4DF1movcl,byteptr[ebp-0Fh]0040106A884DFCmovbyteptr[ebp-4],cl11:

a=p[1];

0040106D8B55ECmovedx,dwordptr[ebp-14h]004010708A4201moval,byteptr[edx+1]004010738845FCmovbyteptr[ebp-4],al第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指针值读到edx中,在根据edx读取字符,显然慢了。

小结堆和栈的区别可以用如下的比喻来看出:

使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。

使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。

windows进程中的内存结构在阅读本文之前,如果你连是什么多不知道的话,请先阅读文章后面的。

接触过的人都知道,高级语言都能通过变量名来访问内存中的数据。

那么这些变量在内存中是如何存放的呢?

程序又是如何使用这些变量的呢?

下面就会对此进行深入的讨论。

下文中的C语言代码如没有特别声明,默认都使用VC编译的release版。

首先,来了解一下C语言的变量是如何在内存分部的。

C语言有全局变量(Global)、本地变量(Local),静态变量(Static)、寄存器变量(Regeister)。

每种变量都有不同的分配方式。

先来看下面这段代码:

intg1=0,g2=0,g3=0;

intmain(){staticints1=0,s2=0,s3=0;

intv1=0,v2=0,v3=0;

7c7c6c3”2”1”0C0000000C4C0040100F894C83C43C0000003C00401078C000C6A6A6A0000000C004068c

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 表格模板 > 合同协议

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1