1、指针和引用的区别?
答:引用是在C++中引入的。它们之间的区别有:
(1)非空区别:指针可以为空,而引用不能为空
(2)可修改区别:如果指针不是常指针,那么就可以修改指向,而引用不能
(3)初始化区别:指针在定义时可以不用初始化,而引用在定义的同时必须初始化
2、为什么构造函数不能声明为虚函数?
答:因为虚函数采用的是虚调用的方法,虚调用是指允许在只知道部分信息的情况下的工作机制,特别允许我们调用一个只知道接口而不知道其对象的准确类型的函数。但是如果我们要调用构造函数创建对象时,必须要知道对象的准确类型,因此构造函数不能为虚函数。
3、char str1[]=”abc”; char str2[] = “abc”; str1==str2为FALSE,因为str1和str2是位于堆栈上的,它们占用不同的内存空间。Const char str3[] = “abc”; const char str4[] = “abc”;str3==str4为FALSE,同样它们是位于堆栈上的内存空间,是不同的。Const char *str5=”abc”, const char *str6=”abc”;char *str7=”abc”,char *str8 = “abc”,str5==str6 str7==str8为TRUE,因为”abc”是位于文字常量区的,系统会将几个“abc”进行优化,使它们位于同一块内存区,因此指针的指向也就相同了。
4、以下函数能求出数组的长度吗?
void fun(char str[])
{
int len = sizeof(str)/sizeof(str[0]);
}
答:不能,数组作为参数传递给函数时,数组名被退化为指针,因此函数中的sizeof(str)实际是在求一个指针的sizeof,答案为4,因此不能计算出数组的长度。
5、一个32位的机器,该机器的指针是多少位?
答:指针是多少位只要看地址总线的位数就行了,80386以后的机子都是32的数据总线。所以指针的位数就是4个字节。即有void *p; 则sizeof(p) = 4。
6、C和C++中的struct和class有什么不同?
答:C和C++中struct的区别是C中的struct不能有成员函数,而C++中的struct可以。C++中struct和class的主要区别是默认的存取权限,struct的默认存取权限为public,而class的默认存取权限为private。
7、类的静态成员和非静态成员有何区别?
答:类的静态成员每个类只有一个,静态成员为所有类的实例对象共享,静态成员有静态成员变量和静态成员函数,静态成员变量使用前必须初始化,静态成员变量可以被静态成员函数和非静态成员函数访问,而静态成员函数只能访问静态成员变量,因为静态成员函数属于类,其没有this指针。非静态成员每个对象都有一个。
8、纯虚函数的定义?
答:virtual void fun()=0;含有纯虚函数的类为抽象类,抽象类不能实例化对象,但是可以定义指针,纯虚函数是接口,由子类实现。
9、请讲一讲析构函数和虚函数的用法和作用?
答:析构函数是用于在撤销对象时完成对对象的清理工作,比如在创建对象时,如果在构造函数中动态申请了内存,那么在对象释放时,应该在析构函数中对动态申请的内存进行释放,避免造成内存泄露,如果在这个时候还不释放就没有机会释放内存了,会造成内存泄露,总之需要在释放对象之前完成的工作都可以放在析构函数中完成,析构函数不需要用户显示调用,它会在释放对象前由系统自动调用。虚函数是实现多态性的方式,虚函数在子类中被重写,因此可以通过基类指针调用不同子类的虚函数,实现一个接口,多种实现。正是因为多态性的存在,为了使子类的析构函数随时都能够执行,基类的析构函数一般都声明为虚析构函数。
10、全局变量和局部变量有什么区别?是怎么实现的?操作系统和编译器是怎么知道的?
答:区别在于它们的作用域不同,全局变量可以在整个程序被使用,局部变量只能在子程序或函数中使用,函数执行完后,局部变量的也被销毁了。操作系统和编译器可能是通过它们所分配的内存区来知道的,全局变量被放在全局数据区,而局部变量放在堆栈中。
11、若类A和类B没有继承关系,对于函数void func(A&),请至少用两种不同方法说明如何才能传递一个非常量的B类对象非func函数。
答:可在A类中定义一个构造函数 A(const B&)
或在B类中定义一个自动转换函数:operator A() const
12、static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
答:static全局变量与普通的全局变量的区别:前者在主函数之前就要被初始化,而后者没有要求,两者的作用域不同,前者的作用域只限于子模块(子程序或函数),而后者在整个程序中都可以被使用。
static局部变量和普通局部变量的区别:一个函数中的static变量值会保留到该函数下次调用来改变它,而后者在函数运行完后就被销毁了,两者的存储区域不同,前者存储在静态区(全局区),后者的内存位于堆栈上。
static函数与普通函数:static函数可以直接通过类调用,不需要在此之前实例化对象,而普通函数需要先定义对象。static函数不能用非static成员。static在循环中定义并赋值时,定义过程只进行一次,而不是每个循环1次。
13、写程序,从键盘上输入一系列整数,以输入-1为结束,将输入的数据保存到文件data.txt中。
答:C语言实现:
#include <stdio.h>
int main()
{
FILE *fp;
if ((fp=fopen("data.txt","wb")) == NULL)
{
cout<<"open error"<<endl;
exit(1);
}
int x;
scanf(“%d”, &x);
while (x!=-1)
{
fputc(x, fp);
cin>>x;
}
fclose(fp);
return 0;
}
C++实现:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ofstream fout("data1.txt");
if (!fout)
{
exit(1);
}
int x;
cin>>x;
while (x != -1)
{
fout<<x<<' ';
cin>>x;
}
fout.close();
return 0;
}
14、写程序,将一个字符串倒序?
答:直接在main函数中实现的
void main()
{
char *source = "hello";
char *des;
int len = strlen(source);
des = (char *)malloc(len+1); //申请空间必须是len+1,加1是为了放结束符
if (!des)
{
exit(1);
}
char *s = &source[len-1];
char *d = des;
while (len--!=0)
{
*d++ = *s--;
}
*d = '\0'; //必须要
cout<<source<<endl;
cout<<des<<endl;
}
15、static的用途?
答:(1)函数体内的静态变量,其值在函数的调用过程中保持不变。跟局部变量的区别。
(2)在函数体外定义的静态变量,限制了它的使用范围只在于该子模块,该子模块内的函数都能访问它,但是子模块外不能访问,实际就类似于是一个本地的全局变量。与一般全局变量的区别。
(3)类的静态成员函数。
本质上来说,static就是声明了对象的生成期,限制了对象的作用域。
或 (1)函数体内static变量的作用范围为该函数体,不同于auto变量,该变量的内存只能被分配一次,因此其值在下次函数调用时仍维持上次的值。
(2)在模块内的static全局变量可以被模块内的所有函数访问,但不能被模块外其他函数访问。
(3)在模块内的static函数只可被这一模块内的其他函数调用,这个函数的使用范围被限制在声明它的模块。
(4)在类中的static成员变量属于整个类所有,对类的所有对象只有一份拷贝。
(5)在类中的static成员函数属于整个类所有,这个函数不接受this指针,因而只能访问类的static成员变量。
16、在C++程序中调用C编译后的函数,为什么要加extern C的声明?
答:因为C++支持函数重载,而C不支持函数重载。函数被C++编译后在库中的名字与C语言的不同。假设某个函数的原型为:void foo(int x, int y);该函数被C编译器编译后在库中的名字为_foo,而C++编译器则产生像_foo_int_int之类的名字。C++提供了C连接交换指定符号 extern C来解决名字匹配问题。
17、float x与零值的比较,指针p与NULL的比较,布尔变量flag与TRUE的比较
答:(1)const float EPSION = 0.00001;
if (x >= -EPSION && x <= EPSION)
(2) if (p == NULL)
(3) if (flag)
18、C++中哪些函数不能被声明为虚函数?
答:普通函数(非成员函数),构造函数,内联成员函数、静态成员函数、友元函数。
(1)虚函数用于基类和派生类,普通函数所以不能
(2)构造函数不能是因为虚函数采用的是虚调用的方法,允许在只知道部分信息的情况的工作机制,特别允许调用只知道接口而不知道对象的准确类型的方法,但是调用构造函数即使要创建一个对象,那势必要知道对象的准确类型。
(3)内联成员函数的实质是在调用的地方直接将代码扩展开
(4)继承时,静态成员函数是不能被继承的,它只属于一个类,因为也不存在动态联编等
(5)友元函数不是类的成员函数,因此也不能被继承
19、include <filename.h>和include “filename.h”的区别?
答:<>是从标准库路径搜索, “”是从用户当前工作目录开始,找不到,在到标准库开始
20、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”, 注意GetMemory函数中的p参数是指向指针的指针,如果是一级指针则出现错误,不会得到申请的地址空间。
21.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 函数会有什么样的结果?
答:运行出错,注意与20中参数p的类型比较,20中是char **p,而本题是char *p。而且像这种情况还会导致每次都泄露一块内存的危险。
22、char *GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}
请问运行Test 函数会有什么样的结果?
答:无效的指针,输出不确定,因为p是函数GetMemory中申请的是一个临时变量,函数调用完后,其空间已经不再存在。
23.char *GetMemory3(int num)
{
char *p = (char *)malloc(sizeof(char) * num);
return p;
}
void Test3(void)
{
char *str = NULL;
str = GetMemory3(100);
strcpy(str, "hello");
cout<< str << endl;
free(str);
}
请问运行Test 函数会有什么样的结果?
答:输出”hello”,因为是返回动态申请的内存,只要不释放内存,即调用free函数,就可以使用该段内存。
24.char *GetString2(void)
{
char *p = "hello world";
return p;
}
void Test5(void)
{
char *str = NULL;
str = GetString2();
cout<< str << endl;
}
答:函数Test5运行虽然不会出错,但是函数GetString2的设计概念却是错误的。因为GetString2内的“hello world”是常量字符串,位于静态存储区,它在程序生命期内恒定不变。无论什么时候调用GetString2,它返回的始终是同一个“只读”的内存块。如果此时还想利用strcpy往str中写数据时,将出现错误。如strcpy(str,”hello world”)。
25、编写strlen函数
答:
int Strlen(const char *str)
{
int len = 0;
assert(str != NULL);
while (*str++ != '\0')
{
len++;
}
return len;}
非空判断是必须进行的操作,可以使用断言的方式assert(str) != NULL才会继续
26、编写strcpy函数
答: char *StrCopy(char *strDes, const char *strSrc)
{
assert((strDes != NULL) && (strSrc != NULL));
char *address = strDes;
while ((*strDes++ = *strSrc++) != '\0')
;
return address;
}
首先必须判断两个指针是否为空,由于复制后的指针需要返回,因此需要一个指针来记录地址的初始值,最后将复制的结果返回是为了进行链式操作。
27、C语言的关键字
28、什么是定义?什么是声明?它们的区别?
答:定义创建了对象并为这个对象分配了内存,声明没有分配内存。
29、最宽宏大量的关键字 auto
最快的关键字 register
最名不副实的关键字static,其作用包括,定义静态全局变量,静态局部变量,修饰函数限制函数的作用域为该函数所在的文件,其他文件不能访问。
30、字符串与整数之间的转换。
31、字符串循环右移n位。
32、栈的生长方向是向低地址扩展,而堆是向高地址扩展。
33、什么是“引用”?申明和使用“引用”要注意哪些问题?
答:引用就是某个目标变量的“别名”(alias),对引用的操作与对变量直接操作效果完全相同。申明一个引用的时候,切记要对其进行初始化。引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,不能再把该引用名作为其他变量名的别名。声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。不能建立数组的引用。
34、将“引用”作为函数参数有哪些特点?
答:(1)传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。
(2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。
(3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。
35、在什么时候需要使用“常引用”?
答:如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。常引用声明方式:const 类型标识符 &引用名=目标变量名。
36、Heap和Stack的区别?
答:Heap是堆,Stack是栈。
栈的空间由操作系统自动分配和回收,而堆上的空间由程序员申请和释放。
栈的空间大小较小,而堆的空间较大。
栈的地址空间往低地址方向生长,而堆向高地址方向生长。
栈的存取效率更高。
程序在编译期间对变量和函数的内存分配都在栈上,且程序运行过程中对函数调用中参数的内存分配也是在栈上。
37、宏定义,将整形变量a的第n位清零,其他位不变。
答:#define clear_bit(a,n) a=((a|(int)pow(2,n-1))!=a)?a:a^(int)pow(2,n-1))
首先判断数a的第n位本身是否为零,如果为零,则与2的n-1次方或运算后肯定不等于数a,此时就不需要清零,直接返回a即可,否则,将数a与2的n-1次方进行异或运算。
38、unsigned short A = 10;
printf(“%u\n”, ~A);
char ch = 128;
printf(“%d\n”, ch);
输出的结果是多少,并分析过程?
答:~A=4294967285,首先将A转化为int类型,即对应的二进制数值为:00000000 00000000 00000000 00001010,~A=11111111 11111111 11111111 11110101,其实这种情况最高位是1,认为是负数,但是在输出中指定以无符号数输出,于是结果为4294967285=4294967295(四字节表示的最大数)-10.
ch = 128对应的二进制为:10000000,在输出中以整数形式输出,由于最高位是1,于是就是负数,10000000是该负数的补码,根据求补码的反步骤计算,先-1,得到01111111,在取反得10000000=128,由于本身是负数,即为-128.
38、sizeof和strlen之间的区别?
答:(1)sizeof操作符的结果类型是size_t,它在头文件中的typedef为unsigned int类型,该类型保证能容纳实现所建立的最大对象的字节大小。
(2)sizeof是运算符,strlen是函数
(3)sizeof可以用类型做参数,strlen只能用char *做参数,且必须是以’\0’结尾的。
(4)数组做sizeof的参数不退化,传递给strlen就退化为指针。
(5)大部分编译程序在编译的时候就把sizeof计算过了,是类型或是变量的长度。
(6)strlen的结果要在运行的时候才能计算出来,用来计算字符串的长度,而不是类型占用内存的大小。
(7)sizeof后如果是类型必须加括号,如果是变量名可以不加括号。
(8)当使用了一个结构类型或变量时,sizeof返回实际的大小。
(9)数组作为参数传递给函数时传的是指针而不是数组,传递的是数组的首地址。
(10)计算结构变量的大小就必须讨论数组对齐问题。
(11)sizeof操作符不能用于函数类型,不完全类型或位字段。
39、sizeof的使用场合?
答:(1)sizeof操作符的一个主要用途是与存储分配和I/O系统那样的例程进行通信。
(2)用它可以看看某种类型的对象在内存中所占的单元字节。
(3)在动态分配一对象时,可以让系统知道要分配多少内存。
(4)便于一些类型的扩充。
(5)由于操作数的字节数在实现时可能出现变化,建议在涉及到操作数字节大小时用sizeof代替常量计算。
(6)如果操作数是函数中的数组形参或函数类型的形参,sizeof给出其指针的大小。
40、内联函数和宏的差别?
答:内联函数和普通函数相比可以加快程序运行的速度,因为不需要中断调用,在编译的时候内联函数可以直接被镶嵌到目标代码中,而宏只是一个简单的替换。内联函数要做参数类型检查,这是与宏相比的优势。
Inline是指嵌入代码,就是在调用函数的地方不是跳转,而是把代码直接写到那里去。对于短小的代码来说,inline可以带来一定效率的提升,而且和C时代的宏函数相比,inline更安全可靠。可是这是以增加空间消耗为代价的。
Inline一般只适用于:一个函数被不断地重复调用;函数只有简单的几行,且函数内不能含有for while switch语句。
41、文件操作函数?
答:FILE *fp
fopen(“filename”, “rwatb+”)
char ch ch = fgetc(fp) fputc(ch, fp)
char str[n] fgets(str, n, fp) fputs(str, fp)
fread(buffer, size, count, fp) fwrite(buffer, size, count, fp)
fscanf(fp, “%c”, &ch) fprintf(fp, “%d”, ch)
fclose(fp)
rewind(fp)
fseek(fp, 偏移长度,SEEK_SET/SEEK_CUR/SEEK_END)
feof(fp)
42.请说出const与#define 相比,有何优点?
答案:1) const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。
2)有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。
43. inline函数和用macro(宏)定义的函数之间有什么区别?
答案:由于inline函数具有内部链接,因此数个文件定义相同名字的内联函数不会发生冲突,而类函数宏就不行,会产生重复定义。
inline函数是真正的函数,可以由语句组成;但类函数宏所作的只是替换,不是真正的函数,当然也不能有语句。
macro定义
只是很初级的一种代换,实现的功能很单一而且安全性很差,比如类型错误、括号漏写都会造成很大的错误, 而且错误不容易被发现,隐患很大。
inline函数
内联函数要比前者好很多功能也要全面很多!最主要的是:内联函数能够进行安全检查(比如参数类型 等)
44. 简述数组与指针的区别?
答案:数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。指针可以随时指向任意类型的内存块。
(1)修改内容上的差别
char a[] = “hello”;
a[0] = ‘X’;
char *p = “world”; // 注意p 指向常量字符串
p[0] = ‘X’; // 编译器不能发现该错误,运行时错误
(2) 用运算符sizeof 可以计算出数组的容量(字节数)。sizeof(p),p 为指针得到的是一个指针变量的字节数,而不是p所指的内存容量。C++/C 语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。
char a[] = "hello world";
char *p = a;
cout<< sizeof(a) << endl; // 12 字节
cout<< sizeof(p) << endl; // 4 字节
计算数组和指针的内存容量
void Func(char a[100])
{
cout<< sizeof(a) << endl; // 4 字节而不是100 字节
}
45. 重载(overload)和重写(overried,有的书也叫做“覆盖”)的区别?
从定义上来说:
重载:是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。
重写:是指子类重新定义复类虚函数的方法。
从实现原理上来说:
重载:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。如,有两个同名函数:function func(p:integer):integer;和function func(p:string):integer;。那么编译器做过修饰后的函数名称可能是这样的:int_func、str_func。对于这两个函数的调用,在编译器间就已经确定了,是静态的。也就是说,它们的地址在编译期就绑定了(早绑定),因此,重载和多态无关!
重写:和多态真正相关。当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的(晚绑定)。
46. New delete 与malloc free 的联系与区别?
答案:都是在堆(heap)上进行动态的内存操作。用malloc函数需要指定内存分配的字节数并且不能初始化对象,new 会自动调用对象的构造函数。delete 会调用对象的destructor,而free 不会调用对象的destructor.
47. 结构与联合有和区别?
答案:1).结构和联合都是由多个不同的数据类型成员组成,但在任何同一时刻,联合中只存放了一个被选中的成员(所有成员共用一块地址空间),而结构的所有成员都存在(不同成员的存放地址不同)
2).对于联合的不同成员赋值,将会对其它成员重写,原来成员的值就不存在了,而对于结构的不同成员赋值是互不影响的
48. C++中的什么是多态性? 是如何实现的?
多态性是面向对象程序设计语言继数据抽象和继承之后的第三个基本特征。它是在运行时出现的多态性通过派生类和虚函数实现。基类和派生类中使用同样的函数名, 完成不同的操作具体实现相隔离的另一类接口,即把" w h a t"从"h o w"分离开来。多态性提高了代码的组织性和可读性,虚函数则根据类型的不同来进行不同的隔离
49. 什么是动态特性?
在绝大多数情况下, 程序的功能是在编译的时候就确定下来的, 我们称之为静态特性。 反之, 如果程序的功能是在运行时刻才能确定下来的, 则称之为动态特性。C++中, 虚函数,抽象基类, 动态绑定和多态构成了出色的动态特性。
50.什么是封装?C++中是如何实现的?
封装来源于信息隐藏的设计理念, 是通过特性和行为的组合来创建新数据类型让接口与具体实现相隔离。C++中是通过类来实现的, 为了尽量避免某个模块的行为干扰同一系统中的其它模块,应该让模块仅仅公开必须让外界知道的接口。
51. 什么是RTTI?
RTTI事指运行时类型识别(Run-time type identification)在只有一个指向基类的指针或引用时确定一个对象的准确类型
52. 什么是拷贝构造函数?
它是单个参数的构造函数,其参数是与它同属一类的对象的(常)引用;类定义中,如果未提供自己的拷贝构造函数,C++提供一个默认拷贝构造函数,该默认拷贝构造函数完成一个成员到一个成员的拷贝
53. 什么是深浅拷贝?
浅拷贝是创建了一个对象用一个现成的对象初始化它的时候只是复制了成员(简单赋值)而没有拷贝分配给成员的资源(如给其指针变量成员分配了动态内存); 深拷贝是当一个对象创建时,如果分配了资源,就需要定义自己的拷贝构造函数,使之不但拷贝成员也拷贝分配给它的资源。
54.面向对象程序设计的优点
开发时间短, 效率高, 可靠性高。面向对象编程的编码具有高可重用性,可以在应用程序中大量采用成熟的类库(如STL),从而虽短了开发时间,软件易于维护和升级。
55.写出判断ABCD四个表达式的是否正确, 若正确, 写出经过表达式中 a的值(3分)
int a = 4; (A)a += (a++); (B) a += (++a) ;(C) (a++) += a;(D) (++a) += (a++); a = ?
56.MFC中CString是类型安全类么?
答:不是,其它数据类型转换到CString可以使用CString的成员函数Format来转换
57.C++中为什么用模板类。
答:(1)可用来创建动态增长和减小的数据结构
(2)它是类型无关的,因此具有很高的可复用性。
(3)它在编译时而不是运行时检查数据类型,保证了类型安全
(4)它是平台无关的,可移植性
(5)可用于基本数据类型
58.CSingleLock是干什么的。
答:同步多个线程对一个数据类的同时访问
59.NEWTEXTMETRIC 是什么。
答:物理字体结构,用来设置字体的高宽大小
60.程序什么时候应该使用线程,什么时候单线程效率高。
答:1.耗时的操作使用线程,提高应用程序响应
2.并行操作时使用线程,如C/S架构的服务器端并发线程响应用户的请求。
3.多CPU系统中,使用线程提高CPU利用率
4.改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独
立的运行部分,这样的程序会利于理解和修改。
其他情况都使用单线程。
61.Windows是内核级线程么。
答:见下一题
62.Linux有内核级线程么。
答:线程通常被定义为一个进程中代码的不同执行路线。从实现方式上划分,线程有两
种类型:“用户级线程”和“内核级线程”。 用户线程指不需要内核支持而在用户程序
中实现的线程,其不依赖于操作系统核心,应用进程利用线程库提供创建、同步、调度
和管理线程的函数来控制用户线程。这种线程甚至在象 DOS 这样的操作系统中也可实现
,但线程的调度需要用户程序完成,这有些类似 Windows 3.x 的协作式多任务。另外一
种则需要内核的参与,由内核完成线程的调度。其依赖于操作系统核心,由内核的内部
需求进行创建和撤销,这两种模型各有其好处和缺点。用户线程不需要额外的内核开支
,并且用户态线程的实现方式可以被定制或修改以适应特殊应用的要求,但是当一个线
程因 I/O 而处于等待状态时,整个进程就会被调度程序切换为等待状态,其他线程得不
到运行的机会;而内核线程则没有各个限制,有利于发挥多处理器的并发优势,但却占
用了更多的系统开支。
Windows NT和OS/2支持内核线程。Linux 支持内核级的多线程
63.C++中什么数据分配在栈或堆中,New分配数据是在近堆还是远堆中?
答:栈: 存放局部变量,函数调用参数,函数返回值,函数返回地址。由系统管理
堆: 程序运行时动态申请,new 和 malloc申请的内存就在堆上
64.使用线程是如何防止出现大的波峰。
答:意思是如何防止同时产生大量的线程,方法是使用线程池,线程池具有可以同时提
高调度效率和限制资源使用的好处,线程池中的线程达到最大数时,其他线程就会排队
等候。
65函数模板与类模板有什么区别?
答:函数模板的实例化是由编译程序在处理函数调用时自动完成的,而类模板的实例化
必须由程序员在程序中显式地指定。
66一般数据库若出现日志满了,会出现什么情况,是否还能使用?
答:只能执行查询等读操作,不能执行更改,备份等写操作,原因是任何写操作都要记
录日志。也就是说基本上处于不能使用的状态
67 SQL Server是否支持行级锁,有什么好处?
答:支持,设立封锁机制主要是为了对并发操作进行控制,对干扰进行封锁,保证数据
的一致性和准确性,行级封锁确保在用户取得被更新的行到该行进行更新这段时间内不
被其它用户所修改。因而行级锁即可保证数据的一致性又能提高数据操作的迸发性
68.如果数据库满了会出现什么情况,是否还能使用?
答:见66
69 关于内存对齐的问题以及sizof()的输出
答:编译器自动对齐的原因:为了提高程序的性能,数据结构(尤其是栈)应该尽可能
地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问
;然而,对齐的内存访问仅需要一次访问
70. int i=10, j=10, k=3; k*=i+j; k最后的值是?
答:60,此题考察优先级,实际写成: k*=(i+j);,赋值运算符优先级最低
71.对数据库的一张表进行操作,同时要对另一张表进行操作,如何实现?
答:将操作多个表的操作放入到事务中进行处理
72.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状态,完成三次握手
73.ICMP是什么协议,处于哪一层?
答:Internet控制报文协议,处于网络层(IP层)
74.触发器怎么工作的?
答:触发器主要是通过事件进行触发而被执行的,当对某一表进行诸如UPDATE、 INSERT
、 DELETE 这些操作时,数据库就会自动执行触发器所定义的SQL 语句,从而确保对数
据的处理必须符合由这些SQL 语句所定义的规则
75.winsock建立连接的主要实现步骤?
答:服务器端:socker()建立套接字,绑定(bind)并监听(listen),用accept()
等待客户端连接。
客户端:socker()建立套接字,连接(connect)服务器,连接上后使用send()和recv(
),在套接字上写读数据,直至数据交换完毕,closesocket()关闭套接字。
服务器端:accept()发现有客户端连接,建立一个新的套接字,自身重新开始等待连
接。该新产生的套接字使用send()和recv()写读数据,直至数据交换完毕,closesock
et()关闭套接字。
76.动态连接库的两种方式?
答:调用一个DLL中的函数有两种方法:
1.载入时动态链接(load-time dynamic linking),模块非常明确调用某个导出函数
,使得他们就像本地函数一样。这需要链接时链接那些函数所在DLL的导入库,导入库向
系统提供了载入DLL时所需的信息及DLL函数定位。
2.运行时动态链接(run-time dynamic linking),运行时可以通过LoadLibrary或Loa
dLibraryEx函数载入DLL。DLL载入后,模块可以通过调用GetProcAddress获取DLL函数的
出口地址,然后就可以通过返回的函数指针调用DLL函数了。如此即可避免导入库文件了
77.IP组播有那些好处?
答:Internet上产生的许多新的应用,特别是高带宽的多媒体应用,带来了带宽的急剧
消耗和网络拥挤问题。组播是一种允许一个或多个发送者(组播源)发送单一的数据包
到多个接收者(一次的,同时的)的网络技术。组播可以大大的节省网络带宽,因为无
论有多少个目标地址,在整个网络的任何一条链路上只传送单一的数据包。所以说组播
技术的核心就是针对如何节约网络资源的前提下保证服务质量。
如有错别字或其他错误之处,请指出以方便修改!!