您的位置:首页 > 编程语言 > C语言/C++

C++小题(三)

2015-12-25 16:45 441 查看
//冯诺依曼体系的五部分是什么?
//冯诺依曼理论的要点是:数字计算机的数制采用二进制;计算机应该按照程序顺序执行。
//其主要内容是:
//1.计算机由控制器、运算器、存储器、输入设备、输出设备五大部分组成。
//2.程序和数据以二进制代码形式不加区别地存放在存储器中,存放位置由地址确定。
//3.控制器根据存放在存储器中地指令序列(程序)进行工作,并由一个程序计数器控制指令地执行。
//控制器具有判断能力,能根据计算结果选择不同的工作流程。

//////////////////////////////////////////////////////////////////////////////////////////////////
/*
#include<iostream>
using namespace std;
class A
{
public:
A()
{
printf("0");
}
A(int a)
{
printf("1");
}
A& operator=(const A& a)
{
printf("2");
return*this;
}
};
int main()
{
A al;//调用构造函数A()
al=10;//10转成A对象,调用A(int)构造函数,然后调用赋值构造函数。
}
//012
*/

//////////////////////////////////////////////////////////////////////////////////////////////////

/*关于虚函数的描述正确的是()
正确答案: B

A派生类的虚函数与基类的虚函数具有不同的参数个数和类型
B内联函数不能是虚函数
C派生类必须重新定义基类的虚函数
D虚函数可以是一个static型的函数*/

//////////////////////////////////////////////////////////////////////////////////////////////////
/*
#include <iostream>
using namespace std;
class A {
public:
int b;
char c;
virtual void print() {
cout << "this is father’s fuction! " << endl;
}
};
class B: A {
public:
virtual void print() {
cout << "this is children’s fuction! " << endl;
}
};
int main(int argc, char * argv[]) {
cout << sizeof(A) << "" << sizeof(B) << endl;//12 12
return 0;
}
//类的大小只与成员变量(非static数据成员变量)和虚函数指针有关,还要考虑到对齐.
//那么类A的大小等于4个字节 + 4个字节(考虑对齐) + 4个字节(指向虚函数的指针)=12字节;
//类B的大小就是等于类A的大小12个字节.
//因为在基类中存在虚函数时,派生类会继承基类的虚函数,因此派生类中不再增加虚函数的存储空间
//(因为所有的虚函数共享一块内存区域),而仅仅需要考虑派生类中添加进来的非static数据成员的内存空间大小。
//所以类B大小为12
*/
//////////////////////////////////////////////////////////////////////////////////////////////////

//free(ptr)
//如果ptr为NULL,则不会做任何操作
//如果ptr未定义,则会崩溃。

//////////////////////////////////////////////////////////////////////////////////////////////////
//malloc函数进行内存分配是在什么阶段?  选执行阶段 ,malloc 在堆上动态分配内存,在运行时期
//编译阶段
//链接阶段
//装载阶段
//执行阶段

//////////////////////////////////////////////////////////////////////////////////////////////////
/*
Which of the following statements are true?
正确答案: A C D

A We can create a binary tree from given inorder and preorder traversal sequences.
B We can create a binary tree from given preorder and postorder traversal sequences.
C For an almost sorted array, insertion sort can be more effective than Quicksort.
D Suppose T(n) is the runtime of resolving a problem with n elements, T(n) = Θ(1) if n = 1; T(n) = 2T(n/2) + Θ(n) if > 1; so T(n) is Θ(n log n).
None of the above.
//必须要有中序才能得到一颗二叉树的正确顺序
*/
//////////////////////////////////////////////////////////////////////////////////////////////////

/*
请说出const与#define 相比,有何优点 ?
BC
A 宏常量有数据类型,而const常量没有数据类型
B 有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试
C 编译器可以对const进行类型安全检查。而对#define只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。
*/
//////////////////////////////////////////////////////////////////////////////////////////////////
/*
#include<iostream>
using namespace std;
struct A{
char a[10];
int b;
short c[3];
};
int main(){
cout<<sizeof(A);//24=10+2+4+3*2+2
}*/

//////////////////////////////////////////////////////////////////////////////////////////////////

/*
STL中的哪种结构在增加成员时可能会引起原有成员的存储位置发生:
正确答案: D

A,map;
B,set;
C,list;
D,vector;
*/

//////////////////////////////////////////////////////////////////////////////////////////////////
/*
#include<stdio.h>
struct node{
int elem;
struct node* next;
};
void difference(node** LA,node* LB){
node*pa,*pb,*pre,*q;
pre=NULL;
pa=*LA;// LA是指向指针的指针,pa指向集合的元素
while(pa){
pb=LB;// pb指向集合B的元素
while(pb && pa->elem!=pb->elem) //在链表LB中寻找与pa所指元素相等的节点
pb=pb->next;
if(pb){ // pa所指元素与pb所指元素相等
if(!pre){
*LA=pa->next;
}else{
pre->next=pa->next;
}
q=pa;// 求差集 所以要删除pa节点
pa=pa->next;
free(q);
}else{
pre=pa;
pa=pa->next;
}
}
}

本题的解法思路较简单:
因为要求集合A和集合B的差集(A-B),结果保存在集合A中.
所以我们取出集合A中每一个元素,然后在集合B中寻找(代码22行所实现) 找到即删除此节点 否则保留
此时while循环跳出只有两种情况,pb为NULL或者 pa->elem==pb->elem
当pb不为null时,即找出集合A和集合B的公有元素,此时要删除这个元素
pre(实现删除节点之后的链接)
当pre为NULL时,说明是首次找到A和B的公有元素,此时 *LA指向pa->next 所以*LA仍然是头结点
当pre不为NULL时, pre指向pa->next,顺利实现删除节点的链接
*/
//////////////////////////////////////////////////////////////////////////////////////////////////

//函数可以嵌套调用,但不可以嵌套定义。

/*
class A
{
int _a;
public:
A(int a): _a(a)
{
}
friend int f1(A &);
friend int f2(const A &);
friend int f3(A);
friend int f4(const A);
};
以下调用哪个是错误的:
正确答案: A   非常量引用的初始值必须为左值

f1(0)
f2(0)
f3(0)
f4(0)
*/

//////////////////////////////////////////////////////////////////////////////////////////////////

/*
下面有关malloc和new,说法错误的是?
正确答案: C

A new 建立的是一个对象, malloc分配的是一块内存.
B new   初始化对象,调用对象的构造函数,对应的delete调用相应的析构函数,malloc仅仅分配内存,free仅仅回收内存
C new和malloc都是保留字,不需要头文件支持
D new和malloc都可用于申请动态内存,new是一个操作符,malloc是是一个函数

new/delete都是要分两步操作的:new分配内存,并且调用对象的构造函数初始化一个对象;delete调用相应的析构函数,然后释放内存
malloc/free只是分配内存/回收内存, 所以A、B对;
malloc需要头文件"stdlib.h"或者"malloc.h" C错;
new/delete都是内建的操作符,而malloc是一个函数,其函数原型是:
1
void *malloc(unsigned int num_bytes);
所以选C
*/

//////////////////////////////////////////////////////////////////////////////////////////////////

/*
union Test
{
char a[4];
short b;
};
Test test;
test.a[0]=256;
test.a[1]=255;
test.a[2]=254;
test.a[3]=253;
printf("%d\n",test.b);
在80X86架构下,输出什么值?
-128
-256
128
256
char类型的取值范围是-128~127,unsigned char的取值范围是0~256
这里a[0]=256,出现了正溢出,将其转换到取值范围内就是0,即a[0]=0;
同理,a[1]=-1, a[2]=-2, a[3]=-3,在C语言标准里面,用补码表示有符号数,故其在计算机中的表示形式如下:
a[0]=0,     0000 0000
a[1]=-1,    1111 1111
a[2]=-2,    1111 1110
a[3]=-3,    1111 1101
short是2字节(a[0]和a[1]),由于80X86是小端模式,即数据的低位保存在内存的低地址中,
而数据的高位保存在内存的高地址中,在本例中,a[0]中存放的是b的低位,a[1]中存放的是b的高位,
即b的二进制表示是:1111 1111 0000 0000,表示-256,故选B。
*/

//////////////////////////////////////////////////////////////////////////////////////////////////
/*
char *c[] = { "ENTER", "NEW", "POINT", "FIRST" };
char **cp[] = { c+3, c+2, c+1, c };
char ***cpp = cp;

int main(void)
{
printf("%s", **++cpp);
printf("%s", *--*++cpp+3);
printf("%s", *cpp[-2]+3);
printf("%s\n", cpp[-1][-1]+1);
return 0;
}
输出POINTERSTEW http://blog.csdn.net/yuanjilai/article/details/8043784 */

//////////////////////////////////////////////////////////////////////////////////////////////////

/*
#include<iostream>
using namespace std;
class A{
public:
const static int a=1;
};
int main(){
A a1;
cout<<a1.a<<" "<<A::a;
}
通常静态数据成员在类声明中声明,在包含类方法的文件中初始化.
初始化时使用作用域操作符来指出静态成员所属的类.
但如果静态成员是整型或是枚举型const,则可以在类声明中初始化!!
*/
////////////////////////////////////////////////////////////////////////////////////////////////////

/*
#include<iostream>
using namespace std;
struct A{
void foo(){printf("foo");}
virtual void bar(){printf("bar");}
A(){bar();}
};
struct B:A{
void foo(){printf("b_foo");}
void bar(){printf("b_bar");}
};
int main(){
A *p=new B;
//p->foo();
//p->bar();
}*/

//////////////////////////////////////////////////////////////////////////////////////////////////

/*
在C++STL中常用的容器和类型,下面哪些支持下标"[]"运算?
vector
list
deque
map
set
unordered_map
unordered_set
stack
string

ACDFI
vector:随机访问迭代器,复杂度O(1)
deque:同上,O(1)
map:双向迭代器,不过由于是关联容器,需要通过key访问value的方法,O(h),h为树的高度
unordered_map:前向迭代器,同上,平摊复杂度O(1),最差O(n),也与散列函数的好坏有关。
string:同vector
*/

//////////////////////////////////////////////////////////////////////////////////////////////////

/*
class ClassA
{
public:
virtual ~ ClassA()
{
}
virtual void FunctionA()
{
}
};
class ClassB
{
public:
virtual void FunctionB()
{
}
};
class ClassC: public ClassA, public ClassB
{
public:
};
ClassC aObject;
ClassA *pA = &aObject;
ClassB *pB = &aObject;
ClassC *pC = &aObject;

假设定义了ClassA* pA2,下面正确的代码是:
正确答案: B D

A pA2=static_cast<ClassA*>(pB);
B void* pVoid=static_cast<void*>(pB);
pA2=static_cast<ClassA*>(pVoid);
C pA2=pB;
D pA2=static_cast<ClassA*>(static_cast<ClassC*>(pB));

A   两个无关类型指针之间的转换 是不合法的
B  通过void*这个媒介 ,合法
C  直接赋值,无法进行隐式转换,不合法
D  通过继承体系中的一个 做媒介, 上行 下行 合法
四类强制转换:
static_cast(编译器可实现的隐式转换或类层次间的下行转换)、
dynamic_cast(操作数只能为类指针或类引用)、
const_cast(去除const)、
reinterpret_const(一般意义强制转换)

static_cast 的用法
static_cast < type-id > ( expression )
该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:
①用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。
进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;
进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。
②用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
③把空指针转换成目标类型的空指针。
④把任何类型的表达式转换成void类型。
注意:static_cast不能转换掉expression的const、volatile、或者__unaligned属性。

C++中的static_cast执行非多态的转换,用于代替C中通常的转换操作。因此,被做为显式类型转换使用。

C++中的reinterpret_cast主要是将数据从一种类型的转换为另一种类型。所谓“通常为操作数的位模式提供较低层的重新解释”
也就是说将数据以二进制存在形式的重新解释。

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: