面试宝典5,6,7--程序设计基本概念;预处理、const与sizeof;指针与引用

http://blog.csdn.net/winglet/article/details/2831605

1.What will be the output of the following C code?

#include <stdio.h>

int main()
{
    int arr[]={6,7,8,9,10};
    int *ptr=arr;
    *(ptr++)+=123;
    printf("%d, %d\n",*ptr,*(++ptr));
    
    return 0;
}
答案是:8,8

解析:*(ptr++)+=123的操作为*ptr=*ptr+123;ptr++,此时ptr指向第二个元素7。其中的难点是C中printf()计算参数是从右到左压栈的,所以在此题中先压栈*(++ptr)此时ptr指向了第三个元素8,再解引用ptr依然为8。

有一篇讲解:printf函数遵守C调用规范,即参数 从右至左 压栈,堆栈由调用者平衡。 其中第二个例子在我机器上的运行结果为:cbb。


2.下面程序的运行结果是多少?

#include <stdio.h>

int main()
{
    unsigned char a=0xA5;
    unsigned char b=~a>>4;
    printf("b=%d\n",b); 
    
    return 0;
}
答案是:245

解析:文中说本题考查两个知识点:一、类型转换问题;二、运算符的优先级问题。文中有一处错误,其实"~"的优先级是要高于">>"的优先级的,而文中说反了。但即便是按照错误的思路下来,还是可以得到正确的结果,让人匪夷所思,是因为文中的解法没有做到“整数提升”。关于整数提升的一篇文章:C语言中的整数提升。

有一篇帖子讨论了这个问题给出了正确的答案:C运算符优先级问题。还有一篇:关于移位运算符和取反运算符的一点感悟。


3.下面程序的运行结果是多少?

#include <stdio.h>

int main()
{
    unsigned int a=0xFFFFFF7;
    unsigned char i=(unsigned char)a;
    char *b=(char *)&a;
    printf("%08x, %08x",i,*b);
    
    return 0;
}
答案是:000000f7,fffffff7

解析:面试宝典错误修正。涉及到printf()的输出格式,x为十六位格式:C Printf and Scanf Reference。


4.在const成员函数中,用mutable修饰成员变量名后,就可以修改类的成员变量了。


5.What is the output of the following code?

#include <iostream>
#include <string>
 
using namespace std;

struct
{
      short a1;
      short a2;
      short a3;
}A;

struct
{
      long a1;
      short a2;
}B;

int main()
{
    char *ss1="0123456789";
    char ss2[]="0123456789";
    char ss3[100]="0123456789";
    int ss4[100];
    char q1[]="abc";
    char q2[]="a\n";
    char *q3="a\n";
    char *str1=(char *)malloc(100);
    void *str2=(void *)malloc(100);
    
    cout<<sizeof(ss1)<<endl;
    cout<<sizeof(ss2)<<endl;
    cout<<sizeof(ss3)<<endl;
    cout<<sizeof(ss4)<<endl;
    cout<<sizeof(q1)<<endl;
    cout<<sizeof(q2)<<endl;
    cout<<sizeof(q3)<<endl;
    cout<<sizeof(A)<<endl;
    cout<<sizeof(B)<<endl;
    cout<<sizeof(str1)<<endl;
    cout<<sizeof(str2)<<endl;
    
    return 0;
} 
答案是:

4

11

100

400

4

3

4

6

8

4

4

解析:本题和下面的一些题目涉及到sizeof()操作符和地址对齐的问题,有一篇介绍的文章:sizeof struct & union



6.32位机器编译,数据以4字节为对齐单位,求输出结果。

#include <iostream>

using namespace std;

class B
{
      private:
              bool m_bTemp;
              int m_nTemp;
              bool m_bTemp2;
};

class C
{
      private:
              int m_nTemp;
              bool m_bTemp;
              bool m_bTemp2;
};

int main()
{
    cout<<sizeof(B)<<endl;
    cout<<sizeof(C)<<endl;
    
    return 0;
}
答案是:

12

8

解析:bool类型为1字节,int为4字节。

7.求解下面程序的结果。

#include <iostream>

using namespace std;

class A1
{
      public:
             int a;
             static int b;
             
             A1();
             ~A1();
};

class A2
{
      public:
             int a;
             char c;
             
             A2();
             ~A2();
};

class A3
{
      public:
             float a;
             char c;
             
             A3();
             ~A3();
};

class A4
{
      public:
             float a;
             int b;
             char c;
             
             A4();
             ~A4();
};

class A5
{
      public:
             double d;
             float a;
             int b;
             char c;
             
             A5();
             ~A5();
};

int main()
{
    cout<<sizeof(A1)<<endl;
    cout<<sizeof(A2)<<endl;
    cout<<sizeof(A3)<<endl;
    cout<<sizeof(A4)<<endl;
    cout<<sizeof(A5)<<endl;
    
    return 0;
}
答案是:

4

8

8

12

24
解析:因为静态变量是存放在全局数据存储区,而sizeof()计算栈中分配的大小,是不会计算在内的,所以sizeof(A)是4。double类型大小为8字节。


8.求代码输出的结果。

#include <iostream>

using namespace std;

int test(char c[])
{
    return sizeof(c);
}

int main()
{
    char var[10];
    cout<<test(var)<<endl;
    
    return 0;
}
答案是:4

解析:var[]等于*var,已经退化成了一个指针,所以为4。数组作为参数传递给函数时传的是指针而不是数组,传递的是数组的首地址,如func(char[8]),func(char[])都等价于func(char *),编译器不知道数组的大小,如果想在函数内知道数组的大小可以将长度由另一个形参传进去。


9.一个空类占多少空间?多重继承空类呢?

#include <iostream>

using namespace std;

class A
{
};

class A2
{
};

class B: public A
{
};

class C: public virtual B
{
};

class D: public A, public A2
{
};

int main()
{
    cout<<sizeof(A)<<endl;
    cout<<sizeof(B)<<endl;
    cout<<sizeof(C)<<endl;
    cout<<sizeof(D)<<endl;
    
    return 0;
}
答案是:

1

1

4

1
解析:空类所占空间为1字节,单一继承空类和多重继承空类所占空间还是1,虚继承设计到虚函数表(虚指针),所以sizeof(c)为4。


10.下面的程序有什么问题,该如何修改?

#include <stdio.h>

char *strA()
{
     char str[]="hello world";
     //char *str="hello world";
     //static char str[]="hello world";
     
     return str;
} 

int main()
{
    printf("%s\n", strA());
     
    return 0;
}
答案是:函数strA()返回的是局部变量的地址,当调用完函数后,局部变量str被释放,所以返回的结果是不确定和不安全的。通过修改为下面注释了的两行内容,就可以得到正确的结果。

解析:char *str和char str[]比较:char c[]="hello world";是分配一个临时数组,char *c="hello world";是分配一个字符串常量,临时数组是局部变量,它对应的是内存中的栈,字符串常量对应的是内存中的全局数据区。

全局区域的值是不能修改的,如:

char *c="hello world";

*c='t';   // error

但是局部区域的数据时可以修改的:

char c[]="hello world";

c[0]='t';  // ok

上题中通过定义静态类型开辟一段静态存储空间来存储字符串也是正确的。


11.下列程序的输出结果是什么?

#include <iostream>

using namespace std;

class A
{
      public:
             int _a;
             A()
             {
                 _a=1; 
             }
             void print()
             {
                  printf("%d\n", _a); 
             } 
};

class B:public A 
{
      public:
             int _a;
             B()
             {
                 _a=2; 
             } 
};

int main()
{
    B b;
    b.print();
    printf("%d\n", b._a);
    
    return 0; 
} 

答案是:

1

2

解析:在构造B类时,先调用A类的构造函数。

12.关于函数指针的用法,程序如下,注释掉的内容也正确。

#include <stdio.h>

int max(int x, int y)
{
    return x>y?x:y; 
} 

int main()
{
    //int max(int, int);
    int (*p)(int, int)=max;
    //int (*p)(int, int)=&max; 
    //int (*p)(int, int);
    //p=max;
    //p=&max; 
    int a,b,c;
    printf("Please input two integers:\n");
    scanf("%d%d",&a,&b);
    //c=(*p)(a,b);
    c=p(a,b); 
    printf("The bigger one is %d",c); 
    
    return 0; 
} 

13.Write in words the data type of the identifier involved in the following definitiions.

(1) float(**def)[10];
(2) double*(*gh)[10];
(3) double(*f[10])();
(4) int*((*b)[10]);
(5) long(*fun)(int);
(6) int(*(*F)(int, int))(int);
答案是:

(1)def是一个二维指针,它指向的是一个一维数组的指针,数组的元素都是float类型。

(2)gh是一个一维数组的指针,数组的元素都是指向double类型的指针。

(3)f是一个一维数组,f有10个元素,每个元素都是函数的指针,指向的函数是没有参数且返回double类型的函数。

(4)相当于int*(*b)[10],b是一个一维数组的指针,数组的每个元素都是指向int类型的指针。

(5)fun是一个函数指针,指向一个参数为一个int类型且返回类型为long的函数。

(6)F是一个函数指针,指向的是有两个int参数且返回一个函数指针的函数,返回的函数指针指向有一个int参数且返回int类型的函数。

14.解释a的输出结果。

int (*a)[10];
a++;
答案是:本题定义了一个指针指向一个含有10个int元素的数组,a++表明a指针向后移动40个字节。

解析:a++表明a指针向后移动(数组大小)*sizeof(类型)。


15.写出程序的输出结果。

#include <stdio.h>

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

解析:int *ptr=(int *)(&a+1)的意思是,指向a数组的第6个元素(尽管这个元素不存在)。

如果存在这样的数组:int b[2][5]={1,2,3,4,5,6,7,8,9,10}  那么 int *p=(int *)(&a+1)=b[1]。时刻牢记这样的观点:数组名本身就是指针,再加个&,就变成了双指针,这里的双指针就是指二维数组,加1,就是数组整体加一行。


16.下面代码有什么错误?

#include <iostream>

using namespace std;

int main()
{
    int *pInt=new int;
    *pInt=10;
    cout<<"*pInt: "<<*pInt<<endl;
    delete pInt;
    //pInt=0; 
    
    long *pLong=new long;
    *pLong=90000;
    cout<<"*pLong: "<<*pLong<<endl;
    
    *pInt=20;   
    
    cout<<"*pInt: "<<*pInt<<endl;
    cout<<"*pLong: "<<*pLong<<endl;
    delete pLong;
    
    return 0; 
} 
答案是:以上程序使用了迷途指针并重新赋值,会导致程序结果的不可预料(或崩溃)。

解析:我在机器上运行pInt=0加注释后的程序,得到的结果为:

此时程序没有崩溃,只是程序运行的不是预期的结果,可能是pInt和pLong指向了同一片内存区域。在删掉注释,就是加上pInt=0后,程序的结果是:


然后抛出异常,程序崩溃,是因为对空指针进行了赋值。

在这里涉及到两个概念:迷途指针(悬浮指针)和空指针。迷途指针是指当对一个指针进行delete操作后(实际上编译器只是释放了它所指向的内存,而指针本身已然存在),并没有将指针设置为空时产生的。如果没有重新赋值就试图再次使用该指针,引起的结果是不可预料的,为了安全起见,在删除一个指针之后,把它设置为空指针,这样就可以消除它的危害。

当使用下面的语句时,就可以把迷途指针改为空指针: MyPtr=0; 使用迷途指针或空指针是非法的,而且有可能造成程序崩溃,如果指针式空指针,尽管同样是崩溃,但它同迷途指针造成的崩溃相比是一种可预料的崩溃(如程序运行抛出异常)。


17.下列程序的输出结果是什么?

#include <iostream>

using namespace std;

int main()
{
    char *a[]={"hello","the","world"};
    char **pa=a;
    pa++;
    cout<<*pa<<endl; 
    
    return 0; 
} 
答案是:the

解析:与下列代码同一效果:

char *a[]={"hello","the","world"};
char **pa=(&a[0]+1);
cout<<*pa<<endl;

#include <iostream>

using namespace std;

int main()
{
    char *a[]={"hello","the","world"};
    char **pa=a;
    (*pa)++; 
    cout<<**pa<<endl; 
    
    return 0; 
} 
的输出结果是:e



你可能感兴趣的:(面试宝典5,6,7--程序设计基本概念;预处理、const与sizeof;指针与引用)