题目摘录-编程语言(C++)(一)
题目:
以下代码:
class ClassA{
public:
virtual ~ClassA(){};
virtual void FunctionA(){};
};
class ClassB{
public:
virtual void FunctionB(){};
};
class ClassC:public ClassA, public ClassB{
public:
};
ClassC Object;
ClassA* pA = &Object;
ClassB* pB = &Object;
ClassC* pC = &Object;
关于pA,pB,pC的取值,下面的描述中正确的是:
答案:
pA和pB不相同
解答:
考察多继承且有虚函数情况下C++存储对象模型。
1. 多继承按继承顺序组织对象模型,有虚函数时低地址包含指向虚函数表的指针。
2. 对象Object的存储模型:类A虚函数表指针(ptrA) | 类A数据 | 类B虚函数表指针(ptrB) | 类B数据 | 类C数据。
3. 子类的虚函数被放到了第一个基类的虚函数表最后(ptrA指向的虚函数表结构:类A虚函数 | 类C虚函数)。
4. 有虚函数的继承,对象地址为指向虚函数表的指针的地址,即pC = &Object = &ptrA。
6. pC = pA = &ptrA = &Object,(pC = pA) < pB。
题目:
下列程序的输出结果:
#include <iostream>
using namespace std;
class A{
public:
void print(){
cout << "A:print()";
}
};
class B:private A{
public:
void print(){
cout << "B:print()";
}
};
class C:public B{
public:
void print(){
A::print();
}
};
int main(){
C b;
b.print();
}
答案:
编译出错
解答:
考察C++继承问题。
1. 类B私有继承类A。
2. 私有继承:类A的公有成员和保护成员都作为类B的私有成员,并且不能被类B的子类(如类C)所访问。
题目:
下面两个结构体:
struct One{
double d;
char c;
int i;
}
struct Two{
char c;
double d;
int i;
}
在#pragma pack(4)和#pragma pack(8)的情况下,结构体的大小分别是:
答案:
16,16
16,24
解答:
考察结构体对齐。
1. 4字节对齐:Struct One[8 + (1 + 3(pading)) + 4], struct Two[(1 + 3(pading)) + 8 + 4]。
2. 8字节对齐:Struct One[8 + (1 + 3(pading) + 4)], struct Two[(1 + 7(pading)) + 8 + (4 + 4(pading))]。
3. 一句话总结:按序存储,装得下尽量装,装不下换一行。
题目:
下列代码的输出为:
#include "iostream"
#include "vector"
using namespace std;
int main(void)
{
vector<int>array;
array.push_back(100);
array.push_back(300);
array.push_back(300);
array.push_back(500);
vector<int>::iterator itor;
for(itor = array.begin(); itor != array.end(); itor++){
if(*itor == 300){
itor = array.erase(itor);
}
}
for(itor = array.begin(); itor != array.end(); itor++){
cout << *itor << " ";
}
return 0;
}
答案:
100
300
500
解答:
考察STL中erase和迭代器问题。
1. erase返回值是一个迭代器,指向删除元素下一个元素。
2. 删除第一个300时返回指向下一个300的迭代器,在循环体又被再加了一次,跳过了第二个300。
题目:
下面程序的输出是什么?
int main(void)
{
int a[5] = {1, 2, 3, 4, 5};
int *ptr = (int *)(&a + 1);
printf("%d,%d", *(a + 1), *(ptr - 1));
return 0;
}
答案:
2
5
解答:
1. a表示数组首元素的地址,对a的所有操作均是以一个元素为单位的。
2. &a表示整个数组的地址,对&a的所有操作均是以一个数组为单位的。
3. ptr类型为int *,所有对ptr的所有操作均是以int大小为单位进行的。
4. (int *)(&a + 1)表示指向a数组最后一个元素后一个字节的int类型指针,*(ptr - 1)表示向前移动一个int类型的数据的位置。
5. 所有指针类型操作先看右侧是以什么为单位,之后再转换为左侧定义的单位。
题目:
32位机上根据下面的代码,问哪些说法是正确的?
signed char a = 0xe0;
unsigned int b = a;
unsigned char c = a;
答案:
b的十六进制表示是:0xffffffe0
解答:
考察有符号数和无符号数之间的转换。
1. a : 1110 0000。
2. 扩展问题:
长 -> 短:低位对齐,按位复制。
短 -> 长:符号位扩展。
3. 精度提升:
两个变量运算,表示范围小的变量精度达的变量提升(signed -> unsigned)。
题目:
下列代码的输出为:
int* pint = 0;
pint += 6;
cout << pint << endl;
答案:
24
解答:
考察指针运算。
1. 变量pint为指向int类型的指针,这里“+1”表示地址加4(pint值加4)。
2. 变量pint初值为0,pint + 6后pint的值变为24。
题目:
如果两段内存重叠,用memcpy函数可能会导致行为未定义。而memmove函数能够避免这种问题,下面是一种实现方式,请补充代码。
#include <iostream>
using namespace std;
void* memmove(void* str1, const void* str2, size_t n)
{
char* pStr1 = (char*) str1;
const char* pStr2 = (const char*)str2;
if( ){
for(size_t i = 0;i != n; ++i){
*(pStr1++) = *(pStr2++);
}
}
else{
pStr1 += n - 1;
pStr2 += n - 1;
for(size_t i = 0; i != n; ++i){
*(pStr1--) = *(pStr2--);
}
}
return ( );
}
答案:
pStr1 < pStr2
str1
解答:
1. 逐字符自动不存在内存覆盖问题。
题目:
设x、y、t均为int型变量,则执行语句:t = 3; x = y = 2; t = x++ || ++y; 后,变量t和y的值分别为:
答案:
t = 1
y = 2
解答:
考察逻辑短路和运算符优先级。
1*. =的优先级最低,t = (x++ || ++y) = 1。
2. x++和++y为或关系,因为x++的值非0,所以++y不执行,y不变。
题目:
指出下面程序哪里可能有问题?
class CBuffer
{
char * m_pBuffer;
int m_size;
public:
CBuffer(){
m_pBuffer = NULL;
}
~CBuffer(){
Free();
}
void Allocte(int size) (1) {
m_size = size;
m_pBuffer = new char[size];
}
private:
void Free(){
if(m_pBuffer! = NULL) (2){
delete[] m_pBuffer;
m_pBuffer = NULL;
}
}
public:
void SaveString(const char* pText) const (3){
strcpy(m_pBuffer, pText); (4)
}
char* GetBuffer() const{
return m_pBuffer;
}
};
void main (int argc, char* argv[])
{
CBuffer buffer1;
buffer1.SaveString("Microsoft");
printf(buffer1.GetBuffer());
}
答案:
1
3
4
解答:
考察动态分配空间等周边细节处理。
1. 分配内存时, 未检测m_pBuffer是否为空, 容易造成内存泄露。
2. 常成员函数不应该对数据成员做出修改, 虽然可以修改指针数据成员指向的数据, 但原则上不应该这么做。
3*. 字符串拷贝时, 未检测是否有足够空间, 可能造成程序崩溃。