C++/MFC试题 一.填空题(26分) 1. WIN32平台下,sizeof(short) = __2__,sizeof(int) = _4___,sizeof(long) = ___4_。(3分) 2.请给出如下程序的结果(2分) int a = 3; int b = a << 3; a = ___2_,b = _24___。 3.请给出如下程序的结果(2分) int aaa = 0x01; htonl(aaa) = ____。 4.请给出如下程序的结果(2分) #define MAX_NUM 100+200 int nTemp = MAX_NUM*10; 则Temp = 2100___。 5.请给出如下程序的结果(3 分) char szTemp[1000] = ""; int nLen1 = sizeof(szTemp); int nLen2 = strlen(szTemp); strcpy(szTemp, "abc"); int nLen3 = sizeof(szTemp); int nLen4 = strlen(szTemp); int nTemp[100]; int *pTemp = nTemp; int nLen5 = sizeof(pTemp); char szResult[200] = ""; sprintf(szResult, "%d,%d,%d,%d,%02d.", nLen1, nLen2, nLen3, nLen4, nLen5); 则szResult = _1000,0,1000,3,04___。(strlen求字符串的长度,不包括’/0’, %02d要注意) 6.MFC中,大部分类是从哪个类继承而来(CCmdTarget、CObject、CWinApp、CWnd)?(2分)__ CObject __ 7.内存是进程范围or线程范围;____进程 CPU调度时,针对进程or线程;_线程___ 函数调用堆栈,针对进程or线程。__线程__(3分) windows: 1.内存是进程范围。因为进程是容器,他拥有操作资源的句柄,而线程不拥有任何资源 2.CPU调度的最小单位是线程。因为进程虽然拥有资源,但他本身不进行任何操作,需要线程来操作 3.针对线程,Windows给每个线程分配一个堆栈 8.调用函数bbb后,输出是什么(4分) void ccc(int x) { char szTemp[10] = ""; x = 2; sprintf(szTemp, "%d,", x); afxDump << szTemp; if(x = 3) { int x = 4; sprintf(szTemp, "%d,", x); afxDump << szTemp; } sprintf(szTemp, "%d,", x); afxDump << szTemp; } void bbb() { char szTemp[10] = ""; int x = 7; ccc(x); sprintf(szTemp, "%d,", x); afxDump << szTemp; } 2,4,3,7(注意这一句: if(x = 3),相当于给x赋值为3!)二.改错题(总共15分,每题5分)。 1.下面代码有何错误 void func1() { int *pa = NULL; func2(pa); // 这一步后pa认为空,要传递引用参数才行 delete pa; } void func2(int *pb) { pb = new int(5); } C++标准规定,delete (void*)0;是安全的。而现在的编译器通常都会有一个#define NULL 0的宏所以,delete NULL也是安全的 无效操作;把指针赋值为null了,那么该指针就什么也不指向了。但是,你还可以对该指针重新赋值,让它可以重新指向。如果赋值为null,并且用delete进行销毁了,那么该指针就不能再重新进行指向了。如果需要,你得另外定义一个指针了。 2.下面代码有何错误 void func2(int *value) { *value = 2; } void func1() { int *p = 0; func2(p);//p并未被赋值 } 3. int func1(int& b) { return 0; } void func2() { int bbb = 3; func1(&bbb);//错,类型不符 func1(bbb); } func2中有何错误,func1的参数b的类型是什么。int 三.简答题(64分) 1.请简述C、C++、VC、MFC在概念上的区别(4分) 2.请写一个函数重载的简单例子(4分) 3.用什么函数开启新进程、线程。(4分) AfxBeginThread函数可以开启一个新的线程,此函数接受两个参数,第一个是线程处理函数,第二个是一个任何类型的指针。 4.SendMessage和PostMessage有什么区别(4分) 详细的说区别就是: 使用SendMessage函数发出消息后不马上返回,而是等待接收到消息的应用程序处理完消息后才返回,并获得返回结果 而PostMessage函数在发出之后马上返回,其语句能够被立即执行,但是无法获取消息的结果 5.WaitForSingleObject有何作用;m_pThrd的类型是CWinThread*时,WaitForSingleObject(m_pThrd->m_hThread, INFINITE);有何作用。(4分) 1.1 WaitForSingleObject的用法 WaitForSingleObject 的用法 DWORD WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds ); 参数 hHandle 是一个事件的句柄,第二个参数 dwMilliseconds 是时间间隔。如果时间是有信号状态返回 WAIT_OBJECT_0 ,如果时间超过 dwMilliseconds 值但时间事件还是无信号状态则返回 WAIT_TIMEOUT 。 hHandle 可以是下列对象的句柄: Change notification Console input Event Job Memory resource notification Mutex Process Semaphore Thread Waitable timer WaitForSingleObject 函数用来检测 hHandle 事件的信号状态,当函数的执行时间超过 dwMilliseconds 就返回,但如果参数 dwMilliseconds 为 INFINITE 时函数将直到相应时间事件变成有信号状态才返回,否则就一直等待下去,直到 WaitForSingleObject 有返回直才执行后面的代码。在这里举个例子: 先创建一个全局 Event 对象 g_event: CEvent g_event; 在程序中可以通过调用 CEvent::SetEvent 设置事件为有信号状态。 下面是一个线程函数 MyThreadPro() UINT CFlushDlg::MyThreadProc( LPVOID pParam ) { WaitForSingleObject(g_event,INFINITE); For(;;) { ………… . } return 0; } 在这个线程函数中只有设置 g_event 为有信号状态时才执行下面的 for 循环,因为 g_event 是全局变量,所以我们可以在别的线程中通过 g_event. SetEvent 控制这个线程。还有一种用法就是我们可以通过 WaitForSingleObject 函数来间隔的执行一个线程函数的函数体 UINT CFlushDlg::MyThreadProc( LPVOID pParam ) { while(WaitForSingleObject(g_event,MT_INTERVAL)!=WAIT_OBJECT_0) { ……………… } return 0; } 在这个线程函数中可以可以通过设置 MT_INTERVAL 来控制这个线程的函数体多久执行一次,当事件为无信号状态时函数体隔 MT_INTERVAL 执行一次,当设置事件为有信号状态时,线程就执行完毕了。 6. __stdcall、__cdecl、__pascal在什么方面有所不同。(4分) cdecl 由调用者清除堆栈 stdcall 由被调的函数清除堆栈 fastcall 是把函数参数列表的前三个参数放入寄存器eax,edx,ecx,其他参数压栈。 _stdcall 与 _cdecl 的区别几乎我们写的每一个WINDOWS API函数都是__stdcall类型的,首先,需要了解两者之间的区别: WINDOWS的函数调用时需要用到栈(STACK,一种先入后出的存储结构)。当函数调用完成后,栈需要清除,这里就是问题的关键,如何清除??如果我们的函数使用了_cdecl,那么栈的清除工作是由调用者,用COM的术语来讲就是客户来完成的。这样带来了一个棘手的问题,不同的编译器产生栈的方式不尽相同,那么调用者能否正常的完成清除工作呢?答案是不能。如果使用__stdcall,上面的问题就解决了,函数自己解决清除工作。所以,在跨(开发)平台的调用中,我们都使用__stdcall(虽然有时是以WINAPI的样子出现)。那么为什么还需要_cdecl呢?当我们遇到这样的函数如 fprintf()它的参数是可变的,不定长的,被调用者事先无法知道参数的长度,事后的清除工作也无法正常的进行,因此,这种情况我们只能使用 _cdecl。到这里我们有一个结论,如果你的程序中没有涉及可变参数,最好使用__stdcall关键字。 另: _cdecl 按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于“C”函数或者变量,修饰名是在函数名前加下划线。对于“C++”函数,有所不同。如函数void test(void)的修饰名是_test;对于不属于一个类的“C++”全局函数,修饰名是?test@@ZAXXZ。这是MFC缺省调用约定。由于是调用者负责把参数弹出栈,所以可以给函数定义个数不定的参数,如printf函数。 stdcall 和pascal一样,都是pascal的调用习惯按从右至左的顺序压参数入栈,由被调用者把参数弹出栈。对于“C”函数或者变量,修饰名以下划线为前缀,然后是函数名,然后是符号“@”及参数的字节数,如函数int func(int a, double b)的修饰名是_func@12。对于“C++”函数,则有所不同。 stdcall 参数从右到左入栈,从左到右获取 cdecl 参数从右到左传递 pascal 参数从左到右传递 7.请把下述代码加上异常处理。(6分) int MyWriteFile(CString strFileName, CString strText) { int nRet = 0; CFile myFile; myFile.Open(strFileName, CFile::modeWrite|CFile::shareExclusive|CFile::modeCreate, NULL); int nLen = strText.GetLength(); myFile.Write((char*)(LPCSTR)strText, nLen); myFile.Close(); return nRet; } 8.请解释“func”为何种类型,这种类型的作用什么,变量ttt 的值是多少?(6分) typedef int (*func)(int, int*); int xxx(int a, int *p) { return a + *p; } int dowork(func aaa, int bbb, int *ccc) { return aaa(bbb, ccc); } int sss = 4; int ttt = dowork(&xxx, 3, &sss); ttt = 7 9.请问下述代码中: int operator+(…)起什么作用?this是什么?ccc 的值最终为多少?(6分) class Fruit { public: Fruit() { weight = 2; } Fruit(int w) { weight = w; } int operator+(Fruit f) { return this->weight * f.weight; } private: int weight; }; Fruit aaa; Fruit bbb(4); int ccc = aaa + bbb; 10.请解释下面代码采用了何种C++特性(C语言不具备),作用是什么?(6分) template T sum(T a, T b) { return (a + b); } 代码重用,取代一些虚函数以获得更快速度,取代宏得到安全保障。。 11.请解释aaa.h中下面代码的功能(5分) #if !defined(AFX_MYSUDU_H__9B952BEA_A051_4026_B4E5_0598A39D2DA4__INCLUDED_) #define AFX_MYSUDU_H__9B952BEA_A051_4026_B4E5_0598A39D2DA4__INCLUDED_ ... ... #endif 12.CMemoryState主要功能是什么(5分) 用CMemoryState检测内存泄漏 CMemoryState是Visual C++提供的内存检测类,主要用于检测程序中的内存泄漏 13.请阅读下述代码,写出程序执行的结果(6分) #include using namespace std; class CBase { public: virtual void print() { cout<< "base" << endl; } void DoPrint() { print(); } }; class CChild1: public CBase { public: virtual void print() { cout<< "child1" << endl; } }; class CChild2: public CBase { public: virtual void print() { cout<< "child2" << endl; } }; void DoPrint(CBase *base) { base->DoPrint(); } void main() { CBase* base = new CBase(); CChild1* child1 = new CChild1(); CChild2* child2 = new CChild2(); DoPrint(child1); DoPrint(child2); DoPrint(base); delete base; base = child1; base->print(); delete child1; delete child2; }
C++/MFC试题
最新推荐文章于 2021-09-27 18:01:17 发布