C语言最好的10道题

编者:对于大多数人,我们预期你可能答错 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 <setjmp.h> 
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被打印出来. 
setjmp : 设置非局部跳转 /* setjmp.h*/ 
Lonjjmp: 执行一个非局部跳转 /* setjmp.h*/ 
Note: Test program without volatile qualifier (result may very) 
更详细介绍,请参阅 C语言的setjmp和longjmp 

第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要先乘上一次,; 偶数次幂,最后                            返回时才会到这里乘以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赋值可能会覆盖重要的系统变量,这就是通常说的野指针的一种. 
f3函数的目的,是取得分配空间的起始地址,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 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 

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

第11题:考查typedef类型定义,函数指针 

typedef int (*test) ( float * , float*) 
test tmp; 

tmp 的类型是 

(a) 函数的指针,该函数以两个指向浮点数(float)的指针(pointer)作为参数

(b) 整型 

(c) 函数的指针,该函数以两个指向浮点数(float)的指针(pointer)作为参数(arguments),并且函数的返回值类型是整型 

(d) 以上都不是 

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


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

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 

第12题: (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) 

第13题:此题考查的是C的变长参数

#include <stdarg.h> 
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 <n; ++j) 
  { 
  i = va_arg( p , int); 
  for (; i; i &=i-1 ) 
  ++k; 
  } 
  return k; 

这段程序的输出是: 

(a) 7 

(b) 6 

(c) 5 

(d) 3 

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

关于可变长参数,可参阅 

http://www.upsdn.net/html/2004-11/26.html 

http://www.upsdn.net/html/2004-11/24.html 


程序分析 

va_list p; /*定义一个变量 ,保存 函数参数列表 的指针*/ 
va_start( p , n); /*用va_start宏 初始化 变量p,va_start宏的第2个参数n , 是一个固定的参数, 必须是我们自己定义的变长函数的最后一个入栈的参数,也就是调用的时候参数列表里的第1个参数*/ 
for (; j <n; ++j) /* j从1开始, 遍历所有可变参数 */ 

  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 
  1 001 
因为i与i-1的最右边的那位(最低位) 肯定是不同,如果i1,i-1肯定是0,反之亦然. i & i-1 这个运算,在二相补的数字系统中,将会消除最右边的1位 


命题人信息:

Ashok K. Pathak a member ( Research Staff ) at Bharat Electronics Limited (CRL) , Ghaziabad. He has been developing embedded application for the past five years .Ashok holds a M.E in computer science and engineering . Ashok recently completed a book about' "Advanced Test in C and Embedded System Programming" , Published by BPB , ND .

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值