笔试题摘选(选择题部分)

来源:互联网 发布:2016年心动网络招聘 编辑:程序博客网 时间:2024/05/16 23:33

做笔试的时候经常感觉很多基本知识大概都知道,但真做起题来总有些细节不甚了解导致无法确定,所以这里收录一些我容易犯错的题,相当于高中的错题集吧(捂脸)


判断union或class的大小

union u{    int a;    char c;    char s[9];};class c{    int a;    char c;    char s[9];};

试分别写出上述两个数据结构的大小(32位系统下)。

答案:12,16

按我之前的理解,union部分的三个元素分别为4,1,9bytes,取最大值9即可,同理class部分将4,1,9加起来即可,答案应该是9,14。要不是做题的时候发现没有这个选项,我至今都不会意识到自己的错误。

我在StackOverflow的这个回答里找到了答案。说是出于Data structure alignment的考虑,机器会在数据结构里安插一些无用(unused)的字节。
例如上述的union块,实际在机器中的结构是:

+---+---+---+---+| a             |+---+---+---+---+| c |+---+---+---+---+---+---+---+---+---+ - + - + - +| s                                 |  unused   |+---+---+---+---+---+---+---+---+---+ - + - + - +  0   1   2   3   4   5   6   7   8   9   10  11 

最后3位是闲置的。另外,经过测试,a,c,s三个元素也都是从对象内存开始的位置开始写入的。也因此,无论int a写在第几个,结果的大小都是不变的。
类似的,class在机器中的实际情况是:

+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ - + - + | a             | c | s                                 |unused |+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ - + - +   0   1   2   3   4   5   6   7   8   9   10  11  12  13  14  15 

但是如果考虑这样两个类

class c1{    int a;    char c;    int b;    char s[9];};class c2{    int a;    int b;    char c;    char s[9];};

其中c1c2的大小分别是24和20字节。因为在c1中,char c后紧跟了3个字节的无用内存,同时char s[9]后紧跟了3个字节的无用内存;而在c2中,char cchar s[9]紧挨着,后面跟着2个字节的无用内存(可以参考前文提到的StackOverflow的那个问题)。

另外补充,空类(没有任何非静态成员变量的类),大小也为1,主要是系统需要一个占位符来方便调用这个类。因此,如果类的非静态成员变量只有一个char时,大小仍然为1。
当类中声明了虚函数(不管是1个还是多个),那么在实例化对象时,编译器会自动在对象里安插一个指针vPtr指向虚函数表VTable,因此会有额外4或8字节存储开销(取决于架构)。

总结:类对象的大小=各非静态数据成员的总和+ 虚基表指针(多继承下可能不止一个)+虚函数表指针(多继承下可能不止一个)+编译器额外增加的字节。


数据库相关

DBS包括DBMS和DB
- 数据库(DB):长期存放在计算机内的有组织的可共享的数据集合
- 数据库管理系统(DBMS):完成数据库的建立、使用和维护功能
- 数据库系统(DBS)
- 数据库+数据库管理系统
- (应用系统+数据库管理员 +用户)
- 数据库管理员(DBA):除DBMS完成外,还需专门的人员来完成,这些人被称为DBA

如下SQL语句中,__可能返回null值。
(1) SELECT COUNT(*) FROM t1;
(2) SELECT MAX(col1) FROM t1;
(3) SELECT CONCAT(‘max=’,MAX(col1)) FROM t1;

答案:(1)不可能,(2)和(3)可能
(1)返回的是表的行数,如果没有记录,应该返回0,不会出现NULL,
(2) 和(3) 正常情况下不会出现NULL,但是如果表里面没有记录,MAX()会出现NULL,而CONCAT(str1,str2,…)返回结果为连接参数产生的字符串。如有任何一个参数为NULL ,则返回值为 NULL。


虚函数

包含虚函数的类会在每个对象中添加一个(无论有多少个虚函数)虚函数表指针来实现多态的特性。这个概念经常会考到不多赘述。
同时,为了保证对象能在任何时候被正确地析构掉,析构函数应该被声明为虚函数(除非你保证绝不会在此类的对象身上用到多态特性)。
于是今天突然想到一个问题,编译期自动提供的默认析构函数,是不是虚析构函数呢?于是做了一个实验:

class base {};      //什么都不写,依赖编译期提供的默认方式class derive : public base {public:    virtual ~derive() {        cout << "derive destruction" << endl;    }};int main(int argc, char* argv[]){    base *b = new derive;    delete b;    return 0;}

这个代码的运行结果是编译正常而运行出错。为了探查原因,我们测试下

    cout << sizeof(base) << endl << sizeof(derive) << endl;

很容易发现sizeof(base)的结果是1sizeof(derive)的结果是8(64位编译器)。前者为什么是1的原因《剑指offer》上也提到过:即便一个对象内什么数据都没有,编译期为了能在需要的时候取到它的地址,就用1字节的空白填充。对比sizeof(derive)就可以发现,base对象里没有虚函数表指针,因此,默认析构函数,不是虚函数


未完待续