华为——嵌入式软件工程师面试题汇总(整理了一下网上资料)

1. 基本概念、简答等

(1)什么是预编译,何时需要预编译?

1. 总是使用而不经常改动的大型代码体。(例如#define宏定义的代码,在预处理阶段就会进行代码替换,而不是在编译阶段按照语法语义生成代码。)

2. 程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。在这种情况下,可以将所有包含文件编译为一个预编译头。(这里的理解是)

预编译指令指示了在程序正式编译前就由编译器进行的操作,可以放在程序中的任何位置。

其中Visual Studio新建的C++项目就自动为项目添加了预编译头文件,名称为“pch.h”,用户可以将一些不经常被改变的代码,还是如#define宏定义,inline内联函数等,或者将一些系统必须包含的头文件等,添加到“pch.h”文件中。

(2)char * const p; char const * p; const char *p 上述三个有什么区别?

主要是看const后面的变量,例如:

char * const p, 由于const在p前面,因此这个说明p是一个常量指针,不能修改。

char const * p,const在*p的前面,因此说明*p是一个常量,即p是一个指向常量的指针,其指向的常量不可修改。

const char *p, 与char const * p相同,const在char *p前面,但是由于char表示变量类型,对const的作用对象无影响,因此实际还是表示*p是一个const类型,即指针所指的变量是常量,不可改变。

(3)字符数组和字符串常量

    char str1[] = "abc"; 
    char str2[] = "abc"; 
    const char str3[] = "abc"; 
    const char str4[] = "abc"; 
    const char *str5 = "abc"; 
    const char *str6= "abc"; 
    char *str7 = "abc"; //应该加上const限定符
    char *str8 = "abc"; //应该加上const限定符
    cout << ( str1 == str2 ) << endl; 
    cout << ( str3 == str4 ) << endl; 
    cout << ( str5 == str6 ) << endl; 
    cout << ( str7 == str8 ) << endl;

注意一点,“abc”是一个字符串常量,用其初始化字符数组,str1~str4都是字符数组变量,其每一个都对应不同变量在内存的存储空间,所以当然是互不相等的。而str5~str8,它们是指针,指向同一个常量区域,因此他们互相都是相等的。可以看看添加下面的代码进行验证。

    printf("str1: %lu\n",str1);
    printf("str2: %lu\n",str2);
    printf("str3: %lu\n",str3);
    printf("str4: %lu\n",str4);
    printf("str5: %lu\n",str5);
    printf("str6: %lu\n",str6);
    printf("str7: %lu\n",str7);
    printf("str8: %lu\n",str8);

得到的结果如下:

    str1: 2686748
    str2: 2686744
    str3: 2686740
    str4: 2686736
    str5: 4214885
    str6: 4214885
    str7: 4214885
    str8: 4214885

另外这道题需要注意的是,“abc”是字符串常量,其指针必须是一个const类型的char*,即表示字符串常量中的内容不允许修改。而实际str6和str7用char*类型的字符指针去指向字符串常量,会报错,应该在前面加上const限定符。

(4)以下代码中sizeof的用法有问题吗?

void UpperCase( char str[] ) // 将str中的小写字母转换成大写字母
{    for( size_t i=0; i 

上面代码UpperCase函数中sizeof实际上是检测了一个char型的指针,当然是返回指针的大小(也就是4),在main函数中可以得到正确的sizeof长度,是整个数组的大小,但是要注意字符串常量在末尾隐含了一个‘\0’,因此sizeof结果是6。最后输出应该是先打印一个6,然后打印“ABCDe”,即只更新了前四个字母。

其实编译器在这里可能会给出警告:

warning: 'sizeof' on array function parameter 'str' will return size of
'char*' [-Wsizeof-array-argument]
     printf("%d\n",sizeof(str));
                             ^

(5)一个32位的机器,该机器的指针是多少位?

指针是多少位只要看地址总线的位数就行了。80386以后的机子都是32的数据总线。所以指针的位数就是4个字节了。

(6)下面程序的输出

int main(void)
{ 
    int a[5]={1,2,3,4,5};   
    int *ptr=(int*)(&a+1);   
    printf("%d,%d",*(a+1),*(ptr-1));
    return 0;
}

输出:2, 5。

*(a+1)不再赘述,(&a+1)中&a是数组指针,因为a是一个指向5个int的数组的指针,其本质为int (*)[5],然后再其基础上+1,自然是偏移一个数组大小(即偏移5个int大小)得到ptr指针。ptr指针减一之后实际就到了a[4]所在的元素,printf得到的是a[4]=5.

从下面的ptr的地址0x28ff3c和a[0]的地址0x28ff28就可以看出,二者相差了20个字节,就是5个int的大小。

华为——嵌入式软件工程师面试题汇总(整理了一下网上资料)_第1张图片

(7)下面代码有什么问题?

int  main() { 
    char a; 
    char *str=&a; 
    strcpy(str,"hello"); 
    printf(str); return 0; 
}

a定义为char类型的数据,为将“hello”拷贝到a的内存,肯定会在读写时发生内存越界问题。可以改成下面的形式:

int  main() { 
    char a[10]; 
    char *str=a; 
    strcpy(str,"hello"); 
    printf(str);
    
    return 0;
}

(8)char* s="AAA"; printf("%s",s); s[0]='B'; printf("%s",s);有什么错?

这个在上面讲到了,"AAA"是字符串常量,应该用const指针来指向它;同时const指针所指区域不允许更改,所以对s[0]的赋值操作也不正确。

(9)写一个标准宏,这个宏输入两个参数然后返回较小的一个

#define Min(X, Y) ((X)>(Y)?(Y):(X))  //结尾没有‘;’并且记得加括号

应当注意,这个宏在有些时候无法给出正确的答案,比如下面的代码:

int a=2,b=3;
int* p=&a;
int least=MIN((*p)++,b);//least=3,a=4,b=3

这个函数的本意应该是判断(*p)++的值与b的值的大小,将较小的那个数赋值给least,但是这里需要注意,(*p)先进行自增以后参与三目运算符的比较判断部分,然后三目运算符?:返回的也是(*p)++,这里*p又自增了一次,虽然least能够得到最初的(*p)++与b较小的那个值,但是*p在这个操作过程中自增了两次,这可能不是我们需要的。

(10)嵌入式系统中经常要用到无限循环,你怎么用C编写死循环?

while(1){}或者for(;;)

(11)关键字static的作用是什么?

定义静态变量

(12)关键字const有什么含意?

表示常量,不可被修改的变量。

(13)关键字volatile有什么含意?并举出三个不同的例子?

提示编译器对象的值可能在编译器未监测到的情况下改变。

三个例子:

  1. 中断服务程序中修改的供其他程序检测的变量要加volatile;
  2. 多任务环境下各任务间共享的标志应该加volatile;
  3. 存储器映射的硬件寄存器通常也要加voliate,因为每次对它的读写都可能有不同意义。

(具体可以参考:C语言中volatile关键字的作用)

(14)int (*s[10])(int) 表示的是什么?

先看一个简单的:int (*p)(int)表示什么?答:一个指向函数的指针,该函数接收一个int型的参数;

那么,int (*s[10])(int)是不是就是表示一个数组,这个数组里面每个元素都是一个指向函数的指针,该函数接收一个int型的参数,并且返回值也是int。

(15)有以下表达式,请问下列表达式哪些会被编译器禁止?为什么?(原文这个地方比较乱,我按照自己的理解整理了一下)

     int a=248, b=4;
     int const c=21;
     const int *d=&a; 
     int *conste=&b;
     int const *f=&a;

以下是要进行的操作,该操作能否进行见注释:

c=32;//被禁止,编译器提示“表达式必须是可以被修改的左值”,其实就是说c是常量,不能修改
d=&b;//可以执行,*d是const表示d所指向的内存空间不可以被修改,但是d本身可以被修改
*d=43;//被禁止,参考上一条注释
e=34;//这里有两个问题,首先e是const,不能修改,另外e是int*类型,不能赋int类型的值
e=&a;//e是const,不能修改
*e=12;//这个是可以的,因为e是const,但是e指向的变量可以被修改
f=&b;//这个是可以的,*f是const,表示f指向的变量不能被修改,但是f本身可以被修改

(16)交换两个变量的值,不使用第三个变量。即a=3,b=5,交换之后a=5,b=3

这个由两种解法:

  1. 算术算法。这个方法即使a+b大于a类型允许的最大值,即发生溢出,也仍然可以得到正确的答案(可以参考证明);
  2. 位运算,亦或方法。异或只能对整型进行操作,所及交换的两个数必须是整型。
//需要注意两个传参不能是指向同一片内存区域的指针
//位运算
void exchange(int* a, int* b){
    if(*a==*b)return;
    *a^=*b;
    *b^=*a;
    *a^=*b;
}
//算术算法
void exchange(int* a, int* b){
    if(*a==*b)return;
    *a=*a+*b;
    *b=*a-*b;
    *a=*a-*b;
}

(17)c和c++中的struct有什么不同?

C中的结构不能含有成员函数,C++中的结构可以含有成员函数,C++中结构跟类的主要区别在于默认的存储权限不同,结构默认是public,类默认是private。

(18)下面函数

#include  
#include  

void getmemory(char *p) 
{   
    p=(char *)malloc(100);//在程序中给p(副本)赋值,并不影响实际的str
    strcpy(p,"helloworld"); 
} 

int main( ) 
{   
    char*str=NULL;   
    getmemory(str); //传入参数之后,函数实际执行的是一个副本
    printf("%s/n",str);   
    free(str);  

    return 0;  
}

程序运行会崩溃,因为str并没有得到malloc出来的内存,对其调用free会出错。这里其实可以将指针换成int,如果传入一个int类型的变量,在getmemory中改变变量的值,实际并不会对函数外面的变量产生影响。对于int类型参数,应该传其指针,而对于指向int的指针,应该传其指针,也就是指针的指针,即**p。函数可以改成下面的形式:

void getmemory(char **p) 
{   
    *p=(char *)malloc(100);
    strcpy(*p,"helloworld"); 
} 

int main( ) 
{   
    char*str=NULL;   
    getmemory(&str); //传入指针的指针
    printf("%s\n",str);   
    free(str);  

    return 0;  
}

(19)charszstr[10];  strcpy(szstr,"0123456789");  产生什么结果?为什么?

产生错误,但是不会显式表现出来,因为“0123456789”还包含一个隐含的'\0',实际应该有11个字符。

(20)列举几种进程的同步机制,并比较其优缺点

几种进程同步机制:原子操作,互斥锁,信号量,自旋锁,管程,会合,分布式系统。

原子操作:原子对象是一个可通过原子操作被读取或修改的对象,原子操作是指不能被并行线程中断的操作。

自旋锁:自旋锁不会引起调用者睡眠(或者叫阻塞),如果自旋锁已经被别的执行单元保持,调用者就一直循环在这里看自旋锁的保持着是否已经释放了锁。其效率比互斥锁高。

互斥锁:同一时间只能有一个任务持有互斥锁,如果互斥锁已经被别的执行单元保持,调用者就会睡眠(或者叫阻塞),等到执行单元执行完成并且释放互斥锁,另一个阻塞的单元才能进入临界区,访问共享资源。效率比自旋锁低。

信号量机制:信号量可以用于进程或者线程之间,信号量可以并行,运行多个线程同时访问共享资源。除此之外,信号量可以用来实现多任务同步,是流程上的概念,互斥锁将多任务同步变成串行执行。

(21)进程之间通信的途径

  1. 管道(Pipe):半双工(数据只能单向流动);只能用于具有亲缘关系的进程之间的通信(父子进程或者兄弟进程)。特点:速度慢,容量有限,只能父子进程之间通信。
  2. 命名管道(Named Pipe):任何进程间都能同信(不同于无名管道),但是速度慢。
  3. 消息队列(Message Queue):是消息的链表,存放在内核中,一个消息队列由一个标识符(即队列ID)来标识。消息队列克服了信号传递信息少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。
  4. 信号量(Semophore):是一个计数器,用来控制多个进程对共享资源的访问,不能传递复杂消息,只能用来同步。
  5. 共享内存(Shared Memory):两个或多个进程共享一个给定的存储区,很容易控制容量,速度快,但要保持同步,一般配合信号量共同使用,用来存放同步对共享内存的访问。
  6. 套接字(Socket):进程间通信机制,可用于不同主机之间的进程通信。

以上参考:进程间的五种通信方式介绍,几种进程间的通信方式。

(22)进程死锁的原因

  1. 资源竞争。当系统中供多个进程共享的资源如打印机、公用队列等,其数目不足以满足进程的需要时,会引起诸进程的竞争而产生死锁。
  2. 进程间推进顺序非法。进程在运行过程中,请求和释放资源的顺序不当。(参考:进程死锁)

(23)死锁的4个必要条件

  1. 互斥:进程要求对所分配的资源进行排他性控制,即在一段时间内某资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待;
  2. 不可剥夺:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能由该资源的进程自己来释放(只能是主动释放);
  3. 请求与保持:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放;
  4. 循环等待:存在一个进程链,使得每一个进程都占有下一个进程所需的至少一种资源。

(24)死锁的处理

  1. 鸵鸟策略:前提:死锁出现的概率很低,或者系统发生死锁不会对用户造成很大影响。可以使用鸵鸟策略是因为解决死锁问题,代价通常比较大,因此在上述前提下,采用鸵鸟策略处理死锁(忽略死锁);
  2. 预防策略:破坏除了“互斥”之外的其他三个条件。
  3. 避免策略:在使用前进行判断,只允许不会产生死锁的进程申请资源。
  4. 死锁检测与解除:在检测到运行系统进入死锁,进行恢复。

参考:死锁的四个必要条件和解决办法,死锁,死锁的四个必要条件以及处理策略。

(25)操作系统中进程调度策略有哪几种?

  1. 先来先服务(FCFS):最简单的调度算法,每次调度从进程队列中选择一个最先进入该队列的进程,为之分配资源投入运行。该进程一直运行完成或发生某件事件而阻塞后才继续处理后面的进程。
  2. 优先级调度算法:有短进程优先级、高优先权优先级、高响应比优先级等,按照优先级来执行就绪进程队列中的调度。  (高响应比:(等待时间+服务运行时间)/服务运行时间)。
  3. 时间片轮转调度算法:系统还是按照先来先服务调度就绪进程,但每次调度时,CPU都会为队首进程分配并执行一个时间片(几ms~百ms)。执行时间片用完后计时器即产生时钟中断,停止该进程并将它送到队尾,其他依次执行。这样保证系统能在给定的时间内执行所有用户进程的请求。
  4. 多级反馈调度算法:前面都有局限性,综合-> 多级反馈调度算法则不必事先知道各进程所需的执行时间,而且还可以满足各类型进程的需要,因而它是目前被公认的一种较好的进程调度算法。(1)设置多个就绪队列,每个队列优先级依次减小。为各个队列分配的时间片大小不同,优先级队列越高,里面进程规定的执行时间片就越小。(2)队列中还是按照FCFS原则排队等待,如果第一队列队首进程在规定的时间片内未执行完,则直接调送至第二队尾,依次向后放一个队列的队尾。因此一个长作业进程会分配到n个队列的时间片执行。(3)按照队列先后依次执行,如果新进的待处理进程优先级较高,则新进程将抢占正在运行的进程,被抢占的进程放置正在运行的队尾。

以上参考:操作系统中进程调度策略有哪几种?

(26)类的静态成员和非静态成员有何区别?

  1. 类的静态成员每个类只有一个,非静态成员每个对象一个。
  2. 静态成员在类外进行初始化,初始化格式:数据类型 类名::静态成员变量名=初值。
  3. 只要在类中声明静态成员变量,即使不定义对象,也可以为静态成员变量分配空间,进而可以使用静态成员变量。
  4. 静态成员变量存储到方法区的静态区中,而非静态成员变量存储到堆内存的对象中。
  5. 成员变量随着对象的产生和消失而消失,静态成员随着类的产生和消失而产生和消失。

(27)纯虚函数如何定义?使用时应注意什么?

virtual void f() =0;

纯虚函数只提供接口,子类必须提供其实现。

(28)数组和链表的区别

数组:顺序存储数据,大小固定,可通过下标访问数据;

链表:数据可以随机存储,大小可以动态改变。

(29)ISO七层模型叫什么?TCP/IP属于哪一层?TCP/UDP有何缺点?

ISO七层模型:物理层,数据链路层,网络层,传输层,会话层,表示层,应用层。

TCP/IP属于传输层。

TCP提供了数据流传输、可靠性、有效流控制、全双工操作和多路复用技术等。与TCP不同,UDP不提供对IP协议的可靠机制、流控制以及错误回复功能等。由于UDP比较简单,UDP头包含很少的字节,比TCP负载消耗小。TCP提供稳定的传输服务,有流量控制,缺点是包头大,冗余性不好。UDP:不提供稳定服务,包头小,开销少。

(30)(void *)ptr 和 (*(void**))ptr的结果是否相同?其中ptr为同一个指针

(void*)ptr 和(*(void**))ptr值是相同的

(31)int main()    {    int x=3;    printf("%d",x);    return1;      } 问函数既然不会被其它函数调用,为什么要返回1?

main中,C标准认为return 0表示成功,非0即表示错误,具体的值时其中具体出错信息。

(32)要对绝对地址0x100000赋值,我们可以用 (unsigned int*)0x100000 =1234; 那么要是想让程序跳转到绝对地址是0x100000去执行,应该怎么做?

*((void(*)( ))0x100000 ) ( ); 首先要将0x100000强制转换成函数指针,即: (void(*)())0x100000 然后再调用它:*((void (*)())0x100000)(); 用typedef可以看得更直观些: typedef void(*)() voidFuncPtr; *((voidFuncPtr)0x100000)();

(33)已知一个数组table,用一个宏定义,求出数据的元素个数

#define NTBL (sizeof(table)/sizeof(table[0]))

(34)线程与进程的区别和联系? 线程是否具有相同的堆栈? dll是否有独立的堆栈?

进程是死的,只是一些资源的集合,真正的程序执行都是线程来完成的,程序启动的时候操作系统就帮你创建了一个主线程。每个线程有自己的堆栈。 DLL中有没有独立的堆栈,这个问题不好回答,或者说这个问题本身是否有问题。因为DLL中的代码是被某些线程所执行,只有线程拥有堆栈,如果DLL中的代码是EXE中的线程所调用,那么这个时候是不是说这个DLL没有自己独立的堆栈?如果DLL中的代码是由DLL自己创建的线程所执行,那么是不是说DLL有独立的堆栈?以上讲的是堆栈,如果对于堆来说,每个DLL有自己的堆,所以如果是从DLL中动态分配的内存,最好是从DLL中删除,如果你从DLL中分配内存,然后在EXE中,或者另外一个DLL中删除,很有可能导致程序崩溃。

(35)下面代码输出是什么?分析过程

过程分析见代码注释。

int main(void){
  unsigned short A = 10; 
  printf("~A = %u\n", ~A); //~A=-11,但是输出格式是unsigned,因此输出4294967285
  char c=128; //c=0x80,二进制为1000 0000,输出int,为-128
  printf("c=%d\n",c); 
  return 0;
}

(36)-1,2,7,28,,126请问28和126中间那个数是什么?为什么?

第一题的答案应该是4^3-1=63规律是n^3-1(当n为偶数0,2,4)     n^3+1(当n为奇数1,3,5)。

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

设2个栈为A、B,一开始均为空。入队: 将新元素push入栈A;出队:(1)判断栈A是否为空;(2)如果为空,执行第三步;如果不为空,则将栈A中所有元素依次pop出并push到栈B; (3)将栈B的栈顶元素pop出。

(37)在c语言库函数中将一个字符转换成整型的函数是atol()吗,这个函数的原型是什么?

函数名:atol;

功能:将字符串转换成长整型数;

用法:long atol(const char *nptr);

示例:

#include 
#include 
int main(void)
{
    long l;
    char *str = "98765432";
    l = atol(str); //l=98765432
    printf("string = %s integer = %ld\n", str, l);
    return(0);
}

输出:

string = 98765432 integer = 98765432

(38)对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现?

C用宏定义(#define),C++用内联函数(inline)。

(39)直接链接两个信令点的一组链路称作什么?

PPP点到点连接。

(40)软件测试都有哪些种类?

黑盒测试:针对系统功能的测试。把测试对象看做一个黑盒子,测试人员完全不考虑程序内部的逻辑结构和内部特性,只依据程序的需求规格说明书,检查程序的功能是否符合它的功能说明。

白盒测试:测试函数功能,各函数接口。是把测试对象看做一个打开的盒子,它允许测试人员利用程序内部的逻辑结构及有关信息,设计或选择测试用例,对程序所有逻辑路径进行测试。通过在不同点检查程序状态,确定实际状态是否与预期的状态一致。

其实软件测试按照不同的分类方式,有很多不同的方法,可以参考:软件测试分类。

(41)确定模块的功能和模块的接口是在软件设计的那个队段完成的?

概要设计阶段。

(42)enum string    {   x1,    x2,    x3=10,   x4,    x5,    }x;    问x?

x是一个枚举变量,注意这里的string是枚举类型,枚举类型是整型,如果没有显式声明类型,默认就是int,并且第一个元素默认是0,因此x1=0,x2=1,x4=11,x5=12;x是枚举里面元素的任意一个,这里定义枚举变量,但是没有赋值,因此x值不固定。

(43)有下面代码,请问:p1+5=?;p2+20=?

    unsigned char *p1;    
    unsigned long*p2;    
    p1=(unsigned char *)0x801000;   
    p2=(unsigned long *)0x810000;  

答案:

//p1+5=0x801005;
//p2+20=0x810014;注意将十进制的20转为16进制,就是0x14

(44)TCP/IP通信建立的过程怎么样,端口有什么用?

TCP/IP通信建立:三次握手,可以参考:TCP/IP--理解TCP三次握手和四次挥手。

端口的作用:确定是哪个应用程序使用该协议。

(45)局部变量能否和全局变量重名?

可以。但是局部变量会屏蔽全局变量。C++中可以使用“::”域解析符来访问全局变量。

(46)如何引用一个已经定义过的全局变量?

可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变量,假定你将那个变量写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。

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

这道题网上答案版本很多。我的理解是,要先搞清楚变量的定义和声明,变量定义只能出现一次,如果是将定义包含在一个被多个.C文件包含的头文件中,会导致重复定义;如果是将声明包含在一个被多个.C文件包含的头文件中,那是可以的,在其他C文件中可以定义,但同时注意,只能在一个特定的c文件中定义。

可以参考:全局变量可不可以定义在可被多个.c文件包含的头文件中,以及这个讨论。

(48)语句for( ;1 ;)有什么问题?它是什么意思?

和while(1)相同,死循环。

(49)do……while和while……do有什么区别?

前一个循环一遍再判断,后一个判断以后再循环。

(50)请写出下列代码的输出内容

输出内容见注释。

#include 
#include 
int main(void){
    int a,b,c,d; a=10; 
    b=a++; //b=10,a=11
    c=++a;//c=12,a=12
    d=10*a++; //d=120,a=13
    printf("b,c,d:%d,%d,%d",b,c,d);//b=10,c=12,d=120
    return 0; 
}

(51)static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?

参考《C Primer Plus 第六版》中的概念:作用域,链接,以及存储期。其中“链接”的概念可能比较陌生,可以参考书上的解释。

全局变量的说明之前加上static就构成了静态的全局变量,全局变量和静态全局变量的作用域相同,都是文件作用域,但是静态全局变量是内部链接(只能在一个翻译单元中使用),全局变量是外部链接(可以在多文件程序中使用)。静态局部变量是改变了局部变量的存储期,将原本局部变量的自动存储器变成了静态局部变量的静态存储器,相较于局部变量,静态局部变量的作用域和链接都没有改变,只是改变了存储期。

(52)程序的局部变量存在于()中,全局变量存在于()中,动态申请数据存在于()中。

局部变量:存储在栈中,由编译器自动分配和释放。

全局变量:存储在静态区,程序结束后由系统释放。

动态申请数据:存储在堆中,如malloc分配的内存空间,需要由程序要自己释放,或者程序结束时释放。如果程序员没有在程序运行期间释放,可能造成内存泄漏。

(53)设有以下说明和定义,则语句printf("%d",sizeof(too)+sizeof(max));的执行结果是?

typedef union {//大小:20字节
    long i; 
    int k[5]; //20字节
    char c;
} DATE; 
struct data { //大小32字节
    int cat; //4字节
    DATE cow; //20字节
    double dog;//8字节
}too; 
DATE max; 

结果是52(32+20),详见上面代码中注释。

(54)队列和栈有什么区别?

队列先进先出,栈后进先出。

(55)已知一个单向链表的头,请写出删除其某一个结点的算法,要求,先找到此结点,然后删除。

如下:

typedef struct node{
    int number;
    struct node* next;
}Node;

Node*Delete(Node *Head,int key){
    Node* newHead=(Node*)malloc(sizeof(Node*));
    Node* Pointer;
    newHead->next=Head;
    while(newHead->next){
        if(newHead->next->number==key){
            Pointer=newHead->next;
            newHead->next=newHead->next->next; 
            free(Pointer);
            break;
        }else{
            newHead=newHead->next;
        }
    }
    return newHead->next;
}

2. 选择、填空、判断

2.1 判断

(1)有数组定义int a[2][2]={{1},{2,3}};则a[0][1]的值为0。

正确。数组部分初始化之后,没有初始化的元素默认赋值为0;但是如果数组只是定义了,没有部分初始化,则所有元素都是垃圾数据。

(2)int (*ptr) (),则ptr是一维数组的名字。

错误。前面已经介绍过,int (*ptr) ();定义了一个指向函数的指针变量,其指向的函数的返回值为int。

(3)指针在任何情况下都可进行>, <,>=, <=,==运算。

这个题其实吧,如果只是将指针作为整型进行比较,是可以的(不同类型的指针之间需要强制类型转换,统一指针类型),但是没有任何意义。

(4)switch(c) 语句中c可以是int,long,char ,float ,unsigned int 类型。

错,switch只能是整型,float不行。

2.2 选择和填空(统一改成填空)

(1)在OSI 7 层模型中,网络层的功能有( )

答案:确定数据包从源到目的如何选择路由。

物理层:在信道上传输原始的比特流;

数据链路层:加强物理层数据传输原始比特流的功能并进行流量控制;

网络层:确定数据包从源到目的如何选择路由;

传输层:确保到达对方的各段信息正确无误。

(2)FDDI 使用的是___局域网技术。

答案:令牌环。

(3)下面那种LAN 是应用CSMA/CD协议的()

答案:ETHERNET。

(4)TCP 和UDP 协议的相似之处是

答案:传输层协议。

(5)应用程序PING 发出的是___报文.( )

答案:ICMP 请求报文。

 

 

....未完待续....

 

 

 

你可能感兴趣的:(C语言,嵌入式)