Chinaunix首页 | 论坛 | 博客
  • 博客访问: 201207
  • 博文数量: 27
  • 博客积分: 1400
  • 博客等级: 上尉
  • 技术积分: 350
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-22 08:34
文章分类

全部博文(27)

文章存档

2011年(1)

2010年(1)

2009年(25)

我的朋友

分类: C/C++

2009-10-22 17:38:36

这是老师收集的c语言笔试题,顺手拿来在blog上收藏了,呵呵,分享一下。
1:(void *)ptr 和 (*(void**))ptr的结果是否相同?其中ptr为同一个指针
 
【解答】:
(void *)ptr 和 (*(void**))ptr值是相同的
2:int main()
  {
  int x=3;
  printf("%d",x);
  return 1;
  }
  问函数既然不会被其它函数调用,为什么要返回1?
 
【解答】: main中,c标准认为0表示成功,非0表示错误。具体的值是其中具体出错信息

3.已知一个数组table,用一个宏定义,求出数据的元素个数
  #define NTBL

【解答】:#define NTBL (sizeof(table)/sizeof(table[0]))
4.
  unsigned short A = 10;
  printf("~A = %u\n", ~A);
  char c=128;
  printf("c=%d\n",c);
  输出多少?并分析过程

【解答】:第一个printf,~A =0xfffffff5,int值 为-11,但输出的是uint。所以输出4294967285
  第二个printf,c=0x10,输出的是int,最高位为1,是负数,所以它的值就是0x00的补码就是128,所以输出-128。
  这两道题都是在考察二进制向int或uint转换时的最高位处理。
5.
分析下面的程序:
  void GetMemory(char **p,int num)
  {
  *p=(char *)malloc(num);
  }
  int main()
  {
  char *str=NULL;
  GetMemory(&str,100);
  strcpy(str,"hello");
  free(str);
  if(str!=NULL)
  {
  strcpy(str,"world");
  }
  printf("\n str is %s",str);
  getchar();
  }
  问输出结果是什么?
 
【解答】:输出str is world。
  free 只是释放的str指向的内存空间,它本身的值还是存在的.
  所以free之后,有一个好的习惯就是将str=NULL.
  此时str指向空间的内存已被回收,如果输出语句之前还存在分配空间的操作的话,这段存储空间是可能被重新分配给其他变量的,
  尽管这段程序确实是存在大大的问题(上面各位已经说得很清楚了),但是通常会打印出world来。
  这是因为,进程中的内存管理一般不是由操作系统完成的,而是由库函数自己完成的。
  当用malloc一块内存的时候,管理库向操作系统申请一块空间(可能会比你申请的大一些),然后在这块空间中记录一些管理信息(一般是在你申请的内存前面一点),并将可用内存的地址返回。但是释放内存的时候,管理库通常都不会将内存还给操作系统,因此你是可以继续访问这块地址的,
 6.
  #include "stdio.h"
  #include "string.h"
  void main()
  {
  char aa[10];
  printf("%d",strlen(aa));
}
运行的结果?

【解答】:
  sizeof()和是否初始化,没有关系;
  strlen()和初始化有关。
 7.
char (*str)[20];/*str是一个数组指针,即指向数组的指针.*/
  char *str[20];/*str是一个指针数组,其元素为指针型数据.*/
 8.long a=0x801010;
   a+5=?
  
【解答】:
0x801010用二进制表示为:“1000 0000 0001 0000 0001 0000”,十进制的值为8392720,再加上5就是8392725
 9.
给定结构struct A
  {
  char t:4;
  char k:4;
  unsigned short i:8;
  unsigned long m;
  };问sizeof(A) = ?
【解答】:  
struct A
  {
  char t:4; 4位
  char k:4; 4位
  unsigned short i:8; 8位
  unsigned long m; // 偏移2字节保证4字节对齐
  }; // 共8字节
10.下面的函数实现在一个数上加一个数,有什么错误?请改正。
  int add_n ( int n )
  {
  static int i = 100;
  i += n;
  return i;
  }
  
【解答】:当第二次调用时得不到正确的结果,问题就出在 static上。
11.求函数返回值,输入x=9999;
  int func ( x )
  {
  int countx = 0;
  while ( x )
  {
  countx ++;
  x = x&(x-1);
  }
  return countx;
  }
  结果呢?
 
【解答】: 
这是统计9999的二进制数值中有多少个1的函数,且有
  9999=9×1024+512+256+15
  9×1024中含有1的个数为2;
  512中含有1的个数为1;
  256中含有1的个数为1;
  15中含有1的个数为4;
  故共有1的个数为8,结果为8。
  1000 - 1 = 0111,正好是原数取反。这就是原理。
  用这种方法来求1的个数是很效率很高的。
  不必去一个一个地移位。循环次数最少。
 12. int a,b,c 请写函数实现c=a+b ,不可以改变数据类型,如将c改为long int,关键是如何处理溢出问题

 【解答】:
 bool add (int a, int b,int *c)
  {
  *c=a+b;
  return (a>0 && b>0 &&(*c<0 && b<0 &&(*c>a || *c>b)));
  }
  
13. 分析:
  struct bit
  { int a:3;
  int b:2;
  int c:3;
  };
  int main()
  {
  bit s;
  char *c=(char*)&s;
  cout<<< p>
  *c=0x99;
  cout << s.a <<<<<<>
  int a=-1;
  printf("%x",a);
  return 0;
  }
  输出为什么是
  4
  1
  -1
  -4
  ffffffff
  
【解答】:
因为0x99在内存中表示为 100 11 001 , a = 001, b = 11, c = 100
  当c为有符合数时, c = 100, 最高1为表示c为负数,负数在计算机用补码表示,所以c = -4;同理
  b = -1;
  当c为有符合数时, c = 100,即 c = 4,同理 b = 3
  位域 :
  有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态,用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域, 并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。一、位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:
  struct 位域结构名
  { 位域列表 };
  其中位域列表的形式为: 类型说明符 位域名:位域长度
  例如:
  struct bs
  {
  int a:8;
  int b:2;
  int c:6;
  };
  位域变量的说明与结构变量说明的方式相同。 可采用先定义后说明,同时定义说明或者直接说明这三种方式。例如:
  struct bs
  {
  int a:8;
  int b:2;
  int c:6;
  }data;
   




1、局部变量能否和全局变量重名? 
  答:能,局部会屏蔽全局。要用全局变量,需要使用 ":: " 
  局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内。
2、如何引用一个已经定义过的全局变量? 
  答:extern 
  可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变理,假定你将哪个变量写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。 
 
  3、全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么? 
  答:可以,在不同的C文件中以static形式来声明同名全局变量。 
  可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错 
 
  4、语句for(   ;1   ;)有什么问题?它是什么意思? 
  答:和while(1)相同。 
 
  5、do……while和while……do有什么区别? 
  答:前一个循环一遍再判断,后一个判断以后再循环 
 
  6、请写出下列代码的输出内容 
  #include  
  main() 
  { 
   int   a,b,c,d; 
   a=10; 
   b=a++; 
   c=++a; 
   d=10*a++; 
   printf( "b,c,d:%d,%d,%d ",b,c,d); 
   return   0; 
  }   
  
答:10,12,120 
 
  7、static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别? 
  全局变量(外部变量)的说明之前再冠以static   就构成了静态的全局变量。全局变量本身就是静态存储方式,   静态全局变量当然也是静态存储方式。   这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序,   当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。   而静态全局变量则限制了其作用域,   即只在定义该变量的源文件内有效,   在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,   因此可以避免在其它源文件中引起错误。 
  从以上分析可以看出,   把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,   限制了它的使用范围。 
  static函数与普通函数作用域不同。仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件 
  static全局变量与普通的全局变量有什么区别:static全局变量只初使化一次,防止在其他文件单元中被引用; 
  static局部变量和普通局部变量有什么区别:static局部变量只被初始化一次,下一次依据上一次结果值;
static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝

程序的局部变量存在于(堆栈)中,全局变量存在于(静态区   )中,动态申请数据存在于(   堆)中。 
  
9、设有以下说明和定义: 
  typedef   union   {long   i;   int   k[5];   char   c;}   DATE; 
  struct   data   {   int   cat;   DATE   cow;   double   dog;}   too; 
  DATE   max; 
  则语句   printf( "%d ",sizeof(struct   date)+sizeof(max));的执行结果是:___52____ 
  答:DATE是一个union,   变量公用空间.   里面最大的变量类型是int[5],   占用20个字节.   所以它的大小是20 
data是一个struct,   每个变量分开占用空间.   依次为int4   +   DATE20   +   double8   =   32. 
所以结果是   20   +   32   =   52. 
  当然...在某些16位编辑器下,   int可能是2字节,那么结果是   int2   +   DATE10   +   double8   =   20 
 
  10、队列和栈有什么区别?    
  队列先进先出,栈后进先出 
 
  11、写出下列代码的输出内容 
  #include  
  int   inc(int   a) 
  { 
   return(++a); 
  } 
  int   multi(int*a,int*b,int*c) 
  { 
   return(*c=*a**b); 
  } 
  typedef   int(FUNC1)(int   in); 
  typedef   int(FUNC2)   (int*,int*,int*); 
  
  void   show(FUNC2   fun,int   arg1,   int*arg2) 
  { 
   INCp=&inc; 
   int   temp   =p(arg1); 
   fun(&temp,&arg1,   arg2); 
   printf( "%d\n ",*arg2); 
  } 
  
  main() 
  { 
   int   a; 
   show(multi,10,&a); 
   return   0; 
  }  

   答:110 
 
  12、请找出下面代码中的所有错误 
  说明:以下代码是把一个字符串倒序,如“abcd”倒序后变为“dcba” 
  1、#include "string.h " 
  2、main() 
  3、{ 
  4、   char*src= "hello,world "; 
  5、   ch
ar* dest=NULL; 
  6、 int len=strlen(src); 
  7、 dest=(char*)malloc(len); 
  8、 char* d=dest; 
  9、 char* s=src[len]; 
  10、 while(len--!=0) 
  11、 d++=s--; 
  12、 printf( "%s ",dest); 
  13、 return 0; 
  14、} 
 

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

 
方法2: 
  #include  
  #include  
  main() 
  { 
   char str[]= "hello,world "; 
   int len=strlen(str); 
   char t; 
   for(int i=0; i    { 
    t=str[i]; 
    str[i]=str[len-i-1]; str[len-i-1]=t; 
   } 
   printf( "%s ",str); 
   return 0; 
  } 

  
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) 
  答案:63 
 
  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  
  #include  
  int main(void) 
  { 
   long l; 
   char *str = "98765432 "; 
   l = atol(lstr); 
   printf( "string = %s integer = %ld\n ", str, l); 
   return(0); 
  } 
 

 
  13.对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现? 
  c用宏定义,c++用inline 
 
   
  ?19. 
  enum string 
  { 
   x1, 
   x2, 
   x3=10, 
   x4, 
   x5, 
  }x; 
  问x= 0x801005,0x8010f4 ; 
 
  20. 
  unsigned char *p1; 
  unsigned long *p2; 
  p1=(unsigned char *)0x801000; 
  p2=(unsigned long *)0x810000; 
 
  请问p1+5= ; 
    p2+5= ; 
 
 
 
找错题: 
  25.请问下面程序有什么错误? 
  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; 
  把循环语句内外换一下 
 
  26. 
  #define Max_CB 500 
  void LmiQueryCSmd(Struct MSgCB * pmsg) 
  { 
   unsigned char ucCmdNum; 
   ...... 
   for(ucCmdNum=0;ucCmdNum    { 
    ......; 
   } 
   死循环 
 
  27.以下是求一个数的平方的程序,请找出错误: 
 
  #define SQUARE(a)((a)*(a)) 
  int a=5; 
  int b; 
  b=SQUARE(a++); 
 
  28. 
  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; 
   } 
   ....... 
  } 

 
嵌入式C语言16道试题
非常基本的C语言问题, 一个信息类(计算机,资讯工程,电子工程, 通信工程)专业的本科毕业生应该达到的水平。题目不难,全部都能快速地答完, 当然也需要一定的知识储备。对于大多数人, 我们预期你可能答错 3)   4)  15)题, 所以答错3道以内的, 我们认为你很棒。答错5道题以内, 我们认为你还不错(你还可能答错第9题)。如果你有6道以上的题目不能答对,基本上我们都不好说什么了....

约定:

1) 下面的测试题中, 认为所有必须的头文件都已经正确的包含了
2) 数据类型    
   char 一个字节 1 byte
   int 两个字节 2 byte (16位系统, 认为整型是2个字节)
   long int 四个字节 4 byte
   float  四个字节4 byet
   double 八个字节 8 byte
   long double 十个字节 10 byte
   pointer 两个字节 2 byte(注意, 16位系统, 地址总线只有16位)


第1题: 考查对volatile关键字的认识

#include

static jmp_buf buf;

main()   
{
    volatile  int b;
    b =3;
   
    if(setjmp(buf)!=0)
    {
        printf("%d ", b);
        exit(0);
    }
    b=5;
    longjmp(buf , 1);
}
请问, 这段程序的输出是
(a) 3
(b) 5
(c) 0
(d) 以上均不是

第1题:   (b)
volatile字面意思是易于挥发的。这个关键字来描述一个变量时, 意味着 给该变量赋值(写入)之后, 马上再读取, 写入的值与读取的值可能不一样,所以说它"容易挥发"的。
这是因为这个变量可能一个寄存器, 直接与外部设备相连, 你写入之后, 该寄存器也有可能被外部设备的写操作所改变;或者, 该变量被一个中断程序, 或另一个进程
改变了.
volatile 不会被编译器优化影响, 在longjump 后,它的值 是后面假定的变量值,b最后的值是5,所以5被打印出来.

第2题:考查类型转换

main()
{
   struct node
   {
       int a;
       int b;
       int c;    
   };
   struct node  s= { 3, 5,6 };
   struct node *pt = &s;
   printf("%d" ,  *(int*)pt);
}
这段程序的输出是:
(a) 3
(b) 5
(c) 6
(d) 7

第2题:   (a)
结构题的成员在内存中的地址是按照他们定义的位置顺序依次增长的。如果一个结构体的指针被看成 它的第一个成员的指针,那么该指针的确指向第一个成员

第3题:考查递归调用

int  foo ( int x , int  n) 
{
    int val;
    val =1;
   
    if (n>0)
    {
        if (n%2 == 1)  val = val *x;
        val = val * foo(x*x , n/2);
    }
    return val;
}
这段代码对x和n完成什么样的功能(操作)?
(a) x^n (x的n次幂)
(b) x*n(x与n的乘积)
(c) n^x(n的x次幂)
(d) 以上均不是



第3题:  (a)
此题目较难.

这个程序的非递归版本

int  what ( int x , int  n)
{
    int val;
    int product;
    product =1;
    val =x;
   
    while(n>0)
    {
        if (n%2 == 1)
        product = product*val;   /*如果是奇数次幂,  x(val)要先乘上一次,;   
                                         偶数次幂, 最后返回时才会到这里乘以1*/
        val = val* val;                  
        n = n/2;
    }
    return product;
}


/* 用二元复乘策略 */
算法描述
(while n>0) 
{
    if  next most significant binary digit of  n( power)  is one
    then multiply accumulated product by current val,
    reduce n(power)  sequence by a factor of two using integer division.
    get next val by multiply current value of itself                  
}

第4题:考查指针,这道题只适合于那些特别细心且对指针和数组有深入理解的人

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


这段程序的输出是:
(a) 2 2
(b) 2 1
(c) 2 5
(d) 以上均不是

第4题:  (c)
a的类型是一个整型数组,它有5个成员。&a的类型是一个整型数组的指针, 所以&a + 1指向的地方等同于a[6], 所以*(a+1) 等同于a[1]
ptr等同a[6], ptr-1就等同与a[5]

第5题:考查多维数组与指针

void foo(int [][3]);    

main()
{
    int a [3][3]= { { 1,2,3} , { 4,5,6},{7,8,9}};
    foo(a);
    printf("%d" , a[2][1]);
}

void foo(int b[][3])   
{
    ++ b;
    b[1][1] =9;
}


这段程序的输出是:
(a) 8
(b) 9
(c) 7
(d)以上均不对

第5题:  (b)

题目自身就给了足够的提示
b[0][0]  = 4
b[1][0]  = 7

第6题:考查逗号表达式

main()
{
    int a, b,c, d;
    a=3;
    b=5;
    c=a,b;
    d=(a,b);
   
    printf("c=%d" ,c);
    printf("d=%d" ,d);
}
这段程序的输出是:
(a) c=3 d=3
(b) c=5 d=3
(c) c=3 d=5
(d) c=5 d=5

第6题:  (c)
考查逗号表达式,逗号表达式的优先级是很低的, 比 赋值(=)的优先级 低. 逗号表达式的值就是最后一个元素的值
逗号表达式的还有一个作用就是分割函数的参数列表..
E1, E2, ..., En
上面这个表示式的左右是,E1, E2,... En的值被分别计算出来, En计算出来的结构赋给整个逗号表达式
c=a,b;       / *yields c=a* /
d=(a,b);    /* d =b  */


第7题:考查指针数组

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

    ++ptr;
    printf("%d %d" , (*ptr)[1], (*ptr)[2]);
}
这段程序的输出是:
(a) 2 3 5 6
(b) 2 3 4 5
(c) 4 5 0 0
(d) 以上均不对

第7题:  (a)
ptr是一个数组的指针, 该数组有3个int成员


第8题:考查函数指针

int *f1(void)
{
    int x =10;
    return(&x);
}

int *f2(void)
{
    int*ptr;
    *ptr =10;
    return ptr;
}

int *f3(void)
{
    int *ptr;
    ptr=(int*) malloc(sizeof(int));
    return ptr;
}

上面这3个函数哪一个最可能引起指针方面的问题
(a) 只有 f3
(b) 只有f1 and f3
(c) 只有f1 and f2
(d) f1 , f2 ,f3

第8题:  (c)
f1显然有问题, 它返回一个局部变量的指针, 局部变量是保存在stack中的,退出函数后, 局部变量就销毁了, 保留其指针没有意义, 因为其指向的stack空间可能被其他变量覆盖了
f2也有问题, ptr是局部变量, 未初始化, 它的值是未知的, *ptr不知道指向哪里了, 直接给*ptr赋值可能会覆盖重要的系统变量, 这就是通常说的野指针的一种

第9题:考查自加操作(++)

main()
{
    int i=3;
    int j;
   
    j = sizeof(++i+ ++i);
   
    printf("i=%d j=%d", i ,j);
}


这段程序的输出是:
(a) i=4 j=2
(b) i=3 j=2
(c) i=3 j=4
(d) i=3 j=6

第9题:  (b)
sizeof  操作符给出其操作数需要占用的空间大小, 它是在编译时就可确定的, 所以其操作数即使是一个表达式, 也不需要在运行时进行计算.( ++i + ++ i )是不会执行的, 所以i的值还是3

第10题:考查形式参数, 实际参数, 指针和数组

void f1(int *, int);
void f2(int *, int);
void(*p[2]) (int *, int);

main()
{
    int a;
    int b;
   
    p[0] = f1;
    p[1] = f2;
    a=3;
    b=5;
   
    p[0](&a, b);
    printf("%d\t %d\t", a, b);

    p[1](&a, b);
    printf("%d\t %d\t", a, b);
}

void f1(int* p , int q)
{
    int tmp;
    tmp =*p;
    *p = q;
    q= tmp;
}

void f2(int* p , int q)
{
    int tmp;
    tmp =*p;
    *p = q;
    q= tmp;



这段程序的输出是:
(a) 5 5 5 5
(b) 3 5 3 5
(c) 5 3 5 3
(d) 3 3 3 3

第10题:  (a)
很显然选a.
f1交换*p 和 q的值, f1执行完后, *p 和 q的值的确交换了,  但q的改变不会影响到b的改变,  *p 实际上就是a
所以执行f1后,  a=b=5
这道题考查的知识范围很广,包括typedef自定义类型,函数指针,指针数组void(*p[ 2 ]) ( int *, int);
定义了一个函数指针的数组p,p有两个指针元素. 元素是函数的指针, 函数指针指向的函数是一个带2个参数,返回void的函数, 所带的两个参数是指向整型的指针, 和整型
p[ 0 ] = f1; p[ 1 ] = f2 contain address of function .function name without parenthesis represent address of function Value and address of variable is passed to function only argument that is effected is a (address is passed). Because of call by value f1, f2 can not effect b

第11题:考查自减操作(--)

void e(int );   

main()
{
    int a;
    a=3;
    e(a);
}

void e(int n)
{
    if(n>0)
    {
        e(--n);
        printf("%d", n);
        e(--n);
    }
}
这段程序的输出是:
(a) 0 1 2 0
(b) 0 1 2 1
(c) 1 2 0 1
(d) 0 2 1 1

第11题:  (a)
考查--操作和递归调用,仔细分析一下就可以了



第12题:考查typedef类型定义,函数指针
typedef int (*test) ( float * , float*)
test tmp;

tmp 的类型是
(a) 函数的指针, 该函数以两个指向浮点数(float)的指针(pointer)作为参数(arguments)
    Pointer to function of having two arguments that is pointer to float
(b) 整型
(c) 函数的指针, 该函数以两个指向浮点数(float)的指针(pointer)作为参数(arguments),并且函数的返回值类型是整型
    Pointer to function having two argument that is pointer to float and return int
(d) 以上都不是

第12题:  (c)
建议不会的看看C专家编程
从左往有, 遇到括号停下来, 将第一个括号里的东西看成一个整体

第13题:数组与指针的区别与联系

main()
{
    char p;
    char buf[10] ={ 1,2,3,4,5,6,9,8};
    p = (buf+1)[5];
    printf("%d" , p);
}
这段程序的输出是:
(a) 5
(b) 6
(c) 9
(d) 以上都不对

第13题:  (c)
考查什么时候数组就是指针.对某些类型T而言, 如果一个表达式是 T[]  (T的数组),  这个表达式的值实际上就是指向该数组的第一个元素的指针.所以(buf+1)[5]实际上就是*(buf +6)或者buf[6]

第14题: 考查指针数组的指针

void f(char**);

main()
{
    char * argv[] = { "ab" ,"cd" , "ef" ,"gh", "ij" ,"kl" };
    f( argv );
}

void f( char **p )
{
    char* t;
   
    t= (p+= sizeof(int))[-1];
   
    printf( "%s" , t);
}
这段程序的输出是:
(a) ab
(b) cd
(c) ef
(d) gh

第14题:  (b)

sizeof(int)的值是2,所以p+=sizeof(int) 指向 argv[2],这点估计大家都没有什么疑问

(p+=sizeof(int))[-1] 指向 argv[1],能理解吗, 因为(p+=sizeof(int))[-1]  就相当于 (p+=2)[-1] ,也就是(p+2-1)

第15题:此题考查的是C的变长参数,就像标准函数库里printf()那样,这个话题一般国内大学课堂是不会讲到的,不会情有可原

#include
int ripple ( int , );

main()
{
    int num;
    num = ripple ( 3, 5,7);
    printf( " %d" , num);
}

int ripple (int n, )
{
    int i , j;
    int k; 
    va_list p;
   
    k= 0;
    j = 1;
    va_start(p, n);
   
    for (; j    {
        i =  va_arg(p , int);
        for (; i; i &=i-1 )
            ++k;
    }
    return k;
}


这段程序的输出是:

(a) 7
(b) 6
(c) 5
(d) 3

第15题:  (c)
在C编译器通常提供了一系列处理可变参数的宏, 以屏蔽不同的硬件平台造成的差异, 增加程序的可移植性。这些宏包括va_start、va_arg和va_end等。
采用ANSI标准形式时, 参数个数可变的函数的原型声明是:type funcname(type para1, type para2, ...)
这种形式至少需要一个普通的形式参数, 后面的省略号不表示省略, 而是函数原型的一部分。type是函数返回值和形式参数的类型。
不同的编译器, 对这个可变长参数的实现不一样 , gcc4.x中是内置函数.
关于可变长参数,可参阅


程序分析
va_list p;  /*定义一个变量 ,保存  函数参数列表 的指针*/
va_start( p , n);     /*用va_start宏 初始化变量p, va_start宏的第2个参数n, 是一个固定的参数, 必须是我们自己定义的
                        变长函数的最后一个入栈的参数也就是调用的时候参数列表里的第1个参数*/
for (; j{
    i =  va_arg( p , int);      /*va_arg取出当前的参数,并认为取出的参数是一个整数(int)  */
    for (; i;    i &=i-1  )     /*判断取出的i是否为0*/
      ++k;                      /* 如果i不为0, k自加, i与i-1进行与逻辑运算, 直到i 为0
                                   这是一个技巧, 下面会谈到它的功能*/
}


当我们调用ripple函数时, 传递给ripple函数的 参数列表的第一个参数n的值是3. va_start 初始化p士气指向第一个未命名的参数(n是有名字的参数) ,也就是 is 5 (第一个). 每次对 va_arg的调用, 都将返回一个参数, 并且把 p 指向下一个参数. va_arg 用一个类型名来决定返回的参数是何种类型,以及在 var_arg的内部实现中决定移动多大的距离才到达下一个参数
(; i; i&=i-1) k++        /* 计算i有多少bit被置1 */

5用二进制表示是 (101) 2
7用二进制表示 (111) 3
所以 k 返回 5(2+3),也即本题应该选c

举个例子, 就很好理解了
令  i= 9 = 1001
    i-1  = 1000       
    (i-1) +1 = i
    1000
      +1
    1001
因为i与i-1的最右边的那位(最低位) 肯定是不同, 如果i1,i-1肯定是0, 反之亦然. i & i-1 这个运算, 在二相补的数字系统中, 将会消除最右边的1位

第16题:考查静态变量的知识
int counter (int i)
{
    static int count =0;
    count = count +i;
    return (count );
}
main()
{
    int i , j;
   
    for (i=0; i <=5; i++)
        j = counter(i);
}
本程序执行到最后,j的值是:
(a) 10
(b) 15
(c) 6
(d) 7


第16题:  (b)
答案是 (b)
相传高斯小学一年级的时候就会做这类等比数列的题目了.这道题考查的是静态变量的知识,当每次调用完函数之后,静态变量的值不会丢失,这与栈中的临时局部变量明显不同的地方.
所以,第一次调用counter(0)之后,count =0
第二次调用 counter(1)后 count = 0+1;
第三次调用 counter(2) count = 1+2;    /* count = count +i */
第四次调用 counter(3) count = 3+3;
第五次调用 counter(4) count = 6+4;
第六次调用 counter(5) count = 10+5;

1.写出判断ABCD四个表达式的是否正确, 若正确, 写出经过表达式中 a的值(3分)
int a = 4;
(A)a += (a++); (B) a += (++a) ;(C) (a++) += a;(D) (++a) += (a++);
a = ?

答:C错误,左侧不是一个有效变量,不能赋值,可改为(++a) += a;
改后答案依次为9,10,10,11

2.某32位系统下, C++程序,请计算sizeof 的值(5分).
char str[] = “”
char *p = str ;
int n = 10;
请计算
sizeof (str ) = ?(1)
sizeof ( p ) = ?(2)
sizeof ( n ) = ?(3)
void Foo ( char str[100]){
请计算
sizeof( str ) = ?(4)
}
void *p = malloc( 100 );
请计算
sizeof ( p ) = ?(5)

答:(1)17 (2)4 (3) 4 (4)4 (5)4

3. 回答下面的问题. (4分)
(1).头文件中的 ifndef/define/endif 干什么用?预处理
答:防止头文件被重复引用
(2). #include 和 #include “filename.h” 有什么区别?
答:前者用来包含开发环境提供的库头文件,后者用来包含自己编写的头文件。
(3).在C++ 程序中调用被 C 编译器编译后的函数,为什么要加 extern “C”声明?
答:函数和变量被C++编译后在符号库中的名字与C语言的不同,被extern "C"修饰的变量和函数是按照C语言方式编译和连接的。由于编译后的名字不同,C++程序不能直接调用C 函数。C++提供了一个C 连接交换指定符号extern“C”来解决这个问题。
(4). switch()中不允许的数据类型是?
答:实型

4. 回答下面的问题(6分)
(1).

Void GetMemory(char **p, int num){
*p = (char *)malloc(num);
}
void Test(void){
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}
请问运行Test 函数会有什么样的结果?
答:输出“hello”
(2).

void Test(void){
char *str = (char *) malloc(100);
strcpy(str, “hello”);
free(str);
if(str != NULL){
strcpy(str, “world”);
printf(str);
}
}
请问运行Test 函数会有什么样的结果?
答:输出“world”,因为free(str)后并未改变str所指的内存内容。
(3).

char *GetMemory(void){
char p[] = "hello world";
return p;
}
void Test(void){
char *str = NULL;
str = GetMemory();
printf(str);
}
请问运行Test 函数会有什么样的结果?
答:无效的指针,输出不确定

5. 编写strcat函数(6分)
已知strcat函数的原型是char *strcat (char *strDest, const char *strSrc);
其中strDest 是目的字符串,strSrc 是源字符串。
(1)不调用C++/C 的字符串库函数,请编写函数 strcat
答:
VC源码:

char * __cdecl strcat (char * dst, const char * src)
{
char * cp = dst;
while( *cp )
cp++; /* find end of dst */
while( *cp++ = *src++ ) ; /* Copy src to end of dst */
return( dst ); /* return dst */
}
(2)strcat能把strSrc 的内容连接到strDest,为什么还要char * 类型的返回值?
答:方便赋值给其他变量


1、用指针的方法,将字符串“ABCD1234efgh”前后对调显示
  #include
  #include
  #include
  int main()
  {
  char str[] = "ABCD1234efgh";
  int length = strlen(str);
  char * p1 = str;
  char * p2 = str + length - 1;
  while(p1 < p2)
  {
  char c = *p1;
  *p1 = *p2;
  *p2 = c;
  ++p1;
  --p2;
  }
  printf("str now is %s\n",str);
  system("pause");
  return 0;
  }
  2、有一分数序列:1/2,1/4,1/6,1/8……,用函数调用的方法,求此数列前20项的和
  #include
  double getValue()
  {
  double result = 0;
  int i = 2;
  while(i < 42)
  {
  result += 1.0 / i;//一定要使用1.0做除数,不能用1,否则结果将自动转化成整数,即0.000000
  i += 2;
  }
  return result;
  }
  int main()
  {
  printf("result is %f\n", getValue());
  system("pause");
  return 0;
  }
 

  有一个数组a[1000]存放0--1000;要求每隔二个数删掉一个数,到末尾时循环至开头继续进行,求最后一个被删掉的数的原始下标位置。
  以7个数为例:
  {0,1,2,3,4,5,6,7} 0-->1-->2(删除)-->3-->4-->5(删除)-->6-->7-->0(删除),如此循环直到最后一个数被删除。
  方法1:数组
  #include
  using namespace std;
  #define null 1000
  int main()
  {
  int arr[1000];
  for (int i=0;i<1000;++i)
  arr[i]=i;
  int j=0;
  int count=0;
  while(count<999)
  {
  while(arr[j%1000]==null)
  j=(++j)%1000;
  j=(++j)%1000;
  while(arr[j%1000]==null)
  j=(++j)%1000;
  j=(++j)%1000;
  while(arr[j%1000]==null)
  j=(++j)%1000;
  arr[j]=null;
  ++count;
  }
  while(arr[j]==null)
  j=(++j)%1000;
  cout<<< p>
  return 0;
  }方法2:链表
  #include
  using namespace std;
  #define null 0
  struct node
  {
  int data;
  node* next;
  };
  int main()
  {
  node* head=new node;
  head->data=0;
  head->next=null;
  node* p=head;
  for(int i=1;i<1000;i++)
  {
  node* tmp=new node;
  tmp->data=i;
  tmp->next=null;
  head->next=tmp;
  head=head->next;
  }
  head->next=p;
  while(p!=p->next)
  {
  p->next->next=p->next->next->next;
  p=p->next->next;
  }
  cout  return 0;
  }
  方法3:通用算法
  #include
  #define MAXLINE 1000 //元素个数
  /*
  MAXLINE 元素个数
  a[] 元素数组
  R[] 指针场
  suffix 下标
  index 返回最后的下标序号
  values 返回最后的下标对应的值
  start 从第几个开始
  K 间隔
  */
  int find_n(int a[],int R[],int K,int& index,int& values,int s=0) {
  int suffix;
  int front_node,current_node;
  suffix=0;
  if(s==0) {
  current_node=0;
  front_node=MAXLINE-1;
  }
  else {
  current_node=s;
  front_node=s-1;
  }
  while(R[front_node]!=front_node) {
  printf("%d\n",a[current_node]);
  R[front_node]=R[current_node];
  if(K==1) {
  current_node=R[front_node];
  continue;
  }
  for(int i=0;i< p>
  front_node=R[front_node];
  }
  current_node=R[front_node];
  }
  index=front_node;
  values=a[front_node];
  return 0;
  }
  int main(void) {
  int a[MAXLINE],R[MAXLINE],suffix,index,values,start,i,K;
  suffix=index=values=start=0;
  K=2;
  for(i=0;i<>
  a[i]=i;
  R[i]=i+1;
  }
  R[i-1]=0;
  find_n(a,R,K,index,values,2);
  printf("the value is %d,%d\n",index,values);
  return 0;
  }
  试题:
  void test2()
  {
  char string[10], str1[10];
  int i;
  for(i=0; i<10; i++)
  {
  str1[i] = 'a';
  }
  strcpy( string, str1 );
  }
  解答:对试题2,如果面试者指出字符数组str1不能在数组内结束可以给3分;如果面试者指出strcpy(string, str1)调用使得从str1内存起复制到string内存起所复制的字节数具有不确定性可以给7分,在此基础上指出库函数strcpy工作方式的给10 分;
  str1不能在数组内结束:因为str1的存储为:{a,a,a,a,a,a,a,a,a,a},没有'\0'(字符串结束符),所以不能结束
  strcpy( char *s1,char *s2)他的工作原理是,扫描s2指向的内存,逐个字符付到s1所指向的内存,直到碰到'\0',因为str1结尾没有'\0',所以具有不确定性,不知道他后面还会付什么东东。
  正确应如下
  void test2()
  {
  char string[10], str1[10];
  int i;
  for(i=0; i<9; i++)
  {
  str1[i] = 'a'+i; //把abcdefghi赋值给字符数组
  }
  str[i]='\0';//加上结束符
  strcpy( string, str1 );
  }
  第二个code题是实现strcmp
  int StrCmp(const char *str1, const char *str2)
  做是做对了,没有抄搞,比较乱
  int StrCmp(const char *str1, const char *str2)
  {
  assert(str1 && srt2);
  while (*str1 && *str2 && *str1 == *str2) {
  str1++, str2++;
  }
  if (*str1 && *str2)
  return (*str1-*str2);
  elseif (*str1 && *str2==0)
  return 1;
  elseif (*str1 = = 0 && *str2)
  return -1;
  else
  return 0;
  }
  int StrCmp(const char *str1, const char *str2)
  {
  //省略判断空指针(自己保证)
  while(*str1 && *str1++ = = *str2++);
  return *str1-*str2;
  }
  第三个code题是实现子串定位
  int FindSubStr(const char *MainStr, const char *SubStr)
  做是做对了,没有抄搞,比较乱
  int MyStrstr(const char* MainStr, const char* SubStr)
  {
  const char *p;
  const char *q;
  const char * u = MainStr;
  //assert((MainStr!=NULL)&&( SubStr!=NULL));//用断言对输入进行判断
  while(*MainStr) //内部进行递增
  {
  p = MainStr;
  q = SubStr;
  while(*q && *p && *p++ == *q++);
  if(!*q )
  {
  return MainStr - u +1 ;//MainStr指向当前起始位,u指向
  }
  MainStr ++;
  }
  return -1;
  }
  分析:
  int arr[] = {6,7,8,9,10};
  int *ptr = arr;
  *(ptr++)+=123;
  printf(“ %d %d ”, *ptr, *(++ptr));
  输出:8 8
  过程:对于*(ptr++)+=123;先做加法6+123,然后++,指针指向7;对于printf(“ %d %d ”, *ptr, *(++ptr));从后往前执行,指针先++,指向8,然后输出8,紧接着再输出8


一、判断题(对的写T,错的写F并说明原因,每小题4分,共20分)
1、有数组定义int a[2][2]={{1},{2,3}};则a[0][1]的值为0。(     )
2、int (*ptr) (),则ptr是一维数组的名字。(     )
3、指针在任何情况下都可进行>, <, >=, <=, = =运算。(     )
4、switch(c) 语句中c可以是int, long, char, float, unsigned int 类型。(   )
5、#define print(x)  printf("the no, "#x",is ")
二、填空题(共30分)
1、在windows下,写出运行结果,每空2分,共10分。
char str[ ]= "Hello";
char *p=str;
int n=10;
sizeof(str)=(      )
sizeof(p)=(       )
sizeof(n)=(       )
void func(char str[100])
{    }
sizeof(str)=(     )
2、void setmemory(char **p, int num)
{ *p=(char *) malloc(num);}
void test(void)
{  char *str=NULL;
   getmemory(&str,100);
   strcpy(str,"hello");
   printf(str);
}
运行test函数有什么结果?(                                )10分
3、设int arr[]={6,7,8,9,10};
     int *ptr=arr;
   *(ptr++)+=123;
 printf("%d,%d",*ptr,*(++ptr));
(                                   ) 10分
二、编程题(第一小题20,第二小题30分)
1、  不使用库函数,编写函数int strcmp(char  *source, char *dest)
 相等返回0,不等返回-1;
2、  写一函数int fun(char *p)判断一字符串是否为回文,是返回1,
不是返回0,出错返回-1;
不使用库函数,编写函数int strcmp(char *source, char *dest) 相等返回0,不等返回-1

#include
#include

int strcmp(char *source, char *dest)
{
assert(*source != NULL);
assert(*dest!= NULL);

while (1)
{
if ((*source++ == *dest++) != '\0')
{
return 0;
}
else
{
return -1
}
}

}

int main()
{
char source[128];
char dest[128];

//获取字符串省略;

printf("source = dest", strcmp(source, dest));
return 0;
}

  回复  引用    
#6楼 2008-09-02 10:34 23u4ou[未注册用户]
while(*source++ != *dest++)
return 0;
return 1;   回复  引用    
#7楼 2008-11-07 20:15 hellofadf[未注册用户]
int strcmp(char *source, char *dest)
{
while((*source != '\0') && (*dest != '\0'))
{
if (*source == *dest)
{
source++;
dest++;
}
else
{
return -1;
}
}
if ((*source == '\0') && (*dest == '\0'))
{
ruturn 0;
}
else
{
return -1;
}
}

 
阅读(1354) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~