据传是《清华同方》的C++笔试题(有改动by ASCE1885):
1)以下代码输出结果是什么?
#include <iostream>
int main()
{
char str1[] = "abc";
char str2[] = "abc";
const char str3[] = "abc";
const char str4[] = "abc";
const char* str5 = "abc";
const char* str6 = "abc";
char *str7 = "abc";
char *str8 = "abc";
std::cout<<&str1<<std::endl;
std::cout<<&str2<<std::endl;
std::cout<<&str3<<std::endl;
std::cout<<&str4<<std::endl;
std::cout<<&str5<<std::endl;
std::cout<<&str6<<std::endl;
std::cout<<&str7<<std::endl;
std::cout<<&str8<<std::endl;
std::cout<<"结果:"<<(str1 == str2)<<std::endl;
std::cout<<"结果:"<<(str3 == str4)<<std::endl;
std::cout<<"结果:"<<(str5 == str6)<<std::endl;
std::cout<<"结果:"<<(str7 == str8)<<std::endl;
system("pause");
return 0;
}
解答:输出结果是:
0x22ff44
0x22ff40
0x22ff3c
0x22ff38
0x22ff34
0x22ff30
0x22ff2c
0x22ff28
结果:0
结果:0
结果:1
结果:1
当然了,输出的各个变量的地址在不同机器上是不同的,甚至在同一台机器上不同时间运行都可能不一样;这里仅看最后输出的四行,这样的结果是因为:字符数组名比较的是内存地址,而字符串名比较的是它指向的内存中的内容。
还有一种深入点的说法是:str1和str2都是字符数组,每个都有自己的存储区,它们的值则是各自存储区的首地址,自然str1和str2就不等了;而str3和str4同上,只是多了个const语义而已,即表示它们指向的数据区内容不能修改;
str5和str6并非数组而是字符指针,它们并不分配存储区,其中的“abc”是以常量形式存在于静态数据区中的,而str5和str6仅仅是指向该区首地址的指针而已,自然相等了;str7和str8同理。
2)DLL有两种加载方式,即显式加载和隐式加载。那么.exe文件隐式加载使用DLL时,DLL文件放在哪里?
解答:说实话,刚看到“DLL文件放在哪里”这句话,一时还真不知道;但转念一想,放在哪不就是说.exe文件会到哪里找DLL吗,于是答案就显而易见了:(下面是从《Windows核心编程(第五版)》摘下的)
启动一个可执行模块的时候,操作系统的加载程序会先为进程创建虚拟地址空间,接着把可执行模块映射到进程的地址空间中。之后加载程序会检查可执行模块的导入段,试图对所需的DLL进行定位并将它们映射到进程的地址空间中。由于导入段只包含DLL的名称,不包含DLL的路径,因此加载程序必须在用户的磁盘上搜索DLL,下面就是加载程序的搜索顺序,也就是这个问题的答案了:
1)包含可执行文件的目录;
2)Windows系统目录,该目录可以通过GetSystemDirectory函数得到;
3)16位的系统目录,即Windows目录中的System子目录;
4)Windows目录,该目录可以通过GetWindowsDirectory函数得到;
5)进程的当前目录;
6)PATH环境变量中所列出的目录。
注意,上面对应用程序当前目录的搜索位于Windows目录之后,这个改变始于Windows XP SP2,其目的是为了防止加载程序在应用程序的当前目录中找到伪造的系统DLL并将它们载入,从而保证系统DLL始终都是从它们在Windows目录中的正式位置载入的。
3)MFC文档类视图的结构及主要作用?
解答:额~,这个似乎不是一两句话能说清的,留着以后再说吧!
4)写内存拷贝函数,原型是:void* ASCEMemcpy(void* dest, const void* src, size_t count)?
解答:这是一个经典的题目了,考察的重点是考虑问题是否全面,以及对内存拷贝的理解是否仅浮于表面:
#include <iostream>
#include <assert.h>
void* ASCEMemcpy(void* dest, const void* src, int count)
{
assert(dest != NULL && src != NULL);
char* pdest = static_cast<char*>(dest);
const char* psrc = static_cast<const char*>(src);
//目标地址在源地址后面(想象成坐标轴方式),且地址重叠
//因此,只能从后向前复制psrc到pdest
if(pdest > psrc && pdest < (psrc + count))
{
for(size_t i=count-1; i != -1; --i)
{
pdest[i] = psrc[i];
}
}
else //无论目标地址在源地址前面,且地址重叠;还是没有重叠
{
for(size_t i=0; i<count; ++i)
{
pdest[i] = psrc[i];
}
}
return pdest;
}
int main()
{
char str[] = "0123456789";
char *pstr = (char*)ASCEMemcpy(str+1, str+0, 10);
std::cout<<pstr<<std::endl;
system("pause");
return 0;
}