PowerWind

网络管理和高校信息化

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

名企笔试之联发科技(合肥)

Posted on 2011-06-25 16:19  PowerWind  阅读(1877)  评论(0编辑  收藏  举报

 

第一卷是选择题

第二卷是大题,1)英语翻译 2)C++程序题填空

3)已知a为[0,f]之间的16进制整数,n为a的个数,编写程序求出表达式:
a+aa+aaa+……+a^^^a;其中最后一项有n个a;   //
recursion
int Sum(int a,int n);/*
函数声明*/这一题我用的是递归方法,因为Sum(a,n)=Sum(a,n-1)+a^^^a;(n个a);令T=0;则,for(i=0;i<n;i++)T=T*16+a;

int Receursion(int a,int n)

{

      if(n==1)

      {

           return a;

      }

      else

      {

           return ((Receursion(a,n-1)+1)*a);

      }

}

int main()

{

      int a=10;

      cout<<Receursion(a,3)<<endl;

      getchar();

}

4)求链表的节点个数;结构如下:typedef struct Link {
                              int     data;
                               struct Link *next;
                               }Link;其中链表可能有环,既尾指针不一定为NULL;
int Count_p(Link *pHead);/*函数声明*/

int count=0;

      int *p = pHead;

      if(p == NULL)

      {

           return count;

      }

      else

      {

           do

           {

                 p=p->next;

                 count++;

           }

           while((p!=NULL)&&(p!=pHead))

      

5)不使用库函数,编写一个函数将一个整数转化为字符串!(应该是将10进制正证书转化为字符串)

void trans(const int a,char *&str)

{

      int count = 0;

      int b= a;

      if(b<0)

      {

           return;

      }

      while(b>0)

      {

           b=b/10;

           count++;

      }

      str = new char[count+1];

      str[count+1]=0;

      b=a;

      while(b>0)

      {

           str[count-1] = ((int)'0')+b%10;

           b = b/10;

           count -- ;

      }

}

      char *str;

      trans(123321,str);

      cout<<str<<endl;

附加题:有点难度,int ripple(int,...);设计一个函数,不限制参数个数,就象printf()里不限制参数个数一样

深入浅出可变参数函数的使用技巧本文主要介绍可变参数的函数使用,然后分析它的原理,程序员自己如何对它们实
现和封装,最后是可能会出现的问题和避免措施。

VA函数(variable argument function),参数个数可变函数,又称可变参数函数
C/C++编程中,系统提供给编程人员的va函数很少。*printf()/*scanf()系列函数
,用于输入输出时格式化字符串;exec*()系列函数,用于在程序中执行外部文件(
main(int argc,char*argv[]
算不算呢,与其说main()也是一个可变参数函数,倒不
如说它是exec*()经过封装后的具备特殊功能和意义的函数,至少在原理这一级上有
很多相似之处)。由于参数个数的不确定,使va函数具有很大的灵活性,易用性,对
没有使用过可变参数函数的编程人员很有诱惑力;那么,该如何编写自己的va函数
va函数的运用时机、编译实现又是如何。作者借本文谈谈自己关于va函数的一些
浅见。

一、 printf()开始

从大家都很熟悉的格式化字符串函数开始介绍可变参数函数。

原型:int printf(const char * format, ...);

参数format表示如何来格式字符串的指令,

表示可选参数,调用时传递给"..."的参数可有可无,根据实际情况而定。

系统提供了vprintf系列格式化字符串的函数,用于编程人员封装自己的I/O函数。


int vprintf / vscanf(const char * format, va_list ap); //
从标准输入/输出
格式化字符串

int vfprintf / vfsacanf(FILE * stream, const char * format, va_list ap);
//
从文件流

int vsprintf / vsscanf(char * s, const char * format, va_list ap); //
字符串

// 1:格式化到一个文件流,可用于日志文件

FILE *logfile;

int WriteLog(const char * format, ...)

{

va_list arg_ptr;

va_start(arg_ptr, format);

int nWrittenBytes = vfprintf(logfile, format, arg_ptr);

va_end(arg_ptr);

return nWrittenBytes;

}

// 调用时,与使用printf()没有区别。

WriteLog("%04d-%02d-%02d %02d:%02d:%02d  %s/%04d logged out.",

nYear, nMonth, nDay, nHour, nMinute, szUserName, nUserID);

 

同理,也可以从文件中执行格式化输入;或者对标准输入输出,字符串执行格式化

在上面的例1中,WriteLog()函数可以接受参数个数可变的输入,本质上,它的实现
需要vprintf()的支持。如何真正实现属于自己的可变参数函数,包括控制每一个传
入的可选参数。

二、 va函数的定义和va

C语言支持va函数,作为C语言的扩展--C++同样支持va函数,但在C++中并不推荐使
用,C++引入的多态性同样可以实现参数个数可变的函数。不过,C++的重载功能毕
竟只能是有限多个可以预见的参数个数。比较而言,C中的va函数则可以定义无穷多
个相当于C++的重载函数,这方面C++是无能为力的。va函数的优势表现在使用的方
便性和易用性上,可以使代码更简洁。C编译器为了统一在不同的硬件架构、硬件平
台上的实现,和增加代码的可移植性,提供了一系列宏来屏蔽硬件环境不同带来的
差异。

ANSI C标准下,va的宏定义在stdarg.h中,它们有:va_listva_start()va_ar
g()
va_end()

// 2:求任意个自然数的平方和:

int SqSum(int n1, ...)

{

va_list arg_ptr;

int nSqSum = 0, n = n1;

va_start(arg_ptr, n1);

while (n > 0)

{

    nSqSum += (n * n);

    n = va_arg(arg_ptr, int);

}

va_end(arg_ptr);

return nSqSum;

}

// 调用时

int nSqSum = SqSum(7, 2, 7, 11, -1);

 

可变参数函数的原型声明格式为:

type VAFunction(type arg1, type arg2, … );

参数可以分为两部分:个数确定的固定参数和个数可变的可选参数。函数至少需要
一个固定参数,固定参数的声明和普通函数一样;可选参数由于个数不确定,声明
时用"…"表示。固定参数和可选参数公同构成一个函数的参数列表。

借助上面这个简单的例2,来看看各个va_xxx的作用。

va_list arg_ptr:定义一个指向个数可变的参数列表指针;

va_start(arg_ptr, argN):使参数列表指针arg_ptr指向函数参数列表中的第一个
可选参数,说明:argN是位于第一个可选参数之前的固定参数,(或者说,最后一
个固定参数;之前的一个参数),函数参数列表中参数在内存中的顺序与函数声
明时的顺序是一致的。如果有一va函数的声明是void va_test(char a, char b, c
har c, …)
,则它的固定参数依次是a,b,c,最后一个固定参数argNc,因此就是
va_start(arg_ptr, c)

va_arg(arg_ptr, type):返回参数列表中指针arg_ptr所指的参数,返回类型为ty
pe
,并使指针arg_ptr指向参数列表中下一个参数。

va_copy(dest, src)destsrc的类型都是va_listva_copy()用于复制参数列表
指针,将dest初始化为src

va_end(arg_ptr):清空参数列表,并置参数指针arg_ptr无效。说明:指针arg_pt
r
被置无效后,可以通过调用va_start()va_copy()恢复arg_ptr。每次调用va_st
art() / va_copy()
后,必须得有相应的va_end()与之匹配。参数指针可以在参数列
表中随意地来回移动,但必须在va_start() … va_end()之内。

 

用法:
func( Type para1, Type para2, Type para3, ... )
{
      /****** Step 1 ******/
      va_list ap;
      va_start( ap, para3 ); //
一定要“...”之前的那个参数**ap指向para后的第一个可变参数。
    
      /****** Step 2 ******/
      //
此时ap指向第一个可变参数
      //
调用va_arg取得里面的值
    
      Type xx = va_arg( ap, Type ); 
    
      //Type
一定要相同,如:
      //char *p = va_arg( ap, char *);
      //int i = va_arg( ap, int );
      //
如果有多个参数继续调用va_arg
      /****** Step 3 ******/
      va_end(ap); //For robust!
}
研究:
typedef char *    va_list;//va_list 
等价于char*即字符指针。
#define va_start _crt_va_start//
注意下面的替代。
#define va_arg _crt_va_arg
#define va_end _crt_va_end
#define  _crt_va_start(ap,v)    ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t)      ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap)        ( ap = (va_list)0 ) 
va_list argptr;
C
语言的函数是从右向左压入堆栈的,调用va_start后,
按定义的宏运算,_ADDRESSOF得到v所在的地址,然后这个
地址加上v的大小,则使ap指向第一个可变参数如图:     
    
    
栈底 高地址
    | .......     
    | 
函数返回地址
    | .......      
    | 
函数最后一个参数
    | ....                       
    | 
函数第一个可变参数       <--va_startap指向 
    | 
函数最后一个固定参数
    | 
函数第一个固定参数 
    
栈顶 低地址
     
    
然后,用va_arg()取得类型t的可变参数值先是让ap指向下一个参数:
ap += _INTSIZEOF(t)
,然后在减去_INTSIZEOF(t),使得表达式结果为
ap
之前的值,即当前需要得到的参数的地址,强制转换成指向此参数的
类型的指针,然后用*取值
最后,用va_end(ap),给ap初始化,保持健壮性。
example:(chenguiming)
#include    <stdio.h>   
   #include    <ctype.h>   
   #include<stdlib.h>   
   #include    <stdarg.h>   
    
   int    average(    int    first,    ...    )      //
变参数函数,C++里也有  **…表明后面有好多可变的参数。 
   {   
         int    count=0,i=first,sum=0;   
         va_list    maker;           //va_list    
类型数据可以保存函数的所有参数,做为一个列表一样保存。Va_list即是char*表明maker是一个字符型的指针。   
         va_start(maker,first);    //
设置列表的起始位置   **frist只是和maker在一起做参数,这并不说明maker指向frist而是指向first之后的第一个可变的参数,而frist是作为一个固定参数,因为它在之前。这时候frist指向3
         while(i!=-1)   
         {   
         sum+=i;   
         count++;   
         i=va_arg(maker,int);//
返回maker列表的当前值,并指向列表的下一个位置   
         }   
//
第一次:I=2sum=2
第二次:I=3,因为va_start(maker,first);sum=2+3=5;同时i=va_arg(maker,int)又使I=4
第三次:I=4sum=5+4=9,同理I=4
第四次I=4sum=9+4=13同理I=-1

         return    sum/count;   
          
   }   
    
   void    main(void)   
   {   
   printf(    "Average    is:    %d\n",    average(    2,    3,    4,4,    -1    )    );   
   }   
注意它们的头文件stdarg..h
std
很正常arg 是参数的意思;
辅助理解:
va_start(arg_ptr, argN)
:使参数列表指针arg_ptr指向函数参数列表中的第一个可选参数,说明:argN是位于第一个可选参数之前的固定参数,(或者说,最后一个固定参数;之前的一个参数),函数参数列表中参数在内存中的顺序与函数声明时的顺序是一致的。如果有一va函数的声明是void va_test(char a, char b, char c, …),则它的固定参数依次是a,b,c,最后一个固定参数argNc,因此就是va_start(arg_ptr, c)
  
  va_arg(arg_ptr, type):返回参数列表中指针arg_ptr所指的参数,返回类型为type,并使指针arg_ptr指向参数列表中下一个参数。
  
  va_copy(dest, src)destsrc的类型都是va_listva_copy()用于复制参数列表指针,将dest初始化为src
  
  va_end(arg_ptr):清空参数列表,并置参数指针arg_ptr无效。说明:指针arg_ptr被置无效后,可以通过调用 va_start()va_copy()恢复arg_ptr。每次调用va_start() / va_copy()后,必须得有相应的va_end()与之匹配。参数指针可以在参数列表中随意地来回移动,但必须在va_start() … va_end()之内。
  

 

合肥联发科技的笔试题(含答案)

1.桌面上有23个硬币,其中10个正面朝上,现在要将你眼睛蒙住,将这些硬币分为两组,(假设硬币的正反面手指是摸不出来的),要求每组中正面朝上的硬币数量相同。请你用最好的方法进行分组。

 

2.AB两个人在一月份首次去健身房时认识,A在一月份第一个星期的星期一去了健身房,然后每隔四天去一次(即第五天去),而B每隔三天去一次(即第四天去)。一月份AB只相遇了一次,即首次认识的那天。请问,AB是在一月份31天中的哪天认识的?

 

3.ABC三人参加了一个体育运动,包括M个项目,每个项目的第一、二、三名分别可获得XYZ积分。其中B得了百米跑第一名。比赛结束,A得分22BC均为9。请问,M值为多少,跳高第二名是谁?

 

4.对一个英文句子加密。要求句子中的字母用该字母在26位字母表后的第三个字母来代替,例如def,在加密后显示为ghi。如为其他字符则不变。请写出具体分析过程及程序实现代码。(写出流程图也有部分加分)

void Encrypt(char a[],int n,char b[])

{

      for(int i=0;i<n;i++)

      {

           if(a[i]<='z'&&a[i]>='a')

           {

                 b[i]=(a[i]+3-('a'))%26+('a');

           }

           else if((a[i]<='Z'&&a[i]>='A'))

           {

                 b[i]=(a[i]+3-('A'))%26+('A');

 

           }

      }

}

5.请用程序来实现一个复数类Complex,要包含.h.cpp文件。Complex类要能实现以下功能:

Complex comp1(2,3);

Complex comp2(comp1);

Complex comp3(3,4);

comp1+comp3;

comp1=comp3;

printf(“comp1==comp3:%s”,comp1==comp3?true:false);

printf(“comp2==comp3:%s”,comp2==comp3?true:false);

 

6.1-3+5……+101的值,以下为实现代码,请补全:

Void m()

{

int i,s,t=1;

For(int i=1;i<=101;i++)

{

s=s+i*t_______;

i=i+1;

t=-1*t________;

}

Printf(“s=%d”,s);

Return;

}

题目转载自应届生求职招聘论坛 http://bbs.yingjiesheng.com/

 

 

参考答案(不保证正确)

答案1. 2堆,一堆10个,一堆13个,然后把10个的那堆翻过来就Ok啦。。。(选择合工大青春无名论坛)

分析:10个正面的硬币,在分组时可能被分为mn,设10个堆中的是m个正面的,则此堆中反面为10 - m = n个。10个的堆翻过来,和13个的n个正面的,数目相同。

(看别人的回答,我还想了半天,真是郁闷呀!)

 

答案2:健身俱乐部根据(1a)和(2a),利兹第一次去健身俱乐部的日子必定是以下二者之一:

A)肯第一次去健身俱乐部那天的第二天。

B)肯第一次去健身俱乐部那天前六天。

如果(A)是实际情况,那么根据(1b)和(2b),肯和利兹第二次去健身俱乐部便是在同一天,而且在20 天后又是同一天去健身俱乐部。根据(3),他们再次都去健身俱乐部的那天必须是在二月份。可是,肯和利兹第一次去健身俱乐部的日子最晚也只能分别是一月份的第六天和第七天;在这种情况下,他们在一月份必定有两次是同一天去健身俱乐部:1 11 日和1 31 日。因此(A)不是实际情况,而(B)是实际情况。

在情况(B)下,一月份的第一个星期二不能迟于1 1 日,否则随后的那个星期一将是一月份的第二个星期一。因此,利兹是1 1 日开始去健身俱乐部的,而肯是1 7 日开始去的。于是根据(1b)和(2b),他二人在一月份去健身俱乐部的日期分别为:利兹:1 日,5 日,9 日,13 日,17 日,21 日,25 日,29 日;肯:7 日,12 日,17 日,22 日,27 日。因此,根据(3),肯和利兹相遇于1 17 日。

 

第三题见本文档最后,1986年加拿大数学竞赛题,类似

 

4答:

1)判断输入字符ch是否是字母,大写还是小写?(A-Z)或(a-z;

3)是字母,则将ch += 3

4)如果是大写字母,且ch > 'Z',则ch + 'A' - 'Z';否则,如果是小写字母,且ch > 'z',则ch + 'a' - 'z'

5)输出ch

 

5分析:

由功能看是要考查类的构造函数、拷贝构造函数和运算符重载等知识点。主要代码如下:Complex() // 无参数构造函数

 

{

 

}

 

Complex::Complex(float r, float i); // 有参数构造函数

 

{

 

 real = r;

 

 imag = i;

 

}

 

Complex::Complex(Complex &cpx); // 拷贝构造函数,其实默认拷贝构造函数已经满足要求

 

{

 

 real = cpx->real;

 

 imag = cpx->imag;

 

}

 

Complex Complex::operator +(Complex c2)

 

{

 

 return Complex(real + c2.real, imag + c2.imag);

 

}

Complex Complex::operator ==(Complex c2)

 

{

       return(real ==c2.real&&imag == c2.imag);

 

 

}

 

 

 101986年加拿大数学竞赛题)有一种体育竞赛共含M个项目,有运动员ABC参加,在每个项目中,第一、二、三名分别得p1p2p3分,其中p1p2p3为正整数且p1p2p3,最后A22分,BC均得9分,B在百米赛中取得第一,求M的值,并问在跳高中谁取得第二名?

 

 分析 考虑三个得的总分,有方程:

 

 M(p1+p2+p3)=22+9+9=40,          

 

         p1+p2+p31+2+3=6   

 

 6MM(p1+p2+p3)=40,从而M6.

 

 由题设知至少有百米和跳高两个项目,从而M2

 

 M|40,所以M可取245.

 

 考虑M=2,则只有跳高和百米,而B百米第一,但总分仅9分,故必有:9p1+p3,∴≤8,这样A不可能得22.

 

 M=4,由B可知:9p1+3p3,又p31,所以p16,p15,那么四项最多得20分,A就不可能得22分,故p1=6.

 

 4p1+p2+p3=40,p2+p3=4.

 

 故有:p2=3,p3=1,A最多得三个第一,一个第二,一共得分3×6+3=2122,矛盾.

 

 M=5,这时由5(p1+p2+p3)=40,得:

 

 p1+p2+p3=8.p32,则:

 

 p1+p2+p34+3+2=9,矛盾,故p3=1.

 

 p1必须大于或等于5,否则,A五次最高只能得20,与题设矛盾,所以p15.

 

 p16,则p2+p32,这也与题设矛盾,∴p1=5p2+p3=3,即p2=2p3=1.

 

 A=22=4×5+2.

 

 A得了四个第一,一个第二;

 

 B=9=5+4×1

 

 B得了一个第一,四个第三;

 

 C=9=4×2+1

 

 C得了四个第二,一个第三.

 

一:编程题(每题20分,共40)

 

1: 编写两个函数,接口如下:第一个负责把一个ASCII字符串转换为一个带符号整数,第二个函数负责把一个带符号的整数转换为一个ASCII字符串。

(1) int StrToInt (c*****t char* pStr);

解答:

#include <iostream.h>

#include "string.h"

#include<stdio.h>

 

int StrToInt (c*****t char* pStr)

{

    int iResult = 0;

    bool bMinus = false;

    int itemp = 0;

    int i = 0;

 

    if(*(pStr+i) == '-')

    {

        bMinus = true;

        i++;

    }

 

    do

    {

        itemp = *(pStr+i) - 0x30;

        iResult = iResult*10+itemp;

        i++;

    }while(*(pStr+i) !='\0');

 

    if(bMinus == true)

        iResult = 0-iResult;

 

    return iResult;

}

 

int main()

{

    char s[] = "-456789";

    int iNum = StrToInt((char*)s);

    printf("%d\n",iNum);

}

(2) int IntToStr (int num, char* pStr);

已知条件:传递给IntToStr函数的缓冲区的长度是能够容纳int整数范围内的数; 传递给StrToInt的字符串只包含数字和‘-’(负号),是一个格式正确的整数值。

 

2:编程实现二分法搜索函数,该函数对一个排序好的整数数组进行二分搜索(binary Search,函数的原型如下:

    Int BinarySearch(c*****t int* array, int lower, int upper, int target);

其中lowerupper分别是需要进行搜索的开始和结束的索引值,请分别使用递归和非递归两种方法实现该函数。

 

二:问答题(每题6分,10题,共60分)

 

1:下面这个程序执行后会有什么错误或者效果

#define MAX 255

int main(void)

{

    unsigned char I;

    unsigned char A[MAX];

   

    for(i=0; i<=MAX; i++)

    {

        A = i;

    }

   

    Return 0;

}

 


2:32位小端字节序系统里,

char array[16] ={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}

char* cp = array;

int* ip = (int*)array;

问:(1)*(cp+2)=?

    (2)*(ip+2)=?

 


3:c是一个char类型的变量,c的取值范围是多少?如果c的值是0xF0,那么 c>>3=? 请给出10进制的答案。

 


4:调用函数时,请列举不使用函数原型潜在的风险。

 


5:下面函数实现有问题吗? 如果有问题,实际运行中调用下面函数结果正确,并没有出现问题,为什么?

 


int Exchange Value(int* pa, int* pb)

{

    int* pt;

    if(pa == NULL || pb == NULL)

        return 0;

 


    *pt = *pa;

    *pa = *pb;

    *pb = *pt;

    return 1;

}

6:  int i1;

    C*****t char* p1 = “AAA”;

    int main()

{

    static int i2;

    int i3;

    int* i4 = malloc(sizeof(int));

    。。。。。。

 


}

上面程序中的变量(i1,p1,i2,i3,i4)分别存在于哪些内存存贮位置(数据段、堆栈或队)?

i1,i2,i3,*i4的值是什么?

 


7:下面哪组语句没有编译和运行的错误?如果有错误的组,请说明哪些语句是错误的,为什么?

 


A.
     c*****t int a; (1)

B.
     char* pa = “AAA”(1)

c*****t char* pb = “BBB”; (2)

pb = pa; (3)

C. char* pa = “AAA”; (1)

   Char* c*****t pb = “BBB”; (2)

   Char* c*****t pc = (char*) malloc(4); (3)

   *pb = ‘A’; (4)

   *(pc+1) = ‘A’;(5)

   Pb = pa;        (6)

 


D. char* pa; (1)

c*****t char* c*****t pb = ”BBB”; (2)

char* c*****t pc; (3)

pa = “AAA”;(4)

pc = pa;(5)

 


8:用变量a给出下面的定义: 举例一个整型数  int a;

(1)
 一个指向指针的指针,它指向的指针是指向一个整型数

(2)
 一个有10个整型数的数组

(3)
 一个有10个指针的数组,该指针是指向一个整型数

(4)
 一个指向有10个整型数组的指针

(5)
 一个指向函数的指针,该函数有一个整型参数并返回一个整型数

(6)
 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数

 


9:请编写一个函数,将216位有符号数分别放入一个32位有符号数的高16位和低16位,请不要使用函数的返回值传递数据。

 


10 下面是一个用来删除单向链表头节点的函数,请找出其中程序的漏洞并加以纠正。

       

        void RemoveHead (node* head)

        {

            free(head);   /* Line1 */

            head = head->next;  /Line2 */

        }