C++笔试题整理

目录

 

1. 笔试题1

1.1 链表反转

1.2 String

2. 笔试题2

2.1 求下面函数的返回值(微软)

2.2 什么是“引用”?申明和使用“引用”要注意哪些问题?

2.3 将“引用”作为函数参数有哪些特点?

2.4 在什么时候需要使用“常引用”? 

2.5 将“引用”作为函数返回值类型的格式、好处和需要遵守的规则?

2.6 “引用”与多态的关系?

2.7 “引用”与指针的区别是什么?

2.8 什么时候需要“引用”?

2.9 结构与联合有和区别?

2.10 下面关于“联合”的题目的输出?

2.11 已知strcpy的函数原型:char *strcpy(char *strDest, const char *strSrc)其中strDest 是目的字符串,strSrc 是源字符串。不调用C++/C 的字符串库函数,请编写函数 strcpy。

2.12 已知String类定义如下:

2.13 .h头文件中的ifndef/define/endif 的作用?

2.14 #i nclude 与 #i nclude "file.h"的区别?

2.15 在C++ 程序中调用被C 编译器编译后的函数,为什么要加extern “C”?

2.16 关联、聚合(Aggregation)以及组合(Composition)的区别?

2.17 面向对象的三个基本特征,并简单叙述之?

2.18 重载(overload)和重写(overried,有的书也叫做“覆盖”)的区别?

2.19 多态的作用?

2.20 Ado与Ado.net的相同与不同?

2.21 New delete 与malloc free 的联系与区别?

2.22. #define DOUBLE(x) x+x ,i = 5*DOUBLE(5); i 是多少?

2.23 有哪几种情况只能用intialization list 而不能用assignment?

2.24 C++是不是类型安全的?

2.25 main 函数执行以前,还会执行什么代码?

2.26 描述内存分配方式以及它们的区别?

2.27 struct 和 class 的区别

2.28 当一个类A 中没有生命任何成员变量与成员函数,这时sizeof(A)的值是多少,如果不是零,请解释一下编译器为什么没有让它为零。(Autodesk)

2.29 在8086 汇编下,逻辑地址和物理地址是怎样转换的?(Intel)

2.30 比较C++中的4种类型转换方式?

2.31 分别写出BOOL,int,float,指针类型的变量a 与“零”的比较语句。

2.32 请说出const与#define 相比,有何优点?

2.33 简述数组与指针的区别?

2.34 类成员函数的重载、覆盖和隐藏区别?

2.35 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.

2.36. 如何打印出当前源文件的文件名以及源文件的当前行号?

2.37 main 主函数执行完毕后,是否可能会再执行一段代码,给出说明?

2.38 如何判断一段程序是由C 编译程序还是由C++编译程序编译的?

2.39 文件中有一组整数,要求排序后输出到另一个文件中

2.40 链表题:一个链表的结点结构

2.41 分析一下这段程序的输出 (Autodesk)

2.42 写一个函数找出一个整数数组中,第二大的数 (microsoft)

2.43 写一个在一个字符串(n)中寻找一个子串(m)第一个位置的函数。

2.44 多重继承的内存分配问题:

2.45 如何判断一个单链表是有环的?(注意不能用标志位,最多只能用两个额外指针)

3. 笔试题3

3.1 C和C++的区别

3.2 C++中指针和引用的区别

3.3 结构体struct和共同体union(联合)的区别

3.4 #define和const的区别

3.5 重载overload,覆盖override,重写overwrite,这三者之间的区别

3.6 new、delete、malloc、free之间的关系

3.7 delete和delete[]的区别

3.8 STL库用过吗?常见的STL容器有哪些?算法用过几个?

3.9 const知道吗?解释一下其作用

3.10 虚函数是怎么实现的

3.11 堆和栈的区别

3.12 关键字static的作用

3.13 STL中map和set的原理(关联式容器)

3.14 #include #include "file.h" 的区别

3.15 什么是内存泄漏?面对内存泄漏和指针越界,你有哪些方法?

3.16 定义和声明的区别

3.17 C++文件编译与执行的四个阶段

3.18 STL中的vector的实现,是怎么扩容的?

3.19 STL中unordered_map和map的区别

3.20 C++的内存管理

3.21 构造函数为什么一般不定义为虚函数?而析构函数一般写成虚函数的原因 ?

3.22 静态绑定和动态绑定的介绍

3.23 引用是否能实现动态绑定,为什么引用可以实现

3.24 深拷贝和浅拷贝的区别

3.25 什么情况下会调用拷贝构造函数(三种情况) 

3.26 C++的四种强制转换 

3.27 调试程序的方法 

3.28 extern“C”作用

3.29 typdef和define区别

3.30 volatile关键字在程序设计中有什么作用

3.31 引用作为函数参数以及返回值的好处

3.32 纯虚函数

3.33 什么是野指针

3.33 线程安全和线程不安全

3.34 C++中内存泄漏的几种情况

3.35 栈溢出的原因以及解决方法

3.36 C++标准库vector以及迭代器

3.37 C++ 11有哪些新特性

3.38 C++中vector和list的区别

3.39 C语言的函数调用过程

3.40 C++中的基本数据类型及派生类型

3.41 友元函数和友元类

3.42 C++线程中的几种锁机制


 

1. 笔试题1

 

1.1 链表反转

单向链表的反转是一个经常被问到的一个面试题,也是一个非常基础的问题。比如一个链表是这样的: 1->2->3->4->5 通过反转后成为5->4->3->2->1。

 

最容易想到的方法遍历一遍链表,利用一个辅助指针,存储遍历过程中当前指针指向的下一个元素,然后将当前节点元素的指针反转后,利用已经存储的指针往后面继续遍历。源代码如下:

struct linka {
    int data;
    linka* next;
};
void reverse(linka*& head) {
    if(head ==NULL)
        return;
    linka *pre, *cur, *ne;
    pre=head;
    cur=head->next;
    while(cur)
    {
       ne = cur->next;
       cur->next = pre;
       pre = cur;
       cur = ne;
    }
    head->next = NULL;
    head = pre;
}

还有一种利用递归的方法。这种方法的基本思想是在反转当前节点之前先调用递归函数反转后续节点。源代码如下。不过这个方法有一个缺点,就是在反转后的最后一个结点会形成一个环,所以必须将函数的返回的节点的next域置为NULL。因为要改变head指针,所以我用了引用。算法的源代码如下:

linka* reverse(linka* p,linka*& head)
{
    if(p == NULL || p->next == NULL)
    {
       head=p;
       return p;
    }
    else
    {
       linka* tmp = reverse(p->next,head);
       tmp->next = p;
       return p;
    }
}

 

1.2 String

已知String类定义如下:

class String
{
    public:
        String(const char *str = NULL); // 通用构造函数
        String(const String &another); // 拷贝构造函数
        ~ String(); // 析构函数
        String & operater =(const String &rhs); // 赋值函数
    private:
        char *m_data; // 用于保存字符串
};

尝试写出类的成员函数实现。

答案:

String::String(const char *str)
{
    if ( str == NULL ) //strlen在参数为NULL时会抛异常才会有这步判断
    {
        m_data = new char[1] ;
        m_data[0] = '/0' ;
    }
    else
    {
        m_data = new char[strlen(str) + 1];
        strcpy(m_data,str);
    }
} 

String::String(const String &another)
{
    m_data = new char[strlen(another.m_data) + 1];
    strcpy(m_data,other.m_data);
}

String& String::operator =(const String &rhs)
{
    if ( this == &rhs)
        return *this ;
    delete []m_data; //删除原来的数据,新开一块内存
    m_data = new char[strlen(rhs.m_data) + 1];
    strcpy(m_data,rhs.m_data);
    return *this ;
}

String::~String()
{
    delete []m_data ;
}

 

2. 笔试题2

 

2.1 求下面函数的返回值(微软)

int func(x)
{
    int countx = 0;
    while(x)
    {
        countx ++;
        x = x&(x-1);
    }
    return countx;
}

        假定x = 9999。 答案:8

        思路:将x转化为2进制,看含有的1的个数。

 

2.2 什么是“引用”?申明和使用“引用”要注意哪些问题?

答:

        引用就是某个目标变量的“别名”(alias),对应用的操作与对变量直接操作效果完全相同。

        申明一个引用的时候,切记要对其进行初始化。

        引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,不能再把该引用名作为其他变量名的别名。

        声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。

       不能建立数组的引用。

 

2.3 将“引用”作为函数参数有哪些特点?

        1. 传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。

        2. 使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。

        3. 使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。

 

2.4 在什么时候需要使用“常引用”? 

        如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。

        常引用声明方式:const 类型标识符 &引用名=目标变量名;

        例1

                 int a ;

                const int &ra=a;

                ra=1; //错误

                a=1; //正确

        例2

                string foo( );

                void bar(string & s);

                那么下面的表达式将是非法的:

                bar(foo( ));

                bar("hello world");

               原因在于foo( )和"hello world"串都会产生一个临时对象,而在C++中,这些临时对象都是const类型的。因此上面的表达式就是试图将一个const类型的对象转换为非const类型,这是非法的。

        引用型参数应该在能被定义为const的情况下,尽量定义为const 。

 

2.5 将“引用”作为函数返回值类型的格式、好处和需要遵守的规则?

        格式:类型标识符 &函数名(形参列表及类型说明){ //函数体 }

        好处:在内存中不产生被返回值的副本;(注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的。因为随着该局部变量生存期的结束,相应的引用也会失效,产生runtime error!

        注意事项:

                1. 不能返回局部变量的引用。这条可以参照Effective C++[1]的Item 31。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态。

                2. 不能返回函数内部new分配的内存的引用。这条可以参照Effective C++[1]的Item 31。虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak。

                3. 可以返回类成员的引用,但最好是const。这条原则可以参照Effective C++[1]的Item 30。主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。

                4. 流操作符重载返回值申明为“引用”的作用:

                        流操作符<<和>>,这两个操作符常常希望被连续使用,例如:cout << "hello" << endl; 因此这两个操作符的返回值应该是一个仍然支持这两个操作符的流引用。可选的其它方案包括:返回一个流对象和返回一个流对象指针。但是对于返回一个流对象,程序必须重新(拷贝)构造一个新的流对象,也就是说,连续的两个<<操作符实际上是针对不同对象的!这无法让人接受。对于返回一个流指针则不能连续使用<<操作符。因此,返回一个流对象引用是惟一选择。这个唯一选择很关键,它说明了引用的重要性以及无可替代性,也许这就是C++语言中引入引用这个概念的原因吧。

                        赋值操作符=。这个操作符象流操作符一样,是可以连续使用的,例如:x = j = 10;或者(x=10)=100;赋值操作符的返回值必须是一个左值,以便可以被继续赋值。因此引用成了这个操作符的惟一返回值选择。

                        例3

                        #include <iostream.h>

                        int &put(int n);

                        int vals[10];

                        int error=-1;

                        void main()

                        {

                                put(0)=10; //以put(0)函数值作为左值,等价于vals[0]=10;

                                put(9)=20; //以put(9)函数值作为左值,等价于vals[9]=20;

                                cout<<vals[0];

                                cout<<vals[9];

                        }

                        int &put(int n)

                        {

                                if (n>=0 && n<=9 ) return vals[n];

                                else { cout<<"subscript error"; return error; }

                        }

                5. 在另外的一些操作符中,却千万不能返回引用:+-*/ 四则运算符。它们不能返回引用,Effective C++[1]的Item23详细的讨论了这个问题。主要原因是这四个操作符没有side effect,因此,它们必须构造一个对象作为返回值,可选的方案包括:返回一个对象、返回一个局部变量的引用,返回一个new分配的对象的引用、返回一个静态对象引用。根据前面提到的引用作为返回值的三个规则,第2、3两个方案都被否决了。静态对象的引用又因为((a+b) == (c+d))会永远为true而导致错误。所以可选的只剩下返回一个对象了。

 

2.6 “引用”与多态的关系?

        引用是除指针外另一个可以产生多态效果的手段。这意味着,一个基类的引用可以指向它的派生类实例。

        例4

                Class A;

                Class B : Class A{...};

                B b;

                A& ref = b;

 

2.7 “引用”与指针的区别是什么?

        指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。此外,就是上面提到的对函数传ref和pointer的区别。

 

2.8 什么时候需要“引用”?

        流操作符<<和>>、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、其它情况都推荐使用引用。

 

2.9 结构与联合有和区别?

        1. 结构和联合都是由多个不同的数据类型成员组成, 但在任何同一时刻, 联合中只存放了一个被选中的成员(所有成员共用一块地址空间), 而结构的所有成员都存在(不同成员的存放地址不同)。

        2. 对于联合的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于结构的不同成员赋值是互不影响的。

 

2.10 下面关于“联合”的题目的输出?

a)

#include <stdio.h>
Union
{
    int i;
    char x[2];
}a;

void main()
{
    a.x[0] = 10;
    a.x[1] = 1;
    printf("%d",a.i);
}

答案:266 (低位低地址,高位高地址,内存占用情况是Ox010A)

 

b)

main()
{
    union{ /*定义一个联合*/
        int i;
        struct{ /*在联合中定义一个结构*/
            char first;
            char second;
        }half;
    }number;
    
    number.i=0x4241; /*联合成员赋值*/
    printf("%c%c/n", number.half.first, mumber.half.second);
    number.half.first='a'; /*联合中结构成员赋值*/
    number.half.second='b';
    printf("%x/n", number.i);
    getch();
}

答案: AB (0x41对应'A',是低位;Ox42对应'B',是高位)

           6261 (number.i和number.half共用一块地址空间)

 

2.11 已知strcpy的函数原型:char *strcpy(char *strDest, const char *strSrc)其中strDest 是目的字符串,strSrc 是源字符串。不调用C++/C 的字符串库函数,请编写函数 strcpy。

答案:

char *strcpy(char *strDest, const char *strSrc)
{
    if ( strDest == NULL || strSrc == NULL)
        return NULL ;
    if ( strDest == strSrc)
        return strDest ;
    char *tempptr = strDest ;
    while( (*strDest++ = *strSrc++) != ‘/0’) 
    {
    }
    return tempptr ;
}

 

2.12 已知String类定义如下:

class String
{
    public:
        String(const char *str = NULL); // 通用构造函数
        String(const String &another); // 拷贝构造函数
        ~ String(); // 析构函数
        String & operater =(const String &rhs); // 赋值函数
    private:
        char *m_data; // 用于保存字符串
};

尝试写出类的成员函数实现。

 

答案:

   

String::String(const char *str)
{
    if ( str == NULL ) //strlen在参数为NULL时会抛异常才会有这步判断
    {
        m_data = new char[1] ;
        m_data[0] = '/0' ;
    }
    else
    {
        m_data = new char[strlen(str) + 1];
        strcpy(m_data,str);
    }
} 

String::String(const String &another)
{
    m_data = new char[strlen(another.m_data) + 1];
    strcpy(m_data,other.m_data);
}

String& String::operator =(const String &rhs)
{
    if ( this == &rhs)
        return *this ;
    delete []m_data; //删除原来的数据,新开一块内存
    m_data = new char[strlen(rhs.m_data) + 1];
    strcpy(m_data,rhs.m_data);
    return *this ;
}

String::~String() 
{
    delete []m_data ;
}

 

2.13 .h头文件中的ifndef/define/endif 的作用?

        答:防止该头文件被重复引用。

 

2.14 #i nclude<file.h> 与 #i nclude "file.h"的区别?

        答:前者是从Standard Library的路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h。

 

2.15 在C++ 程序中调用被C 编译器编译后的函数,为什么要加extern “C”?

        extern "C"的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern "C"后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。

 

2.16 关联、聚合(Aggregation)以及组合(Composition)的区别?

        涉及到UML中的一些概念:关联是表示两个类的一般性联系,比如“学生”和“老师”就是一种关联关系;聚合表示has-a的关系,是一种相对松散的关系,聚合类不需要对被聚合类负责。

        从实现的角度讲,聚合可以表示为:

                 class A {...} class B { A* a; .....}

        而组合表示contains-a的关系,关联性强于聚合:组合类与被组合类有相同的生命周期,组合类要对被组合类负责。

        实现的形式是:

                class A{...} class B{ A a; ...}

 

2.17 面向对象的三个基本特征,并简单叙述之?

        1. 封装:将客观事物抽象成类,每个类对自身的数据和方法实行protection(private, protected,public)。

        2. 继承:广义的继承有三种实现形式:实现继承(指使用基类的属性和方法而无需额外编码的能力)、可视继承(子窗体使用父窗体的外观和实现代码)、接口继承(仅使用属性和方法,实现滞后到子类实现)。前两种(类继承)和后一种(对象组合=>接口继承以及纯虚函数)构成了功能复用的两种方式。

        3. 多态:是将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。

 

2.18 重载(overload)和重写(overried,有的书也叫做“覆盖”)的区别?

        从定义上来说:

                重载:是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。

                重写:是指子类重新定义父类虚函数的方法。

        从实现原理上来说:

               重载:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。如,有两个同名函数:void func(p:integer)和void func(p:string);。那么编译器做过修饰后的函数名称可能是这样的:int_func、str_func。对于这两个函数的调用,在编译器间就已经确定了,是静态的。也就是说,它们的地址在编译期就绑定了(早绑定),因此,重载和多态无关!

              重写:和多态真正相关。当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的(晚绑定)。

 

2.19 多态的作用?

        主要是两个:

                1. 隐藏实现细节,使得代码能够模块化;扩展代码模块,实现代码重用;

                2. 接口重用:为了类在继承和派生的时候,保证使用家族中任一类的实例的某一属性时的正确调用。

 

2.20 Ado与Ado.net的相同与不同?

        除了“能够让应用程序处理存储于DBMS 中的数据“这一基本相似点外,两者没有太多共同之处。但是Ado使用OLE DB 接口并基于微软的COM 技术,而ADO.NET 拥有自己的ADO.NET 接口并且基于微软的.NET 体系架构。众所周知.NET 体系不同于COM 体系,ADO.NET 接口也就完全不同于ADO和OLE DB 接口,这也就是说ADO.NET 和ADO是两种数据访问方式。ADO.net 提供对XML 的支持。

 

2.21 New delete 与malloc free 的联系与区别?

        答案:都是在堆(heap)上进行动态的内存操作。用malloc函数需要指定内存分配的字节数并且不能初始化对象,new 会自动调用对象的构造函数。delete 会调用对象的destructor,而free 不会调用对象的destructor.

 

2.22. #define DOUBLE(x) x+x ,i = 5*DOUBLE(5); i 是多少?

        答案:i 为30。

        直接展开:5 * x + x,所以当x为5时,是30。

        如果是 #define DOUBLE(x) (x + x),则展开为:5 * (x + x),则结果是50。

 

2.23 有哪几种情况只能用intialization list 而不能用assignment?

        答案:当类中含有const、reference 成员变量;基类的构造函数都需要初始化表。

 

2.24 C++是不是类型安全的?

        答案:不是。两个不同类型的指针之间可以强制转换(用reinterpret cast)。C#是类型安全的。

 

2.25 main 函数执行以前,还会执行什么代

  • 4
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
1.static有什么用途?(请至少说明两种) 1)在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。 2) 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。 3) 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用 2.引用与指针有什么区别? 1) 引用必须被初始化,指针不必。 2) 引用初始化以后不能被改变,指针可以改变所指的对象。 3) 不存在指向空值的引用,但是存在指向空值的指针。 3.描述实时系统的基本特性 在特定时间内完成特定的任务,实时性与可靠性。 4.全局变量和局部变量在内存中是否有区别?如果有,是什么区别? 全局变量储存在静态数据库,局部变量在堆栈。 5.什么是平衡二叉树? 左右子树都是平衡二叉树 且左右子树的深度差值的绝对值不大于1。 6.堆栈溢出一般是由什么原因导致的? 没有回收垃圾资源。 7.什么函数不能声明为虚函数? constructor函数不能声明为虚函数。 8.冒泡排序算法的时间复杂度是什么? 时间复杂度是O(n^2)。 9.写出float x 与“零值”比较的if语句。 if(x>0.000001&&x<-0.000001) 10.Internet采用哪种网络协议?该协议的主要层次结构? Tcp/Ip协议 主要层次结构为: 应用层/传输层/网络层/数据链路层/物理层。 11.Internet物理地址和IP地址转换采用什么协议? ARP (Address Resolution Protocol)(地址解析協議) 12.IP地址的编码分为哪俩部分? IP地址由两部分组成,网络号和主机号。不过是要和“子网掩码”按位与上之后才能区分哪些是网络位哪些是主机位。 13.用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出。写出C程序。 循环链表,用取余操作做 14.不能做switch()的参数类型是: switch的参数不能为实型。 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[] = “http://www.ibegroup.com/” 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). #i nclude 和 #i nclude “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” (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 * 类型的返回值? 答:方便赋值给其他变量 6.MFC中CString是类型安全类么? 答:不是,其它数据类型转换到CString可以使用CString的成员函数Format来转换 7.C++中为什么用模板类。 答:(1)可用来创建动态增长和减小的数据结构 (2)它是类型无关的,因此具有很高的可复用性。 (3)它在编译时而不是运行时检查数据类型,保证了类型安全 (4)它是平台无关的,可移植性 (5)可用于基本数据类型 8.CSingleLock是干什么的。 答:同步多个线程对一个数据类的同时访问 9.NEWTEXTMETRIC 是什么。 答:物理字体结构,用来设置字体的高宽大小 10.程序什么时候应该使用线程,什么时候单线程效率高。 答:1.耗时的操作使用线程,提高应用程序响应 2.并行操作时使用线程,如C/S架构的服务器端并发线程响应用户的请求。 3.多CPU系统中,使用线程提高CPU利用率 4.改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独 立的运行部分,这样的程序会利于理解和修改。 其他情况都使用单线程。 11.Windows是内核级线程么。 答:见下一题 12.Linux有内核级线程么。 答:线程通常被定义为一个进程中代码的不同执行路线。从实现方式上划分,线程有两 种类型:“用户级线程”和“内核级线程”。 用户线程指不需要内核支持而在用户程序 中实现的线程,其不依赖于操作系统核心,应用进程利用线程库提供创建、同步、调度 和管理线程的函数来控制用户线程。这种线程甚至在象 DOS 这样的操作系统中也可实现 ,但线程的调度需要用户程序完成,这有些类似 Windows 3.x 的协作式多任务。另外一 种则需要内核的参与,由内核完成线程的调度。其依赖于操作系统核心,由内核的内部 需求进行创建和撤销,这两种模型各有其好处和缺点。用户线程不需要额外的内核开支 ,并且用户态线程的实现方式可以被定制或修改以适应特殊应用的要求,但是当一个线 程因 I/O 而处于等待状态时,整个进程就会被调度程序切换为等待状态,其他线程得不 到运行的机会;而内核线程则没有各个限制,有利于发挥多处理器的并发优势,但却占 用了更多的系统开支。 Windows NT和OS/2支持内核线程。Linux 支持内核级的多线程 13.C++中什么数据分配在栈或堆中,New分配数据是在近堆还是远堆中? 答:栈: 存放局部变量,函数调用参数,函数返回值,函数返回地址。由系统管理 堆: 程序运行时动态申请,new 和 malloc申请的内存就在堆上 14.使用线程是如何防止出现大的波峰。 答:意思是如何防止同时产生大量的线程,方法是使用线程池,线程池具有可以同时提 高调度效率和限制资源使用的好处,线程池中的线程达到最大数时,其他线程就会排队 等候。 15函数模板与类模板有什么区别? 答:函数模板的实例化是由编译程序在处理函数调用时自动完成的,而类模板的实例化 必须由程序员在程序中显式地指定。 16一般数据库若出现日志满了,会出现什么情况,是否还能使用? 答:只能执行查询等读操作,不能执行更改,备份等写操作,原因是任何写操作都要记 录日志。也就是说基本上处于不能使用的状态。 17 SQL Server是否支持行级锁,有什么好处? 答:支持,设立封锁机制主要是为了对并发操作进行控制,对干扰进行封锁,保证数据 的一致性和准确性,行级封锁确保在用户取得被更新的行到该行进行更新这段时间内不 被其它用户所修改。因而行级锁即可保证数据的一致性又能提高数据操作的迸发性。 18如果数据库满了会出现什么情况,是否还能使用? 答:见16 19 关于内存对齐的问题以及sizof()的输出 答:编译器自动对齐的原因:为了提高程序的性能,数据结构(尤其是栈)应该尽可能 地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问 ;然而,对齐的内存访问仅需要一次访问。 20 int i=10, j=10, k=3; k*=i+j; k最后的值是? 答:60,此题考察优先级,实际写成: k*=(i+j);,赋值运算符优先级最低 21.对数据库的一张表进行操作,同时要对另一张表进行操作,如何实现? 答:将操作多个表的操作放入到事务中进行处理 22.TCP/IP 建立连接的过程?(3-way shake) 答:在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。   第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状 态,等待服务器确认; 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个 SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;   第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1) ,此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。 23.ICMP是什么协议,处于哪一层? 答:Internet控制报文协议,处于网络层(IP层) 24.触发器怎么工作的? 答:触发器主要是通过事件进行触发而被执行的,当对某一表进行诸如UPDATE、 INSERT 、 DELETE 这些操作时,数据库就会自动执行触发器所定义的SQL 语句,从而确保对数 据的处理必须符合由这些SQL 语句所定义的规则。 25.winsock建立连接的主要实现步骤? 答:服务器端:socker()建立套接字,绑定(bind)并监听(listen),用accept() 等待客户端连接。 客户端:socker()建立套接字,连接(connect)服务器,连接上后使用send()和recv( ),在套接字上写读数据,直至数据交换完毕,closesocket()关闭套接字。 服务器端:accept()发现有客户端连接,建立一个新的套接字,自身重新开始等待连 接。该新产生的套接字使用send()和recv()写读数据,直至数据交换完毕,closesock et()关闭套接字。 26.动态连接库的两种方式? 答:调用一个DLL中的函数有两种方法: 1.载入时动态链接(load-time dynamic linking),模块非常明确调用某个导出函数 ,使得他们就像本地函数一样。这需要链接时链接那些函数所在DLL的导入库,导入库向 系统提供了载入DLL时所需的信息及DLL函数定位。 2.运行时动态链接(run-time dynamic linking),运行时可以通过LoadLibrary或Loa dLibraryEx函数载入DLL。DLL载入后,模块可以通过调用GetProcAddress获取DLL函数的 出口地址,然后就可以通过返回的函数指针调用DLL函数了。如此即可避免导入库文件了 。 27.IP组播有那些好处? 答:Internet上产生的许多新的应用,特别是高带宽的多媒体应用,带来了带宽的急剧 消耗和网络拥挤问题。组播是一种允许一个或多个发送者(组播源)发送单一的数据包 到多个接收者(一次的,同时的)的网络技术。组播可以大大的节省网络带宽,因为无 论有多少个目标地址,在整个网络的任何一条链路上只传送单一的数据包。所以说组播 技术的核心就是针对如何节约网络资源的前提下保证服务质量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

公众号:程序喵星人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值