1. charc = '\72'; 中的\72代表一个字符,72是八进制数,代表ASCII码字符“:”。
2. 10*a++ 中a先进行乘法运算再自增(笔试中经常喜欢出这类运算符优先级容易混淆的输出问题)。
3. const和static的作用
太常见的问题了,下面给出一个较详细的参考答案:
static关键字:
1)函数体内static变量的作用范围为函数体。不同于auto变量。该变量的内存只被分配一次。因此其值在下次调用时仍维持上次的值。
2)在模块内的static全局变量可以被模块内的所有函数访问。但不能被模块外的其他函数访问。
3)在模块内的static函数只可被这一模块内的其它函数调用。这个函数的使用范围被限制在声明它的模块内。
4)在类中的static成员变量属于整个类所有,对类的所有对象只有一份复制。
5)在类中的static成员函数属于整个类所有,这个函数不接受this指针,因而只能访问类的static成员变量。
const关键字:
1)欲阻止一个变量被改变,可以使用const关键字。在定义该const变量时,通常需要对它进行初始化。因为以后就没有机会再改变它了。
2)对指针来说,可以指定指针的本身为const,也可以指定指针所指向的数为const。或二者同时为const。
3)在一个函数的声明中,const可以修饰形参,表明它是一个输入参数。在函数内不能改变其值。
4)对于类的成员函数,若指定其为const类型。则表明其是一个常量函数。不能修改类的成员变量。
5)对于类的成员函数,有时候必须指定其返回值为const类型。以使得其返回值不为“左值”。
4. 注意sizeof不是函数而是运算符,所以在计算变量所占用空间大小时,括号是可以省略的,但在计算类型大小时括号则不能省略,比如int i = 0; 则sizeof int是错误的。
5. 有1,2,…,n的无序数组,求排序算法,并且要求时间复杂度为O(n),空间复杂度O(1),使用交换,而且一次只能交换两个数。
#include
int main(){
inta[] = {10, 6, 9, 5, 2, 8, 4, 7, 1, 3};
inti, tmp;
intlen = sizeof(a) / sizeof(a[0]);
for(i= 0; i < len;) {
tmp = a[a[i] - 1];
a[a[i] - 1] = a[i];
a[i] = tmp;
if(a[i] == i + 1) i++;
}
for(i= 0; i < len; ++i)
printf("%d ",a[i]);
printf("\n");
return0;
}
6. 易误解:如果inta[5], 那么a与&a是等价的,因为两者地址相同。
解答:一定要注意a与&a是不一样的,虽然两者地址相同,但意义不一样,&a是整个数组对象的首地址,而a是数组首地址,也就是a[0]的地址,a的类型是int[5],a[0]的类型是int,因此&a+1相当于a的地址值加上sizeof(int) * 5,也就是a[5],下一个对象的地址,已经越界了,而a+1相当于a的地址加上sizeof(int),即a[1]的地址。
7. 如何将一个小数分解成整数部分和小数部分?
要记得利用头文件中的库函数modf,下面是函数原型(记住一些实用的库函数,避免自己重写):
double modf(doublenum, double *i); // 将num分解为整数部分*i和小数部分(返回值决定)
8. 可作为函数重载判断依据的有:参数个数、参数类型、const修饰符;
不可以作为重载判断依据的有:返回类型。
9. 程序输出题:
inta[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int*p = &(a + 1)[3];
printf("%d\n", *p);
输出:5
说明:因为a+1指向a的第二个元素,[3]表示再向后移动3个元素。
10.程序输出题:
charstr1[] = "abc";
charstr2[] = "abc";
constchar str3[] = "abc";
constchar str4[] = "abc";
constchar *str5 = "abc";
constchar *str6 = "abc";
char*str7 = "abc";
char*str8 = "abc";
cout<< (str1 == str2) << endl;
cout<< (str3 == str4) << endl;
cout<< (str5 == str6) << endl;
cout<< (str7 == str8) << endl;
输出:0 0 1 1
说明:输出str1~str8的地址为:
0x23aa80
0x23aa70
0x23aa60
0x23aa50
0x23aa48
0x23aa40
0x23aa38
0x23aa30
输出str1~str8内容“abc”的存储地址为:
0x23aa80
0x23aa70
0x23aa60
0x23aa50
0x100403030
0x100403030
0x100403030
0x100403030
可以发现str1~str4中的内容是存在栈上,地址各不相同,而str5~str8的内容都是存储在常量区,所以地址都相同。
注意:
char *str ="abc";
printf("%p\n",str1);
cout<< &str1 << endl;
上面打印的是字符串 “abc”的地址,下面打印的是 str1 变量的地址。
11.C的结构体和C++结构体的区别
(1)C的结构体内不允许有函数存在,C++允许有内部成员函数,且允许该函数是虚函数。所以C的结构体是没有构造函数、析构函数、和this指针的。
(2)C的结构体对内部成员变量的访问权限只能是public,而C++允许public,protected,private三种。
(3)C语言的结构体是不可以继承的,C++的结构体是可以从其他的结构体或者类继承过来的。
以上都是表面的区别,实际区别就是面向过程和面向对象编程思路的区别:
C的结构体只是把数据变量给包裹起来了,并不涉及算法。
而C++是把数据变量及对这些数据变量的相关算法给封装起来,并且给对这些数据和类不同的访问权限。
C语言中是没有类的概念的,但是C语言可以通过结构体内创建函数指针实现面向对象思想。
12.如何在类中定义常量成员并为其初始化?
解答:只能在初始化列表里对const成员初始化,像下面这样:
class CBook{
public:
constdouble m_price;
CBook() :m_price(8.8) { }
};
下面的做法是错误的:
class CBook{
public:
constdouble m_price;
CBook() {
m_price = 8.8;
}
};
而下面的做法虽未报错,但有个warning,也不推荐:
class CBook{
public:
constdouble m_price = 8.8; // 注意这里若没有const则编译出错
CBook() { }
};
13.在定义类的成员函数时使用mutable关键字的作用是什么?
解答:当需要在const方法中修改对象的数据成员时,可以在数据成员前使用mutable关键字,防止出现编译出错。例子如下:
class CBook{
public:
mutabledouble m_price; // 如果不加就会出错
CBook(double price) :m_price(price) { }
doublegetPrice() const; // 定义const方法
};
doubleCBook::getPrice() const {
m_price = 9.8;
returnm_price;
}
14.构造函数、拷贝构造函数、析构函数的调用点和顺序问题,如下面这个例子输出是什么?
class CBook{
public:
CBook() {
cout << "constructoris called.\n";
}
~CBook() {
cout << "destructor iscalled.\n";
}
};
voidinvoke(CBook book) { // 对象作为函数参数,如果这里加了个&就不是了,因为加了&后是引用方式传递,形参和实参指向同一块地
// 址,就不需要创建临时对象,也就不需要调用拷贝构造函数了
cout<< "invoke is called.\n";
}
int main(){
CBook c;
invoke(c);
}
解答:注意拷贝构造函数在对象作为函数参数传递时被调用,注意是对象实例而不是对象引用。因此该题输出如下:
constructor is called.
invoke is called.
destructor is called. // 在invoke函数调用结束时还要释放拷贝构造函数创建的临时对象,因此这里还调用了个析构函数
destructor is called.
引申:拷贝构造函数在哪些情况下被调用?
(1)函数的参数为类对象且参数采用值传递方式;
(2)将类对象做为函数的返回值。
15.C++中的explicit关键字有何作用?
解答:禁止将构造函数作为转换函数,即禁止构造函数自动进行隐式类型转换。
例如CBook中只有一个参数m_price,在构建对象时可以使用CBook c = 9.8这样的隐式转换,使用explicit防止这种转换发生。
16.在C++中,如果确定了某一个构造函数的创建过程,在该构造函数中如果调用了其它重载的构造函数,它将不会执行其它构造函数的初始化列表部分代码,而是执行函数体代码,此时已经退化成普通函数了。例子说明如下:
class CBook{
public:
doublem_price;
CBook() {
CBook(8.8);
}
CBook(double price) : m_price(price) { }
};
int main(){
CBook c;
cout<< c.m_price << endl; // 此时并不会输出理想中的8.8
}
17.静态数据成员只能在全局区域进行初始化,而不能在类体中进行(构造函数中初始化也不行),且静态数据成员不涉及对象,因此不受类访问限定符的限制。
例子说明如下:
class CBook{
public:
staticdouble m_price;
};
doubleCBook::m_price = 8.8; // 只能在这初始化,不能在CBook的构造函数或直接初始化
18.C++中可以重载的运算符:new/delete、new[]/delete[]、++等。
可以重载的运算符:、.、::、?:、sizeof、typeid、.、**、不能改变运算符的优先级。
引申:重载++和–时是怎么区分前缀++和后缀++的?
例如当编译器看到++a(先自增)时,它就调用operator++(a);
但当编译器看到a++时,它就调用operator++(a,int)。即编译器通过调用不同的函数区别这两种形式。
19.C++的多态性分为静态多态和动态多态。
静态多态性:编译期间确定具体执行哪一项操作,主要是通过函数重载和运算符重载来实现的;
动态多态性:运行时确定具体执行哪一项操作,主要是通过虚函数来实现的。
20.虚函数原理考点,例如下面程序的输出是什么?
class A {
public:
virtualvoid funa();
virtualvoid funb();
voidfunc();
staticvoid fund();
staticint si;
private:
inti;
charc;
};
问:sizeof(A) = ?
解答:
关于类占用的内存空间,有以下几点需要注意:
(1)如果类中含有虚函数,则编译器需要为类构建虚函数表,类中需要存储一个指针指向这个虚函数表的首地址,注意不管有几个虚函数,都只建立一张表,所有的虚函数地址都存在这张表里,类中只需要一个指针指向虚函数表首地址即可。
(2)类中的静态成员是被类所有实例所共享的,它不计入sizeof计算的空间
(3)类中的普通函数或静态普通函数都存储在栈中,不计入sizeof计算的空间
(4)类成员采用字节对齐的方式分配空间
答案:12(32位系统)或16(64位系统)
21.虚继承的作用是什么?
在多继承中,子类可能同时拥有多个父类,如果这些父类还有相同的父类(祖先类),那么在子类中就会有多份祖先类。例如,类B和类C都继承与类A,如果类D派生于B和C,那么类D中就会有两份A。为了防止在多继承中子类存在重复的父类情况,可以在父类继承时使用虚函数,即在类B和类C继承类A时使用virtual关键字,例如:
class B : virtual public A
class C : virtual public A
注:因为多继承会带来很多复杂问题,因此要慎用。
22、在C++中参数传递只有值传递和引用传递,地址传递指的是指针传递,而指针传递本质上也是值传递(指针值)
23、假设x=9981,下面函数的返回值是?
int func(x)
{
int countx=0;
while(x)
{
countx++;
x=x&(x-1);
}
return countx;
}
先转2进制为10011011111101,每次x&(x-1)会让原来的1(从低位到高位依次)变为0。一共10个1,10次循环之后x为0,退出循环。
24、在C++中的结构体可以有构造函数
C中的结构体没有函数 但是C++的结构体可以有函数;这是C与C++结构体的区别。
C++的结构体可以被类取代,因为类相对于结构体 具有封装性等优势。
C++中结构体与类的区别:
结构体中的成员访问权限不声明时候默认是 公开的;而类 是私有的
25、静态多态(早绑定),如函数重载
动态多态(晚绑定),如虚函数,继承
26、父类指针指向子类对象,如果子类有指针数据成员,删除父类对象时会造成内存泄漏,解决方法时,将父类的析构函数定义成虚析构函数
27、virtual 不能修饰静态成员函数、内联函数和构造函数
28、父类和子类定义了同名的函数就是函数的隐藏
子类继承父类的虚函数就是函数的覆盖
29、没有数据成员的类,实例化时也有一个字节内存单元
30、虚函数表占用4个字节内存
31、继承抽象类时,如果没有对纯虚函数重新定义,则子类也是抽象类
32、ctrl+k+u取消注释
33、默认构造函数:class::class(){};
34、仅含有纯虚函数的类是接口类,没有数据成员,只有纯虚成员函数
35、typeid(*obj).name()打印obj对象的类型
36、dynamic_cast注意事项:
只能应用与指针和引用的转换
要转换的类型中必须包含虚函数
转换成功返回子类的地址,失败返回NULL
37、typeid注意事项:typeid返回一个type_info对象的引用
如果想通过基类的指针或的派生类的数据类型,基类必须带有虚函数
只能获取对象的实际类型
38、常见的异常:
数组下标越界,除数为0,内存不足(内存泄漏)
C++远征之模板篇
39、类的静态成员函数可以调用静态数据成员,但是不能调用非静态数据成员和非静态成员函数
静态数据成员必须单独初始化
静态数据成员只有一份,且不依赖对象而存在
静态成员函数不能加const
40、前置:Coordinate& operator ++();
后置:Coordinate operator++(int);
41、一元运算符重载,如果是类的成员函数,则不需要形参,如果是类的友元函数,则需要一个类类型的形参。
二元运算符重载,如果是类的成员函数,则需要一个形参,如果是类的友元函数,则需要两个形参。
42、索引运算符重载不可以是友元函数
43、大端模式:数据低位放在内存高位
小端模式:数据低位放在内存低位
44、构造函数中,成员变量一定要通过初始化列表来初始化的是:引用、const和没有默认构造函数的成员对象
45、不允许通过函数返回值重载函数
46、由多个源文件组成的C程序,经过编辑、预处理、编译,链接等阶段会生成最终的可执行程序。下面哪个阶段可以发现被调用的函数未定义?链接
47、对于内部数据类型来说,返回值是否是常量并没有关系处理用户定义的类型时,返回值是常量是很重要的,如果一个函数返回一个类对象的值,其值是常量,那么这个函数的返回值不能是一个左值(即它不能被赋值,也不能被修改)
48、
32位系统 64位系统 (单位Bytes)
char 1 1
short 2 2
int 4 4
指针 4 8
long 4 8
float 4 4
double 8 8
49、浮点数的比较不可以用==或者!=,判断浮点数是否相等:abs(a-b) 50、静态联编与动态联编:如果是通过对象名调用虚函数,在编译期间就能确定调用的是哪一个类的虚函数,所以属于静态关联;如果是通过基类指针调用虚函数,在编译阶段无法从语句本身确定调用哪一个类的虚函数,只有在运行时,pt指向某一个类对象后,才能确定调用的是哪一个类的虚函数,故为动态关联 51、关于格式化输入与输出,标准库定义了一组操作符来修改流的格式状态,这些操作符(如setprecision、setw())都定义在文件iomanip中。 52、在函数调用过程中,如果函数funA调用了函数funB,函数funB又调用了函数funA,则称为函数的间接递归调用 53、#pragma pack(2)强制设定为2字节对齐 54、enum占用4个字节空间 55、重载:只有在同一个类定义中的同名成员函数才存在重载关系,主要特点是函数的参数类型和数目有所不同,但不能出现函数参数的个数和类型均相同,重载和成员函数是否是虚函数无关 覆盖:在派生类中覆盖基类中的同名函数,要求两个函数的参数个数、参数类型、返回类型都相同,且基类函数必须是虚函数。 隐藏:派生类中的函数屏蔽了基类中的同名函数,两个函数参数相同,但基类函数不是虚函数(和覆盖的区别在于基类是否是虚函数)。两个函数参数不同,无论基类函数是否是虚函数,基类函数都会被屏蔽(和重载的区别在于两个函数不在同一个类中)。 56、答案:0个 57、在组合类的析构函数中并不需要显式调用其成员对象的析构函数,因为当执行组合类的析构函数时,其数据成员也会被销毁,对于类成员对象来说,成员对象销毁时,程序会自动调用其析构函数;不过对于组合类中new的指向类成员的指针,组合类需要自己去delete该指针; 在类继承层次中,基类在上,派生类在下,所以可以自动进行向上类型转换,即可以使基类指针和引用指向派生类对象,而不可以使派生类指针和引用指向基类对象。 58、数组名是指针常量,不能进行自加运算。 59、只有在使用时才为该类型变量分配内存的存储类说明是:auto和register 60、函数的形式参数隐含的存储类型说明是:auto 61、一个图的领接矩阵表示是唯一的,邻接表表示不唯一 62、C语言字符串以\0结束,\0在内存中的实际表示为0. 63、友元函数访问对象中的成员需要通过对象名,因为友元函数里不含this指针。 64、假设以邻接表作为图的存储结构,则深度优先遍历该图所得到的生成树是唯一的 65、赋值运算符只能作为类的成员函数重载 66、#define后面不加分号,typedef后面要加分号 typedef原类型名 新类型名 67、JAVA没有指针的概念,被封装起来了,而C++有; JAVA不支持类的多继承,但支持接口多继承,C++支持类的多继承; C++支持运算符重载,JAVA不支持; JAVA的内存管理比C++方便,而且错误处理也比较好; C++的速度比JAVA快 C++更适用于有运行效率要求的情况,JAVA适用于效率要求不高,但维护性要好的情况。 68、不能被重载的运算符:. \ .* \ :: \ ?: \ sizeof \ typeid 69、C++中,能作为函数重载判断依据的是:参数类型、参数个数、const 如果同时在类中,对于函数名相同的const函数和非const函数能够构成重载 70、Ab=a,这是定义了对象b,且以a对b进行初始化,这个时候要调用拷贝构造函数; 如果写成A a;A b;b=a;则是调用重载的赋值函数 还有两种情况是调用拷贝构造函数:1)一个对象以值传递的方式传入函数体;2)一个对象以值传递的方式从函数返回 71、对象成员的表示方法与结构体变量成员的表示方法相同 72、私有继承中基类的私有成员在派生类中还是私有的:FALSE 是不可见的,基类中的私有成员不能在子类中访问 73、位运算符的对象只能是整形或字符型数据 74、每个C语言程序文件的编译错误分为2类:编译错误和链接错误 75、静态存储变量具有局部的生存期:FALSE 76、引用数组元素,只要是整型就行,常量可以,变量也可以 77、类方法是指类中被static修饰的方法,无this指针 类方法是可以调用其它类的static方法的 可以在类方法中生成实例对象再调用实例方法 成员方法又称为实例方法 78、若已包含标准库头文件及相关命名空间,则系统不允许用户重新定义标准库函数 79、若使用一维数组名作为函数实参,则在主调函数中说明此数组的大小 80、在C++程序中,对象之间的相互通信通过调用成员函数实现。 81、chara[7] = "abcdef"; charb[4] = "ABC"; strcpy(a,b); printf("%c",a[5]); 输出为f strcpy_s遇到字符串结束符\0时结束复制,从初始位置开始复制,包括\0,覆盖原来的要复制的空间的内容。第六个元素是原来的f。 如果题设改为printf("%s\n",a),则结果为ABC 82、fclose()函数是C标准库函数,不是成员函数 83、字符串两种初始化 chars[10]=”right!”;(字符数组) char*sp=”right!”;(字符指针) 84、文件指针是程序中用FILE定义的指针变量,它指向的是一块内存区域,这块区域存储着打开的文件的相关信息,包括文件读取指针当前位置、文件读取缓存区大小等信息,并不是指向文件的;fscanf是从文件中格式化读取,fprintf才是向文件中格式化写入。 85、当一个对象的生命周期结束后,先调用派生类的析构函数,后调用基类的析构函数 86、一个共有派生类的对象在使用上可以被当作基类的对象,反之则禁止。 87、C语言程序中的整数不能是二进制整数 88、自动变量,只在定义他们的时候才创建,在定义他们的函数返回时系统回收变量所占的空间。对这些变量存储空间的分配和回收是由系统自动完成的。一般情况下,不做专门说明的局部变量,均是局部变量。自动变量也可用关键字auto作出说明 89、在所有类说明中内部定义的成员函数都是内联函数。 90、大文件表空间只能包含一个文件,但是文件可以达到4G个数据块 91、 92、 93、数组也是STL容器类型 94、在C的文件操作中,可以利用fseek函数进行文件指针的随机定位 95、实行常数,e/E前面必须有数字,后跟整数 96、char **s; *s=”computer”; 97、在同一个源文件中,外部变量与局部变量同名,则在局部变量的作用范围内,外部变量不起作用 98、a=(b=4)+(c=6)是一个合法的赋值表达式 99、%取余运算符的运算对象必须是整型数;/ 、*则没要求整形数 100、#pragma comment 将一个注释记录放置到对象文件或可执行文件中; #pragmapack 用来改变编译器的字节对齐 #pragmacode_seg 它能够设置程序中的函数在obj文件中所在的代码段。如果未指定参数,函数将设置在默认代码段.text中 #pragmaonce 保证所在文件只会被包含一次,它是基于磁盘文件的,而#ifndef则是基于宏的 101、代码生成阶段的主要任务是把中间代码变换成具体机器的目标代码 102、静态链表中指针表示的是下一个元素在数组中的位置 103、若在线性表中采用折半查找法查找元素,该线性表应该元素按值有序且采用顺序存储结构 104、单链表的存储密度小于1 105、栈是一种数据结构,但是链表不是一种数据结构,它是一种存储结构;线性表可以有顺序存储结构和链式存储结构,栈也可以有顺序存储结构和链式存储结构 106、采用二叉链表作为存储结构,树的前序遍历和其相应的二叉树的前序遍历的结果是一样的。 107、下面哪个不是线性表:关联数组 循环链表、队列、栈、关联数组、空字符串数组、双向链表 108、cin不是istream类的成员函数,cin表示标准输入的istream对象 109、C语言中只能逐个引用数组元素而不能一次引用整个数组 110、 111、下面哪种方法不能用于文本加密:MD5 RSA、RC4、MD5、DES 112、指针变量p进行自加运算(p++)后,地址偏移量为1,则其数据类型是char 113、对象引用做函数参数比用对象指针方便些 114、声明一个引用的同时,如果不是作为函数的参数或返回值,必须进行初始化,明确引用是哪个变量的别名,引用一旦成为某个变量的别名,在程序运行过程中不可改变这种指代关系。 115、栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存区域,栈顶的地址和栈的最大容量是系统预先规定好的,在Windows下,栈的大小是2M(也有的说是1M,总之就是一个确定的数),如果申请的空间超过栈的剩余空间时,将提示overflow。 堆:堆是向高地址扩展的数据结构,是不连续的内存区域。只是由于系统使用链表来存储的空闲内存地址的,而链表的遍历方向是低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存,由此可见,堆获得的空间比较灵活,也比较大。 116、const static数据成员可以在类内初始化,也可以在类外,不能在构造函数中初始化,也不能在构造函数的初始化列表中初始化; Static数据成员只能在类外,即类的实现文件中初始化,也不能在构造函数中初始化,不能在构造函数的初始化列表中初始化; Const数据成员只能在构造函数的初始化列表中初始化; 普通数据成员不能在类内初始化,可以在构造函数中初始化,也可以在构造函数的初始化列表中初始化。 117、内联函数一般用于加快程序执行速度,可能减小可执行文件大小,也可能增加可执行文件大小。 118、在C++STL中常用的容器和类型,下面那些支持下标“[]”运算:vector、deque、map、unordered_map、string vector、list、deque、map、set、unordered_map、unordered_set、stack、string 119、int(*ptr)[]是一个指向整形数组的指针,而int *ptr[]是指指针数组,ptr[]里面存的都是指针 120、一共有十五个优先级:1,(),[],->; 2,!,~,-(负号),++,--,&(取变量地址),*,(type)(强制类型),sizeof; 3,*,/,%; 4,+,-; 5,<<,>>; 6,>,>=,<=,<; 7,==,!= 8,&; 9,^ 10,|; 11,&&; 12,||; 13,?: 14,=,+=,-=,*=,/=,%=,|=,&=,&=,>>=,<<=; 15,, 结合性:2,13,14是从右至左,其他都是从左至右 121、++分为前置和后置,前置++比+运算符优先级高,后置比+运算符优先级低 122、有的运算符只能作为成员函数重载 123、只要是类的成员函数,都可以放在类内定义,编译器一般视为内联函数,但是,这种写法与我们追求的类的定义和实现相分离的目标背道相驰,所以不建议将类的函数实现写在类的内部。 124、通过一个对象调用虚函数时,C++系统对该调用采用静态联编 125、‘0’的ASCLL码是30H,48; 126、C++中使用模板类的原因: 1)可用来创建动态增加和减小的数据结构; 2)它是类型无关的,因此具有很高的可复用性; 3)它在编译时而不是运行时检查数据类型,保证了类型安全; 4)它是平台无关的,可移植性; 5)可用于基本数据类型 127、sizeof()是运算符,其值在编译时就计算好了,获得的是所建立的最大对象的字节大小,返回值与对象存储的内容没有关系; Strlen()是函数,其值需在运行时才能计算出,参数必须是(char*),返回的是字符串的长度,从代表该字符串的第一个地址开始遍历,直到遇到结束符NULL,返回长度不包括NULL,结束标志:x[i]=0;x[i]=’\0’ 128、void *memcpy(void *dest,const void* src,size_t n)功能:由src指向地址为起始地址的连续n个字节的数据复制到以dest指向地址为起始地址的空间内,函数返回一个指向dest的指针 129、派生类实例化时,先调用基类的构造函数,然后是派生类的类成员变量构造函数(构造顺序是按照成员变量的定义先后顺序,而不是按照初始化列表的顺序),最后是派生类的构造函数。 130、this指针 回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方法直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应 131、实际上只要是*data,我们就知道了它是指针,如果是32位机器,该指针就指着内存中的某个地址,用32位表示,记住这个32位只是初始地址,任何指针都是的。而前面的void 或者int 类型是定义一次读几个字节,如果是int则读4个字节,也就是从*data存的地址开始从内存往后读4个字节就行,而void是空,没有指定要读多少个字节,所以要用指针类型(unsigned int *)强制转化为知道要读几个字节的int指针,然后再用*从开始地址,读取unsigned int个字节出来! 132、重载多态和强制多态是指特定多态; 参数多态和包含多态是指通用多态。 在C++语言中,这种多态性可以通过强制多态、重载多态、类型参数化多态、包含多态4种形式来实现; 类型参数化多态和包含多态称为一般多态性,用来系统地刻画语义上相关的一组类型; 重载多态和强制多态称为特殊多态性,用来刻画语义上无关联的类型间的关系 133、对于C和C++来说是没有字符串这种数据类型的,只是可以通过字符数组或者指向字符的指针又或是C++的标准库string来实现存储字符串,但是这并不能称作定义了字符串变量 134、C语言中的文件类型只有ASCII码文件和二进制文件两种 135、若有格式输入函数scanf(“%d%d%d”,&x,&y,&z),输入数据时不能使用(逗号)作为数据的分隔符 空格、逗号、TAB(制表符)、回车 136、预处理可以包含:1)宏定义指令;2)条件编译指令;3)头文件包含指令;4)编译程序可以识别的特殊符号 C源程序中凡是以#标识的控制行为都是预处理指令 137、const对象只能调用const类型成员函数 构造函数不能是虚函数,析构函数可以是虚函数 138、哪些方式可以用于线程间同步:临界区、互斥区、事件、信号量 139、 140 141、关于new delete与malloc free的联系和区别: 用malloc函数需要指定内存分配的字节数并且不能初始化对象,new会自动调用对象的构造函数; delete会调用对象的destructor,而free不会调用对象的destructor. 142、软件的特性:复杂性、一致性、可变性、不可见性 143、signed char a=0xe0; unsignedint b=a; unsigned char c=a; a的值为-32;c的值为224;b的16进制表示为0xffffffe0; 144、 145 146、C语言本身没有提供对字符串进行整体操作的运算符 147、C语言程序中,若对函数类型未加显示类型,则函数的隐含说明类型是int。 148、指数e前必有数,e后必为整 149、宏替换不占用程序运行时间 150、 151、浅拷贝:只复制指针内容,不复制指针所指对象,结果为两个指针指向同一块内存 深拷贝:重新为指针分配内存,并将原来指针所指对象的内容拷贝过来,最后结果为两个指针指向两块不同的内存。 152、在哪种派生方式中,派生类可以访问基类中的protected成员: Public、protected、private均可。 153、实参可以是常量、变量或表达式,但是形参只能是变量。 154、一次性输入、输出字符数组,只写字符数组名:true 155、 1)、*p++ 先取指针p指向的值(数组第一个元素2),再将指针p自增1; 2)、(*p)++ 先去指针p指向的值(数组第一个元素2),再将该值自增1(数组第一个元素变为3) 3)、*++p 先将指针p自增1(此时指向数组第二个元素),操作再取出该值 4)、++*p 先取指针p指向的值(数组第一个元素2),再将该值自增1(数组第一个元素变为3) 156、用C程序实现的算法可以没有输入但是必须要有输出。 157、 158、派生类的构造函数的初始化列表中,不能包含:C基类的子对象初始化 A基类的构造函数、B派生类中子对象的初始化、C基类的子对象初始化、D派生类中一般数据成员的初始化 159、stl中,map的迭代器的key是const类型,无法对其进行修改;list是双链表实现,插入元素的复杂度为O(1)。 160、下列存储标识符中,内部静态类的可见性与存在性不一致 外部类、自动类、内部静态类、寄存器类 161、在do-while循环体中,不一定要有能使while后面表达式的值变成零的操作 162、this指针保证每个对象拥有自己的数据成员,但共享处理这些数据的代码 163、只有十进制才有负数 164、只能通过成员函数进行重载 = 赋值运算符 165、在C程序中,赋值运算符的优先级不是最低的,逗号运算符优先级最低 166、结构化程序由三种基本结构组成,三种基本结构组成的算法只能完成符合结构化的任务。 167、 168、(1)传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。 (2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。 (3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。 169、由&&构成的逻辑表达式与由||构成的逻辑表达式都有“短路”现象 短路效应是指,二元逻辑运算符&&,||,左边真值一旦确定,不会执行右边表达式 170、局部变量说明为static存储数,其生存期将得到延长,离开局部时,局部变量的值会保存,下次再回到局部时可以读取保存的值; 全局变量声明为static后,其作用域非但没有扩大,反而缩小,只能在所在的文件内使用; 静态变量默认初始化为0; 局部变量可以使用static,形参不能。 171、使用malloc系统调用分配的内存是在堆上分配的 172、以下哪些做法是不正确或者应极力避免的:A,C,D A、构造函数声明为虚函数 B、派生关系中的基类析构函数声明为虚函数 C、构造函数中调用虚函数 D、析构函数中调用虚函数 173、r以只读方式打开,r+以读写方式打开,rb+以读写方式打开二进制文件,rt+以读写方式打开一个文本文件 174、可以把define定义为用户标识符,但不能把if定义为用户标识符 预定义标识符:define、scanf、printf、include可以作为用户标识符 175、C 语言中,函数值类型的定义可以缺省,此时函数值的隐含类型是int 176、如果要实现一个多线程(非MFC)程序, 选择多线程CRT, 创建线程的时候应该用CreateThread还是_beginthreadex:_beginthreadex。 177、char a=101;char类型的范围是-128---+127,当a+=27 ,之后a的值超出可表示范围会变为-128 178、静态函数属于类本身,不与类绑定,因此不能用this指针。 在类定义时,无法使用构造函数,因而无法完成对象的初始化 一般成员变量需要在类内进行初始化 静态成员变量必须在类外初始化,静态成员常量在类中初始化。 179、假定编译器不做优化,对一个int类型变量k,做前缀自加和后缀自加,++k执行速度更快,因为++k运算结束后,k的值和表达式的值相同。 而k++运算结束后,k的值和表达式的值不相同。编译器要开辟一个新的变量来保存k++表达式的值。 所以说:++k更快。 180、预处理命令是以#号开头的代码行,结尾没有“;”,所以每一条独占一行。 181、C 语言程序中,当调用函数时实参和虚参各占一个独立的存储单元,C 语言没有传引用调用这种形式,只有传值调用这种形式,你可以通过传递指针模拟传引用调用,但是别忘了,指针其实也就是一个值而已 182、C 语言中的整型常量有3种表示方法。八进制,十进制和十六进制三种 183、scanf不能指定输入精度,可以指定长度。比如%m.nf是不允许的,但是可以%mf。m为整数。 184、静态分配是指在编译阶段就能确定大小,由编译器进行分配,堆不可以进行静态分配,堆的申请都是在执行过程中进行的。堆是使用malloc()、calloc()、realloc()等函数动态分配的,而使用alloca()函数可以动态分配栈的内存空间,释放的时候由编译器自己释放。 185、虚成员函数不可能是static成员函数 186、下面哪种C/C++ 分配内存的方法会将分配的空间初始化为0:calloc() malloc()、calloc()、realloc()、new[ ] 187、sizeof是操作符,在编译阶段就获得结果,strlen是函数调用,在运行阶段获得值。 188、虚函数必须是类的成员函数,其中类的静态成员函数和构造函数不能定义为虚函数,析构函数可以 189、volatile提醒编译器它后面所定义的变量随时都有可能改变 ,因此编译后的程序每次需要存储或读取这个变量的时候 ,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储, 可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象 190、 外部变量,可供所以源文件使用 寄存器变量,放在寄存器而非内存中,效率更高,一般是临时变量 自动变量,所有未加 static 关键字的都默认是 auto 变量,也就是我们普通的变量 静态变量,在内存中只存在一个,可供当前源文件的所有函数使用 191、线程安全 1.局部变量局部使用是安全的 为什么?因为每个thread 都有自己的运行堆栈,而局部变量是生存在堆栈中,大家不干扰。 2.全局原生变量多线程读写是不安全的 , 全局变量是在堆(heap)中。 3.函数静态变量多线程读写也是不安全的。 4.volatile能保证全局整形变量是多线程安全的么? 5.InterlockedIncrement保证整型变量自增的原子性 写好多线程安全的法宝就是封装,使数据有保护的被访问到 局部变量 > 成员变量 > 全局变量 192、C/C++函数,比较两个字符串,设这两个字符串为str1,str2, 若str1==str2,则返回零; 若str1 若str1>str2,则返回正数。 193、以下哪些对象可用于Windows进程间通信:共享内存 事件、临界区、互斥量、共享内存 194、以下函数中,和其他函数不属于一类的是:pwrite fwrite、putc、pwrite、putchar、getline、scanf pwrite是系统调用,其他都是库函数 常见文件系统 系统函数 fcntl 文件控制 open 打开文件 creat 创建新文件 close 关闭文件描述字 read 读文件 write 写文件 readv 从文件读入数据到缓冲数组中 writev 将缓冲数组里的数据写入文件 pread对文件随机读 pwrite 对文件随机写 195、#define和const 相比有如下劣势: 196、函数模板必须由编译器根据程序员的调用类型实例化为可执行的函数; 类模板的成员函数都是函数模板 没使用过的成员函数(即函数模板)不会被实例化 197、使用对象名调用虚函数,是静态联编; 使用基类指针调用虚函数,是动态联编; 198、静态存储变量具有局部的生存期.说法是否正确?错误 在程序运行期间都不释放 static不在栈区存储,所以不是局部生存期。 199、scanf不能输入空格,而gets函数却可以。gets(字符数组名或指针),gets能够接受空格、制表符Tab和回车等。gets和sacnf函数,在字符串接受结束后自动加'\0' 200、
() 函数调用运算符
[] 下标
-> 间接成员运算符
不能。 volatile仅仅是告诫compiler不要对这个变量作优化,每次都要从memory取数值,而不是从register
安全性:
1.const定义常量是有数据类型的,而#define宏定义常量却没有
2.const常量有数据类型,而宏常量没有数据类型。编译器可以对const进行类型安全检查,
而对后者只进行字符替换,没有类型安全检查,并且在字符替换中可能会产生意料不到的错误
3.有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。