C语言之字符串

来源:互联网 发布:北风网php 百度云 编辑:程序博客网 时间:2024/04/30 14:51

这讲我将带大家一起看看C语言面试的基本题型

面试例题1: What does the following program print?

#include <iostream>using namespace std;int main(){    int x=2,y,z;    x *=(y=z=5); cout << x << endl;    z=3;    x ==(y=z);    x =(y==z); cout << x << endl;    x =(y&z);  cout << x << endl;    x =(y&&z); cout << x << endl;    y=4;    x=(y|z);   cout << x << endl;    x=(y||z);  cout << x << endl;   return 0;}

解析:x *=(y=z=5)的意思是说 5 赋值给 z,z 再赋值给 y,x=x*y,所以 x 为 2*5=10。x ==(y=z)的意思是说 z 赋值给 y,然后看 x 和 y 相等否?不管相等不相等,x 并未发生变化,仍然是 10。x =(y==z)的意思是说首先看 y 和 z 相等否,相等则返回一个布尔值 1,不等则返回一个布尔值 0。现在 y 和 z 是相等的,都是 3,所以返回的布尔值是 1,再把 1 赋值给 x,所以 x 是 1。x =(y&z)的意思是说首先使 y 和 z 按位与。y 是 3,z 也是 3。y 的二进制数位是 0011,z的二进制数位也是 0011。按位与的结果如下表所示。

                         

所以 y&z 的二进制数位仍然是 0011,也就是还是 3。再赋值给 x,所以 x 为 3。x =(y&&z) 的意思是说首先使 y 和 z 进行与运算。与运算是指如果 y 为真,z 为真,则(y&&z)为真,返回一个布尔值 1。这时 y、z 都是 3,所以为真,返回 1,所以 x 为 1。x =(y|z) 的意思是说首先使 y 和 z 按位或。y 是 4,z 是 3。y 的二进制数位是 0100,z的二进制数位是 0011。与的结果如下表所示。

                             

所以 y&z 的二进制数位是 0111,也就是 7。再赋值给 x,所以 x 为 7。x =(y||z) 的意思是说首先使 y 和 z 进行或运算。或运算是指如果 y 和 z 中有一个为真,则(y||z)为真,返回一个布尔值 1。这时 y、z 都是真,所以为真,返回 1。所以 x 为 1。

答案:10,10,1,3,1,7。


面试例题 2:以下代码结果是多少?

#include <iostream>using namespace std;int func(int x){     int count = 0;     while(x)     {           count ++;           x=x&(x-1);           return count;    }}int main(){     cout << func(9999) << endl;     return 0;}

A. 8       B. 9        C. 10         D. 11

解析:本题 func 函数返回值是形参 x 转化成二进制后包含 1 的数量。理解这一点就很容易答出来了。9999 转化为二进制是:
         9999:10011100001111
答案:A

面试例题 3:下面两段代码的输出结果有什么不同?

第 1 段:

#include<iostream>using namespace std;int main(){       int a,x;       for(a =0 ,x =0; a<=1&&!x++;a++)        {                     a++;         }       cout<<a<<x<<endl;       return  0;}
第 2 段:

#include<iostream>using namespace std;int main(){    int a,x;    for(a=0,x=0;a<=1 &&!x++;)    {         a++;    }   cout<<a<<x<<endl;    return 0;}
解析:这两段代码的不同点就在 for 循环那里,前者是 for(a=0,x=0; a<=1 &&!x++;a++),后者是 for(a=0,x=0;a<=1 &&!x++;)。
先说第 1 段代码。
第 1 步:初始化定义 a=0,x=0。
第 2 步:a 小于等于 1,x 的非为 1,符合循环条件。
第 3 步:x++后 x 自增为 1。
第 4 步:进入循环体,a++,a 自增为 1。
第 5 步:执行 for(a=0,x=0;a<=1 &&!x++;a++)中的 a++,a 自增为 2。
第 6 步:a 现在是 2,已经不符合小于等于 1 的条件了,所以“&&”后面的“!x++”不执行,x 还是 1,不执行循环体。
第 7 步:打印 a 和 b,分别是 2 和 1。


再说第 2 段代码。
第 1 步:初始化定义 a=0,x=0。
第 2 步:a 小于等于 1,x 的非为 1,符合循环条件。

第 3 步:x++后 x 自增为 1。
第 4 步:进入循环体,a++,a 自增为 1。
第 5 步:a 现在是 1,符合小于等于 1 的条件,所以“&&”后面的“!x++”被执行,x 现在是1,x 的非为 0,不符合循环条件,不执行循环体,但 x++依然执行,自增为 2。
第 6 步:打印 a 和 b,分别是 1 和 2。


答案:第一段输出结果是 21,第二段输出结果是 12。


面试例题 4:What will be the output of the following C code?

#include <stdio.h>int main(){    int  b=3;    int arr[]={6,7,8,9,10};    int *ptr=arr; *(ptr++)+=123;     printf( "%d,%d\n ",*ptr,*(++ptr));    return 0;}

A.8 8        B.130 8              C.7 7                 D.7 8

解析:C 中 printf 计算参数时是从右到左压栈的。几个输出结果分别如下:printf( "%d\n ",*ptr);//此时 ptr 应指向第一个元素 6。*(ptr++)+=123 应为*ptr=*ptr+123;ptr++,//此时 ptr 应指向第二个元素 7。printf( "%d\n ",*(ptr-1));//此时输出第一个元素 129,注意此时是经过计算的。printf( "%d\n ",*ptr);//此时输出第二个元素 7,此时 ptr 还是指向第二个元素 7

printf( "%d,%d\n ",*ptr,*(++ptr)); 从右到左运算,第一个是(++ptr),也就是 ptr++, *ptr=8,此时 ptr 指向第三个元素 8,所以全部为 8。

答案:A

 编程风格面试例题5:We have two pieces of code , which one do you prefer, and tell why?

A.// a is a variable写法 1:if( 'A'==a ) {a++;}写法 2:if( a=='A' ) {a++;}

B.写法 1:for(i=0;i<8;i++) {X= i+Y+J*7;printf("%d",x);}写法 2:S= Y+J*7;for(i=0;i<8;i++) {printf("%d",i+S);}

答案:

     A.第一种写法'A'==a 比较好一些。这时如果把“==”误写做“=”的话,因为编译器不允许对常量赋值,就可以检查到错误。     B.第二种写法好一些,将部分加法运算放到了循环体外,提高了效率。缺点是程序不够简洁。

类型转换面试例题 6:下面程序的结果是多少?

#include <iostream>#include <stdio.h>#include <string.h>#include <conio.h>using namespace std;int main(){     float a = 1.0f;     cout << (int)a << endl;     cout << &a << endl;     cout << (int&)a << endl;     cout << boolalpha << ( (int)a == (int&)a )          << endl;//输出什么?    float b = 0.0f;    cout << (int)b << endl;    cout << &b << endl;    cout << (int&)b << endl;   cout << boolalpha << ( (int)b == (int&)b )       << endl;//输出什么?   return 0;}
解析:在机器上运行一下,可以得到结果,“cout << (int&)a << endl;”输出的是 1065353216,而不是 1。这是因为浮点数在内存里和整数的存储方式不同,(int&)a 相当于将该浮点数地址开始的 sizeof(int)个字节当成 int 型的数据输出,因此这取决于 float 型数据在内存中的存储方式,而不是经过(int&)a 显示转换的结果(1)。因为 float a = 1.0f 在内存中的表示都是 3f800000,而浮点数和一般整型不一样,所以当(int&)a 强制转换时,会把内存值 3f8000000 当做 int 型输出,所以结果自然变为了 1065353216(0x3f800000 的十进制表示)。

答案:false true 或者 0 1。

面试例题 7:下面程序的结果是多少?


#include <stdio.h>int main(){        unsigned int a = 0xFFFFFFF7;        unsigned char i = (unsigned char)a;        char* b = (char*)&a;        printf("%08x, %08x", i,*b);         retun 0;}
解析:unsigned int 变量赋值给 unsigned char 变量时会发生字节截断(3 位和高于 3 位的将被程序自动丢弃)。
那么第二个数,也就是 char* b = (char*)&a 中 a 本身为一个 uint 类型的值,把它的地址赋给一个执行 char 类型数据的指针。 char 类型的长度只有一个字节,打印 char 类型的指针指向的值会是多少?
&a 的结果是一个指针,它的类型取决于 a 的类型,此处&a 的类型应该是:
  unsigned int * ;
  char *b = (char *)&a ;
上面等价于:
  unsigned int *p = &a;//p 中的内容是 a 的地址,即 p 指向 a

char *b = (char *)p;//此处的强制转换只是使 b 也指向 a 而已
上面的步骤就是将一个 unsigned int 型的指针强制转换成一个 char 型的指针。
所以请注意:这里是 char 类型的指针转换,而不是 char 类型的转换。
这样转换后,假设 a 的地址是 x:
p + 1 = x + 1*sizeof(int) = x + 1* 4 = x + 4;
b + 1 = x + 1*sizeof(char) = x + 1* 1 = x + 1;
影响的是指针的寻址。


答案:000000f7,fffffff7。 

     

运算符问题
面例题8:下面程序的结果是多少?

#include <iostream>using namespace std;int  main(){     unsigned char a=0xA5;     unsigned char b=~a>>4+1;     //cout <<b;      printf("b=%d\n",b);      return 0;}
A.245            B.246            C.250            D.2

解析:这道题目考查两个知识点:一是类型转换问题;二是算符的优先级问题。


对于第一个问题:unsigned char b=~a>> 4,在计算这个表达式的时候,编译器会先把 a和 4 的值转换为 int 类型(即所谓整数提升)后再进行计算,当计算结果出来后,再把结果转换成 unsigned char 赋值给 b。
对于第二个问题:因为“~”的优先级高于“>>”和“+”,本题的过程是这样的:先对于 1010 0101取反 0101 1010;再右移,这里有一个问题,是先右移 4 位再加 1 呢,还是直接右移 5(4+1)位。因为“+”的优先级高于“>>”,所以直接右移 5 位。结果是 0000 0010。
最后的结果应该是 2 才对,但把如上的指令放到 vs2008 中运行,答案居然是 250。
那么到底是什么地方出了问题?在调试的过程中进入汇编指令。可以看到高级语句转换为汇编语言以后,是先执行取反再位移的。我们看到 eax 是 16 位的寄存器,于是在机器中0xA5 的寄存中表达是 0000 0000 1010 0101 ,取反是 1111 1111 0101 1010,那么右移 5 位是0000 0111 1111 1010,由于是 unsigned char 型的只能表示低 8 位的数值,即 250。


答案:C

 面试例题 9:用一个表达式,判断一个数 X 是否是 2 N 次方(2,4,8,16,...),不可用循环语句  

解析:2、4、8、16 这样的数转化成二进制是 10、100、1000、10000。如果 X 减 1 后与X 做与运算,答案若是 0,则 X 是 2 N 次方。

答案:!(X&(X-1))


面试例题 10:下面代码:
int f(int x, int y)
{
       return(x&y)+((x^y)>>1)
}
(729,271)=______

解析:这道题如果使用笨办法来求解,就都转化成二进制然后按位与。但这样的做法显然不是面试官所期待的。仔细观察一下题目,x&y 是取相同的位与,这个的结果是 x 和 y 相同位的一半,x^y 是取 x 和 y 的不同位,右移相当于除以 2,所以这个函数的功能是取两个数的平均值。(729+271)/2=500。
答案:50


面试例题 11:利用位运算实现两个整数的加法运算,请用代码实现

int Add(int a,int b){      if(b == 0) return a;//没有进位的时候完成运算     int sum,carry;     sum = a ^ b;//完成第一步没有进位的加法运算     carry=(a & b) << 1;//完成第二步进位并且左移运算     return Add(sum,carry);//进行递归,相加}

面试例题 12:There are two int variables: a and b, don’t use “if”, “? :”, “switch” or other judgement statements, find out the biggest one of the two numbers.

答案:方案一:
                  int max = ((a+b)+abs(a-b)) / 2

       方案二:

                 int c = a -b;
                 char *strs[2] = {"a Large ","b Large "};
                 c = unsigned(c) >> (sizeof(int) * 8 - 1);


面试例题 13:给三个整数 a、b、c,函数实现取三个数的中间数,不可以使用 sort,整数操作尽可能少。


答案:代码如下:

inline int max(int a, int b) {return a>=b? a:b;}inline int min(int a, int b) {return a<=b? a:b;}inline int medium(int a, int b, int c){    int t1 = max(a,b);    int t2 = max(b,c);    int t3 = max(a,c);    return min(t1, min(t2,t3));}


0 0
原创粉丝点击