C++笔试面试常考知识点汇总(一)

本文深入探讨了C++中的核心概念和技术,包括大端与小端的区别、#include指令的不同用法、虚函数的重要性、深拷贝与浅拷贝的区别等,旨在帮助读者更好地理解和掌握C++的关键细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1:大端与小端?与寻常习惯的区别?
大端:高地址存储低位字节。
小端:低地址存储低位字节。
如对于数据0x1234,其32位为0x00001234。
对于大端来说:(地址由低到高存储)00 00 12 34
对于小端来说:(地址由低到高存储)34 12 00 00
由此可以得出结论:大端的存储方式与寻常习惯相一致,而小端的存储方式为按照字节倒排。

2:#include< >与#include” “的区别?
优先搜索路径不同。
前者优先搜索标准库文件目论,因此对于标准库文件搜索效率高。
后者优先搜索自定义文件目录,然后搜索整个磁盘,对于自定义文件的搜索比较快。

3:C++将基类的析构函数定义为虚函数的目的?
若将基类的析构函数定义为虚函数,当删除一个指向派生类的基类指针时,首先会调用派生类的析构函数,然后再调用基类的析构函数;否则只会调用基类的析构函数。

4:mutable定义数据成员的意义?
mutable定义的数据成员,可以在const成员函数中进行修改。

5:怎样定义一个纯虚函数?纯虚函数与抽象类的关系?抽象类的特点?
将虚函数赋值为0即可得到一个纯虚函数;包含纯虚函数的类是抽象类。抽象类有以下特点:不能实例化;不能作为函数参数及函数返回类型;可以定义抽象类类型的指针。
抽象类一般作为基类使用。对于一个抽象基类,如果其派生类没有重新定义基类的虚函数,则派生类也还是抽象类,只有派生类重新定义了基类的虚函数,派生类才不再是抽象类,才是一个可以建立对象的具体类。

6:malloc与new的区别?
1)malloc是函数,而new是操作符
2)malloc申请内存时,需要我们指定申请的空间大小,且返回的类型为void*,需要将其强制转换为所需类型指针;new申请内存时,会根据所申请的类型自动计算申请空间的大小,且可直接返回指定类型的指针
3)malloc释放内存时,用free函数,而new删除对象时,用的是delete操作符
4)malloc/free申请释放内存时,不需要需要调用析构函数,而new/delete申请释放内存时需要调用析构函数

7:STL算法中的next_permutation()算法的用法?
如果序列已经是最后一个排列,则next_permutation将序列重排为最小的序列,并返回false。否则,它将输入序列转换为字典序中下一个排列,并返回true。

8:用位逻辑运算实现位向量的set、clr、test?

#define BITSPERWORD 32 //表示一个整型含有32个bit
#define SHIFT 5 //单位位移量
#define MASK 0x1F   //掩码
#define N 10000000  //表示有1000万个数
int a[1+N/BITSPERWORD]; //使用整型数组模拟定义1000万个位的数组

//i>>SHIFT指的是右移5位,也就是除以32,指的是该位存在于哪个数组中
//i&MASK指的是i%32,剩下的数字为多少,1<<(i&MASK))表示1左移i&MASK位
void set(int i){a[i>>SHIFT]|=(1<<(i&MASK));}
void clr(int i){a[i>>SHIFT]&=~(1<<(i&MASK));}
int test(int i){return a[i>>SHIFT]&(1<<(i&MASK));}

解析:拿set函数为例:对于形参i,首先将i除以32(i>>SHIFT)以找到i位于数组中哪一位置;i&MASK指的是i%32后剩下的数字为多少,然后进行左移(因为对于任意一个a[m],只有32位,现其已经限定到具体的某个a[m],因此其移位范围为0~32);最后通过或运算将a[m]中的0变为1。
clr函数通过非运算(该位置1取非成为0)与与运算(该位置1与0相与后成为0),将相应位置的1转化为0。test函数探测i位置上数据到底是1还是0(i位置上的数据与1相与,返回其真实值)。

9:二维数组作为参数传递的注意事项?
需要指明数组的第二维,第一维不是必须要显式指定。

10:建立动态二维数组的两种方法?在删除用new建立的二维数组时注意事项?
法1://申请空间

    int ** a = new int *[row];//比一维的等号左右多了2个*而已
    for(int i = 0;i < row;i++)
        a[i] = new int[column];
该方法定义的动态二维数组的释放需先释放指针数组的每个元素指向的数组,然后再释放该指针数组:
for(int i = 0;i < row;i++)
    {
        delete a[i];
        a[i] = NULL;
    }
    delete [row]a;
    a = NULL;
vector<vector<int> > vec(row,vector<int>(column));//法2

11:sizeof运算符在编译阶段处理的特性?
sizeof操作符在其作用范围内,内容不会被编译,而只是简单替换成其类型。

12:sizeof(字符串序列)和sizeof(字符串数组)的区别?
sizeof(字符串序列)=字符串长度+1;(算上最后面的’\0’)
sizeof(字符串数组)=字符串长度;(用{}表示时)

13:sizeof(动态数组)?
动态数组实质上是一个指针,其占用空间为4/8(32位/64位系统)。

14:用strlen得到字符串的长度?
对于字符串序列,到第一个’\0’为止(’\0’自动添加且不计算在内);对于字符串数组,必须要显示指定’\0’。对于string型字符串,不能直接使用strlen,而需要使用strlen(s.c_str())计算。

    char p[]="abcdefg";
    char a[]={'a','b','c','\0'};
    cout<<strlen(p)<<endl;//输出7
    cout<<strlen(a)<<endl;//输出3

15:sizeof(联合)需要注意的占用空间最大的成员及对齐方式问题?
联合与结构的区别:结构中各成员有各自的内存空间,结构变量所占用内存空间是各成员所占用内存空间之和;联合中,各成员共享一段内存空间,一个联合变量所占用内存空间等于各成员中所占用内存空间最大的变量所占用内存空间(需考虑内存对齐问题),此时共享意味着每次只能赋一种值,赋入新值则冲去旧值。

16:sizeof(class)需注意情况?
sizeof只计算数据成员的大小;不计算static数据成员的大小;继承时需要考虑基类数据成员问题,考虑虚函数问题,无论有多少个虚函数,计算空间时虚函数表只计算一次。
补充:当派生类存在多重继承时,sizeof运算结果?

class A
{
    int a;
    int b;
    virtual void fun()
    {
    }
};
class B
{
    int c;
    virtual void fun1()
    {
    }
    virtual void fun2()
    {
    }
};
class C:public A,public B
{
    int d;
};

int main( ) 
{    
    cout<<sizeof(A)<<endl;//输出12
    cout<<sizeof(B)<<endl;//输出8
    cout<<sizeof(C)<<endl;//输出24
    return 0;    
}
对于同一个类的不同虚函数,只需考虑一次即可,而对于不同类的虚函数,派生类需要都考虑(每一个类虚函数只需考虑一次)。可参考虚函数表里的内存分配原则。

17:rand()函数的用法?srand函数的用法?

    rand();
    srand((unsigned int)(time NULL));

18:++a与a++的问题
++a得到左值,而a++得到右值。

19:静态分配与动态分配的区别?
静态分配是指在编译期间就能确定内存的大小,由编译器分配内存。动态分配是指在程序运行期间,由程序员申请的内存空间。堆和栈都可以动态分配,但静态分配只能是栈。

20:构造函数的列表初始化的初始化顺序?哪三种情况是必须的?

1:const数据成员;2:引用数据成员;3:没有默认构造函数的成员对象

对于static成员:若是static const成员,可以在类内初始化,也可以在类外初始化;若是普通的static成员,必须在类外初始化。

21:C++的转义序列?\abc与\xabc分别表示什么?
\abc表示8进制转义序列(\后最多跟三位数字);\xabc表示16进制的转义序列。
补充:\\也是一个转义字符

22:当编译器处理一个const时会将其转化成一个立即数。

23:为什么不能重新定义一个继承而来的默认参数?
因为从基类继承来的缺省参数值都是静态绑定的,而virtual函数——你唯一应该覆盖的东西,却是动态绑定。

24:为什么不能重新定义继承而来的非虚函数?
因为非虚函数是静态绑定的,如果重新定义继承而来的非虚函数,则指向派生类的基类指针在调用该非虚函数时,将可能会产生行为异常。

25:(做题经验)短路求值问题一定要细心运算。
一定要细心,判断是否一定会对&&或||后面的操作进行运算

26:深拷贝与浅拷贝的区别?
深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。浅拷贝是指源对象与拷贝对象共用一份实体,仅仅是引用的变量不同(名称不同),对其中任何一个对象的改动都会影响另外一个对象。
换种解释:浅拷贝,只是对指针的拷贝,拷贝后两个指针指向同一个内存空间,深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针。
浅拷贝会出现什么问题呢?
其一,浅拷贝只是拷贝了指针,使得两个指针指向同一个地址,这样在对象块结束,调用函数析构时,会造成同一份资源析构2次,即delete同一块内存2次,造成程序崩溃。
其二,浅拷贝使得源对象和拷贝对象指向同一块内存,任何一方的变动都会影响到另一方。
其三,在释放内存的时候,会造成拷贝对象原有的内存没有被释放造成内存泄露。(源对象内存被释放后,由于源对象和拷贝对象指向同一个内存空间,拷贝对象的空间不能再被利用了,删除拷贝对象不会成功,无法操作该空间,所以导致内存泄露)
类的静态成员是所有类的实例共有的,存储在全局(静态)区,只此一份,不管继承、实例化还是拷贝都是一份。因此类的静态成员不允许深拷贝。

27:如何只让类对象只在栈(堆)上分配对象?
1:只在堆上分配对象
动态建立对象,是使用new运算符将对象建立在堆空间中。过程分为2步,第一步是执行operator new()函数,在堆空间中搜索适合的内存并进行分配;第二步是调用构造函数构造对象,初始化这片内存空间。这种方法,间接调用类的构造函数。
将构造函数设为私有,将会阻止在堆上分配对象,是不行的。
将析构函数设为私有(为了考虑继承,可将析构函数设为受保护的)。当对象建立在栈上面时,是由编译器分配内存空间的,调用构造函数来构造栈对象。当对象使用完后,编译器会调用析构函数来释放栈对象所占的空间。编译器管理了对象的整个生命周期。编译器在为类对象分配栈空间时,会先检查类的析构函数的访问性,其实不光是析构函数,只要是非静态的函数,编译器都会进行检查。如果类的析构函数是私有的,则编译器不会在栈空间上为类对象分配内存。因此,将析构函数设为私有,类对象就无法建立在栈上了。
2:只在栈上分配对象
只要禁用new运算符(设为私有)就可以实现类对象只能建立在栈上。

28:char扩展为int的两种情况及注意事项?
将char转换为int时关键看char是unsigned还是signed,如果是unsigned就执行0扩展,如果是signed就执行符号位扩展。跟int本身是signed还是unsiged无关。
而同等位数的类型之间的赋值表达式不会改变其在内存之中的表现形式,即如果signed char a = 0xe0; unsigned char c = a;则c=0xe0;

29:面向过程static全局变量与全局变量的区别?
1)全局变量默认是有外部链接性的,作用域是整个工程,在一个文件内定义的全局变量,在另一个文件中,通过extern 全局变量名的声明,就可以使用全局变量。
2)静态全局变量是显式用static修饰的全局变量,作用域是声明此变量所在的文件,其他的文件即使用extern声明也不能使用。

30:面向过程静态局部变量的特点?
1)在全局数据区分配内存;
2)在程序执行到该对象的声明处时被首次初始化,且以后不再初始化;
3)一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0;
4)它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束;

31:面向对象静态数据成员的特点?
静态数据成员被当作是类的成员。只分配一次内存,供所有对象共用。
静态数据成员存储在全局数据区。静态数据成员定义时要分配空间,所以不能在类声明中定义(const static成员可以在类中定义)。
不属于特定的类对象,在没有产生类对象时其作用域就可见,即在没有产生类的实例时,我们就可以操作它。

静态数据成员初始化与一般数据成员初始化不同。静态数据成员初始化的格式为:
数据类型 类名:: 静态数据成员名=值
类的静态数据成员有两种访问形式:
类对象名.静态数据成员名 或 类类型名::静态数据成员名

静态数据成员主要用在各个对象都有相同的某项属性的时候。比如对于一个存款类,每个实例的利息都是相同的。所以,应该把利息设为存款类的静态数据成员。这有两个好处,第一,不管定义多少个存款类对象,利息数据成员都共享分配在全局数据区的内存,所以节省存储空间。第二,一旦利息需要改变时,只要改变一次,则所有存款类对象的利息全改变过来了;

同全局变量相比,使用静态数据成员有两个优势:
不存在与程序中其它全局名字冲突的可能性;
可以实现信息隐藏。静态数据成员可以是private成员,而全局变量不能;

32:面向对象静态成员函数的特点?
普通的成员函数一般都隐含了一个this指针,this指针指向类的对象本身,因为普通成员函数总是具体的属于某个类的具体对象的。但是与普通函数相比,静态成员函数由于不与任何的对象相联系,因此它不具有this指针。从这个意义上讲,它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员。
注意:出现在类体外的函数定义不能指定关键字static;
使用方法:可以用成员访问操作符(.)和(->;)为一个类的对象或指向类对象的指针调用静态成员函数,也可以直接:类名::静态成员函数名(参数表)

33:静态成员与非静态成员之间的可访问性?
静态成员之间可以互相访问;非静态成员可以访问静态成员及非静态成员,而静态成员不能访问非静态成员。

34:memcpy的用法与strcpy之间的区别?
memcpy函数的功能是从源指针所指的内存地址的起始位置开始拷贝n个字节到目标指针所指的内存地址的起始位置中。
void *memcpy(void *dest, const void *src, size_t n); //函数返回指向dest的指针
strcpy和memcpy主要有以下3方面的区别。
1)复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
2)复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符”\0”才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。
3)用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy。

35:前置递增递减运算符的运算对象必须是左值。

36:不能声明为虚函数的几种情况?
1)普通函数(非类成员函数)(不能被覆盖)
2)友元函数(C++不支持友元函数继承)
3)内联函数(编译期间展开,虚函数是在运行期间绑定)
4)构造函数(没有对象不能使用虚函数,先有构造函数后有虚函数,虚函数是对对象的动作(构造函数不能继承))
5)静态成员函数(只有一份大家共享)

37:虚函数的定义及功能?
定义:在某基类中声明为 virtual 并在一个或多个派生类中被重新定义的非static成员函数。
功能:实现多态性,通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数。

38:抽象类的特点?
含有纯虚拟函数的类称为抽象类,它不能生成对象。
在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。如动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。
抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出。如果派生类中没有重新定义纯虚函数,而只是继承基类的纯虚函数,则这个派生类仍然还是一个抽象类。如果派生类中给出了基类纯虚函数的实现,则该派生类就不再是抽象类了,它是一个可以建立对象的具体的类。

39:malloc、alloc、calloc、realloc的区别?
alloc:唯一在栈上申请内存的,无需释放;
malloc:在堆上申请内存,最常用;
calloc:malloc+初始化为0;
realloc:将原本申请的内存区域扩容,参数size大小即为扩容后大小,因此此函数要求size大小必须大于ptr内存大小。

40:STL算法中partition算法的用法?
对指定范围内的元素重新排序,使用输入的函数,把结果为true的元素放在结果为false的元素之前。stable_partition版本保留原始容器中的相对顺序。如使数组中奇数位于偶数前面。

41:什么是多态?
多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向派生类的基类的指针或引用,来调用实现派生类中的方法。

42:dynamic_cast的作用?
dynamic_cast将一个基类对象指针(或引用)(需指向派生类或为派生类的引用)cast到派生类指针。dynamic_cast会根据基类指针是否真正指向继承类对象来做相应处理,即会作一定的判断。对指针进行dynamic_cast,失败返回null,成功返回正常cast后的对象指针; 对引用进行dynamic_cast,失败抛出一个异常,成功返回正常cast后的对象引用。

43:在32位系统中和64为中long分别占用多少字节?
32位:4字节;64位:8字节。

44:#define与typedef的区别?
1) #define是预处理指令,在编译预处理时进行简单的替换,不作正确性检查。
2)typedef是在编译时处理的。它在自己的作用域内给一个已经存在的类型一个别名。
3)typedef int * int_ptr;与#define int_ptr int * (注意没有分号,否则连同分号一起替换)
作用都是用int_ptr代表 int * ,但是二者不同,正如前面所说 ,#define在预处理时进行简单的替换,而typedef不是简单替换 ,而是采用如同定义变量的方法那样来声明一种类型。
这也说明了为什么下面观点成立

typedef int * pint ;
#define PINT int *

那么:

const pint p ;//p不可更改,但p指向的内容可更改
const PINT p ;//p可更改,但是p指向的内容不可更改。

pint是一种指针类型 const pint p 就是把指针给锁住了 p不可更改
而const PINT p 是const int * p 锁的是指针p所指的对象。

45:堆和栈的区别?
1)栈,由编译器自动管理,无需我们手工控制;堆,申请释放工作由程序员控制
2)堆的生长方向是向上的,也就是向着内存地址增加的方向;栈的生长方向是向下的,是向着内存地址减小的方向增长。
3)对于堆来讲,频繁的 new/delete 势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题
4)一般来讲在 32 位系统下,堆内存可以达到4G的空间,但是对于栈来讲,一般都是有一定的空间大小的(2M)。

46:C、C++源代码要经过哪些步骤才生成可执行文件?各步骤的作用?
C/C++源代码要经过:预处理、编译、连接三步才能变成相应平台下的可执行文件。
预处理:主要是编译器对各种预处理命令进行处理,包括头文件的包含、宏定义的扩展、条件编译的选择等。
编译:进行词法与语法分析,首先编译成纯汇编语句,再将之汇编成跟CPU相关的二进制码,生成各个目标文件。
连接:链接是处理可重定位文件,把它们的各种符号引用和符号定义转换为可执行文件中的合适信息(一般是虚拟内存地址) 的过程。

47:公有继承、私有继承后基类public、protected、private成员在派生类中的访问权限?
有如下表格解释

基类中的public成public继承public
基类中的protected成员public继承protected
基类中的private成员public继承不可访问
基类中的public成员protected继承protected
基类中的protected成员protected继承protected
基类中的private成员protected继承不可访问
基类中的public成员private继承private
基类中的protected成员private继承private
基类中的private成员private继承不可访问

注意:派生类的对象只可访问public继承的基类中的public成员。

48:指针和引用的相同点与区别?
相同点:
1. 都是地址的概念;
指针指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名。
区别:
1. 指针是一个实体,而引用仅是个别名;
2. 引用使用时无需解引用(*),指针需要解引用;
3. 引用只能在定义时被初始化一次,之后不可变;指针可变;
4. 引用不能为空,指针可以为空;
5. “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身(所指向的变量或对象的地址)的大小;
6. 指针和引用的自增(++)运算意义不一样;引用的++实际上是绑定引用的对象的++,而指针的++,将指向指针之后的内存
7.从内存分配上看:程序为指针变量分配内存区域,而引用不需要分配内存区域。

49:初始化与赋值的区别?
初始化不是赋值,初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值擦除,而以一个新值来替代。

50:声明与定义的区别?
为了支持分离式编译,C++将声明和定义区分开来。声明使得名字为程序所知,一个文件如果想使用别处定义的名字则必须包含对那个名字的声明。定义负责创建与名字关联的实体。
简单来说,声明规定了变量的类型和名字,在这一点上与定义相同。但定义还申请了内存空间,也可能会为变量赋一个初始值。

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上产生的许多新的应用,特别是高带宽的多媒体应用,带来了带宽的急剧 消耗和网络拥挤问题。组播是种允许个或多个发送者(组播源)发送单的数据包 到多个接收者(次的,同时的)的网络技术。组播可以大大的节省网络带宽,因为无 论有多少个目标地址,在整个网络的任何条链路上只传送单的数据包。所以说组播 技术的核心就是针对如何节约网络资源的前提下保证服务质量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值