//冯诺依曼体系的五部分是什么? //冯诺依曼理论的要点是:数字计算机的数制采用二进制;计算机应该按照程序顺序执行。 //其主要内容是: //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主要是将数据从一种类型的转换为另一种类型。所谓“通常为操作数的位模式提供较低层的重新解释” 也就是说将数据以二进制存在形式的重新解释。 */