华为笔试题五

来源:互联网 发布:c语言break语句 编辑:程序博客网 时间:2024/04/27 16:11

(一) 初级题


1. 什么是预编译,何时需要预编译:
答:

预编译又称为预处理,是做些代码文本的替换工作,处理#开头的指令,比如拷贝#include包含的文件代码,#define宏定义的替换,条件编译等 ,就是为编译做的预备工作的阶段,主要处理#开始的预编译指令,预编译指令指示了在程序正式编译前就由编译器进行的操作,可以放在程序中的任何位置。

(1) 总是使用不经常改动的大型代码体
(2) 程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。在这种情况下,可以将所有包含文件预编译为一个预编译头

(3)  用于创建预编译头文件的第一次编译所花费的时间比后面的编译稍长一些。通过包含预编译代码可以加快后面的编译速度。  


2. char * const p
   char const * p
   const char *p
上述三个有什么区别?

答:
char * const p; //常量指针,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 " ;
char   * str8  =   " abc " ;

cout 
<<  ( str1  ==  str2 )  <<  endl;
cout 
<<  ( str3  ==  str4 )  <<  endl;
cout 
<<  ( str5  ==  str6 )  <<  endl;
cout 
<<  ( str7  ==  str8 )  <<  endl;

结果是:0 0 1 1

str1,str2,str3,str4是数组变量,它们有各自的内存空间;而str5,str6,str7,str8是指针,它们指向相同的常量区域。


4. 以下代码中的两个sizeof用法有问题吗?

void  UpperCase(  char  str[] )  //  将 str 中的小写字母转换成大写字母
{
    
for ( size_t i = 0 ; i < sizeof (str) / sizeof (str[ 0 ]);  ++ i )
        
if ' a ' <= str[i]  &&  str[i] <= ' z '  )
            str[i] 
-=  ( ' a ' - ' A '  );
}
char  str[]  =   " aBcDe " ;
cout 
<<   " str字符长度为:  "   <<   sizeof (str) / sizeof (str[ 0 ])  <<  endl;
UpperCase( str );
cout 
<<  str  <<  endl;

答:函数内的sizeof有问题。根据语法,sizeof如用于数组,只能测出静态数组的大小,无法检测动态分配的或外部数组大小。函数外的str是一个静态定义的数组,因此其大小为6,因为还有'/0',函数内的str实际只是一个指向字符串的指针,没有任何额外的与数组相关的信息,因此sizeof作用于上只将其当指针看,一个指针为4个字节,因此返回4。所以只能使str数组里面的前四个字母变成大写。


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

6.

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

答:2,5

*(a+1)就是a[1],*(ptr-1)就是a[4], 执行结果是2, 5。&a+1不是首地址+1,系统会认为加一个a数组的偏移,是偏移了一个数组的大小(本例是5个int)。int *ptr=(int *)(&a+1); 则ptr实际是&(a[5]),也就是a+5

原因如下:

&a是数组指针,其类型为 int (*)[5]; 而指针加1要根据指针类型加上一定的值,不同类型的指针+1之后增加的大小不同; a是长度为5的int数组指针,所以要加 5*sizeof(int)。所以ptr实际是a[5]。但是prt与(&a+1)类型是不一样的(这点很重要),所以prt-1只会减去sizeof(int*)。a,&a的地址是一样的,但意思不一样,a是数组首地址,也就是a[0]的地址,&a是对象(数组)首地址,a+1是数组下一元素的地址,即a[1],&a+1是下一个对象的地址,即a[5]。


7. 请问以下代码有什么问题:

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

 

答:没有为str分配内存空间,将会发生异常。问题出在将一个字符串复制进一个字符变量指针所指地址。虽然可以正确输出结果,但因为越界进行内在读写而导致程序崩溃。


8.
char* s="AAA";
printf("%s",s);
s[0]='B';
printf("%s",s);

有什么错?

答:"AAA"是字符串常量。s是指针,指向这个字符串常量,所以声明s的时候就有问题。
cosnt char* s="AAA"; 然后又因为是常量,所以对是s[0]的赋值操作是不合法的。


9. 写一个“标准”宏,这个宏输入两个参数并返回较小的一个。
答:#define Min(X, Y) ((X)>(Y)?(Y):(X)) //结尾没有';'


10. 嵌入式系统中经常要用到无限循环,你怎么用C编写死循环。
答:while(1){}或者for(;;)


11. 关键字static的作用是什么?
答:定义静态变量


12. 关键字const有什么含意?
答:加const前缀的变量,就是一个常量除了第一次声明的时候赋值,以后不可以更改。


13. 关键字volatile有什么含意?并举出三个不同的例子?
答:提示编译器对象的值可能在编译器未监测到的情况下改变。


14. int (*s[10])(int) 表示的是什么啊?
答:int (*s[10])(int) 函数指针数组,每个指针指向一个int func(int param)的函数。


15. 有以下表达式:
int a=248; b=4; int const c=21; const int *d=&a;
int *const e=&b; int const *f const =&a;

请问下列表达式哪些会被编译器禁止?为什么?

*c=32; d=&b; *d=43; e=34; e=&a; f=0x321f;

答:*c=32,const型的常量;*d=43  const int *d 指向的值不能改变;e=34,e=&a, e是const指针;f=ox321f禁止。


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

答:有两种解法, 一种用算术算法, 一种用^(异或)

a = a + b;
b = a - b;
a = a - b;

or

a = a^b;// 只能对int,char..
b = a^b;
a = a^b;

or

a ^= b ^= a;


17.

#include  < stdio.h >
#include  
< stdlib.h >

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

int  main( )
{
    
char   * str = NULL;
    getmemory(str);
    printf(
" %s/n " ,str);
    free(str);
    
return   0 ;
}

 

答:程序崩溃,getmemory中的malloc 不能返回动态内存, free()对str操作很危险


18. 列举几种进程的同步机制,并比较其优缺点。
答:原子操作、信号量机制、自旋锁、管程、会合、分布式系统


20. 进程之间通信的途径
答:共享存储系统、消息传递系统、管道:以文件系统为基础


21. 进程死锁的原因和4个必要条件
答:资源竞争及进程推进顺序非法;互斥、请求保持、不可剥夺、环路


22. 死锁的处理
答:鸵鸟策略、预防策略、避免策略、检测与解除死锁


23. 操作系统中进程调度策略有哪几种?
答:FCFS(先来先服务),优先级,时间片轮转,多级反馈


24. 类的静态成员和非静态成员有何区别?
答:类的静态成员每个类只有一个,非静态成员每个对象一个


25. 纯虚函数如何定义?使用时应注意什么?
答:virtual void f()=0; 是接口,子类必须要实现


26. 数组和链表的区别
答:
数组:数据顺序存储,固定大小
链表:数据可以随机存储,大小可动态改变


27. ISO的七层模型是什么?tcp/udp是属于哪一层?tcp/udp有何优缺点?
答:应用层、表示层、会话层、运输层、网络层、物理链路层、物理层
tcp/udp属于运输层
TCP服务提供了数据流传输、可靠性、有效流控制、全双工操作和多路复用技术等。
与TCP 不同, UDP并不提供对IP协议的可靠机制、流控制以及错误恢复功能等。由于UDP比较简单,UDP头包含很少的字节,比TCP负载消耗少
tcp: 提供稳定的传输服务,有流量控制,缺点是包头大,冗余性不好
udp: 不提供稳定的服务,包头小,开销小 


28. (void *)ptr 和 (*(void**))ptr的结果是否相同?其中ptr为同一个指针
答:(void *)ptr 和 (*(void**))ptr值是相同的

 

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

答:main中,c标准认为0表示成功,非0表示错误。具体的值是某中具体出错信息


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

答:*((void (*)( ))0x100000 ) ( );

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


31. 已知一个数组table,用一个宏定义,求出数据的元素个数
答:

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


32. 线程与进程的区别和联系? 线程是否具有相同的堆栈? dll是否有独立的堆栈?
答:进程是死的,只是一些资源的集合,真正的程序执行都是线程来完成的,程序启动的时候操作系统就帮你创建了一个主线程。每个线程有自己的堆栈。DLL中有没有独立的堆栈,这个问题不好回答,或者说这个问题本身是否有问题。因为DLL中的代码是被某些线程所执行,只有线程拥有堆栈,如果DLL中的代码是EXE中的线程所调用,那么这个时候是不是说这个DLL没有自己独立的堆栈?如果DLL中的代码是由DLL自己创建的线程所执行,那么是不是说DLL有独立的堆栈?

以上讲的是堆栈,如果对于堆来说,每个DLL有自己的堆,所以如果是从DLL中动态分配的内存,最好是从DLL中删除,如果你从DLL中分配内存,然后在EXE中,或者另外一个DLL中删除,很有可能导致程序崩溃


33.
unsigned short A = 10;
printf("~A = %u/n", ~A);
char c=128;
printf("c = %d/n",c);

输出多少?并分析过程

答:
第一题,~A =0xfffffff5, int值为-11(取反+1),但输出的是uint。所以输出4294967285(0xfffffff5)。
第二题,c=0x10,输出的是int,最高位为1,是负数,所以它的值就是0x00的补码就是128,所以输出-128。
这两道题都是在考察二进制向int或uint转换时的最高位处理。

unsigned本身是unsigned int的缩写


(二) 中级题

1. -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)

2. 用两个栈实现一个队列的功能?要求给出算法和思路!
答:设2个栈为A,B, 一开始均为空.

入队:
将新元素push入栈A;

出队:
(1)判断栈B是否为空;
(2)如果不为空,则将栈A中所有元素依次pop出并push到栈B;
(3)将栈B的栈顶元素pop出;

这样实现的队列入队和出队的平摊复杂度都还是O(1), 比上面的几种方法要好。

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

答:
函数名: atol
功  能: 把字符串转换成长整型数
用  法: long atol(const char *nptr);

程序例:

#include  < stdlib.h >
#include  
< stdio.h >
int  main( void )
{
   
long  l;
   
char   * str  =   " 98765432 " ;
   l 
=  atol(lstr);
   
   printf(
" string = %s integer = %ld/n " , str, l);
   
return ( 0 );
}

 

4. 对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现?
答:c用宏定义,c++用inline

5. 直接链接两个信令点的一组链路称作什么?
答:PPP点到点连接

7. 软件测试都有那些种类?
答:黑盒:针对系统功能的测试    白合:测试函数功能,各函数接口

8. 确定模块的功能和模块的接口是在软件设计的那个队段完成的?
答:概要设计阶段

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

请问
p1+5=______;
p2+5=______;

答案:801005;810014。不要忘记了这个是16进制的数字,p2要加20变为16进制就是14


选择题:

1. Ethternet链接到Internet用到以下那个协议?

A.HDLC;  B.ARP;  C.UDP;  D.TCP;  E.ID

2. 属于网络层协议的是:

A.TCP;  B.IP;  C.ICMP;  D.X.25

3.Windows消息调度机制是:

A.指令队列;  B.指令堆栈;  C.消息队列;  D.消息堆栈;

答:b,a,c


找错题:

1. 请问下面程序有什么错误?

int  a[ 60 ][ 250 ][ 1000 ],i,j,k;
for (k = 0 ;k <= 1000 ;k ++ )
    
for (j = 0 ;j < 250 ;j ++ )
        
for (i = 0 ;i < 60 ;i ++ )
            a[i][j][k]
= 0 ;

 

答:把循环语句内外换一下(???出界吧?)

 

2. 以下是求一个数的平方的程序,请找出错误:

#define SQUARE(a) ((a)*(a))
int a=5;
int b;
b=SQUARE(a++);

答案:这个没有问题,s(a++),就是((a++)×(a++))唯一要注意的就是计算后a=7了

 

3. 找错误

typedef unsigned  char  BYTE

int  examply_fun(BYTE gt_len; BYTE  * gt_code)
{
    BYTE 
* gt_buf;
    
    gt_buf
= (BYTE  * )MALLOC(Max_GT_Length);
    
    
       
    
if (gt_len > Max_GT_Length)
    {
        
return  GT_Length_ERROR; 
    }
     .
}

答:要释放内存


问答题:

1.IP Phone的原理是什么?
答:IPV6

2.TCP/IP通信建立的过程怎样,端口有什么作用?
答:三次握手,确定是哪个应用程序使用该协议

 

(三) 高级题

1、static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?

答:全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。 这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序, 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。

而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用, 因此可以避免在其它源文件中引起错误。从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域, 限制了它的使用范围。

static函数与普通函数作用域不同。仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件
static全局变量与普通的全局变量有什么区别:static全局变量只初使化一次,防止在其他文件单元中被引用;
static局部变量和普通局部变量有什么区别:static局部变量只被初始化一次,下一次依据上一次结果值;
static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝


2、程序的局部变量存在于( )中,全局变量存在于( )中,动态申请数据存在于( )中。
答:栈;静态区;堆


3、设有以下说明和定义:
typedef union {long i; int k[5]; char c;} DATE;
struct data { int cat; DATE cow; double dog;} too;
DATE max;

则语句 printf("%d",sizeof(too)+sizeof(max));的执行结果是:______

答:DATE是一个union, 变量公用空间. 里面最大的变量类型是int[5], 占用20个字节. 所以它的大小是20
data是一个struct, 每个变量分开占用空间. 依次为int4 + DATE20 + double8 = 32.
所以结果是 20 + 32 = 52.

当然...在某些16位编辑器下, int可能是2字节,那么结果是 int2 + DATE10 + double8 = 20


4、队列和栈有什么区别?
答:队列先进先出,栈后进先出÷


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

答:

slnodetype  * Delete(slnodetype  * Head, int  key)
{
    
if (Head -> number == key)
    {
        Head
= Pointer -> next;
        free(Pointer);
        
break ;
    }
    
    Back 
=  Pointer;
    Pointer
= Pointer -> next;
    
    
if (Pointer -> number == key)
    {
        Back
-> next = Pointer -> next;
        free(Pointer);
        
break ;
    }
    
 
}

 

7、请找出下面代码中的所以错误

说明:以下代码是把一个字符串倒序,如“abcd”倒序后变为“dcba”

#include   " string.h "

main()
{
    
char * src = " hello,world " ;
    
char *  dest = NULL;

    
int  len = strlen(src);

    dest
= ( char * )malloc(len);
    
    
char *  d = dest;
    
char *  s = src[len];

    
while (len --!= 0 )
        d
++= s -- ;
    printf(
" %s " ,dest);
    
return   0 ;
}

 

答:还要加上#include <stdio.h>,#include <malloc.h>

int  main()
{
    
char *  src  =   " hello,world " ;
    
int  len  =  strlen(src);
    
char *  dest  =  ( char * )malloc((len + 1 ) * sizeof ( char ));  // 要为/0分配一个空间
     char *  d  =  dest;
    
char *  s  =   & src[len - 1 ];  // 指向最后一个字符
     while ( len --   !=   0  )
        
* d ++=* s -- ;
    
* =   0 // 尾部要加/0
    printf( " %s/n " ,dest);
    free(dest);
//  使用完,应当释放空间,以免造成内存汇泄露
     return   0 ;
}
原创粉丝点击