客观题
(1)大端、小端问题,以共用体示例代码给出
假设计算机的CPU是Intel 32位的,以下代码输出结果是什么?
- #include<stdio.h>
- union ut
- {
- short s;
- char ch[2];
- }u;
- int main()
- {
- u.ch[0]=0x11;
- u.ch[1]=0x22;
- printf("u.s=%0x\n",u.s);
- return 0;
- }
(2)字节对齐问题
下面的结构体占多少个字节?(32位机器上)
- struct s
- {
- char ch1;
- char ch2;
- short s1;
- char ch3;
- }
那么表达式sizeof(s)=?
答:结果是6
(3)char* p="hello world";与char p[]="hello world";的区别。
(4)指针的问题
面试:进程与线程的区别。(面试最后一个问题,居然卡住了,看来得好好看看操作系统了)
二、互联网面试
1、设计模式相关
(1)画出命令模式的类图
(2)使用C++语言实现单例模式类
(3)使用C++语言实现工程模式类
2、数据结构和算法
(1)使用C或者C++实现快速排序
C++代码如下:
- #include <iostream>
- #include <cstdlib> // srand() 以及 rand()
- #include <ctime> // time()
- using namespace std;
- int partion(int a[],int p,int r){
- //rand
- srand((unsigned)time( NULL));
- int e=rand()%(r-p+1)+p;
- int tem;
- tem=a[e];
- a[e]=a[r];
- a[r]=tem;
- int x=a[r], i=p-1;
- for (int j=p;j<r;j++){
- if (a[j]<=x){
- tem=a[i+1];
- a[i+1]=a[j];
- a[j]=tem;
- i++;
- }
- }
- tem=a[r];
- a[r]=a[i+1];
- a[i+1]=tem;
- return i+1;
- }
- void QuickSort(int a[],int p,int r){
- if (p<r){
- int q=partion(a,p,r);
- QuickSort(a,p,q-1);
- QuickSort(a,q+1,r);
- }
- }
- int main(){
- int array[]={0,-2,11,-4,13,-5,14,-43};
- QuickSort(array,0,7);
- for(int i=0;i<=7;i++)
- cout<<array[i]<<" ";
- cout<<endl;
- return 0;
- }
参考资料:
快速排序-百度百科
白话经典算法系列之六 快速排序 快速搞定
快速排序算法
3、C++语言相关
写出了几个类,判断类所占字节数。
含有纯虚函数的类会占用4个字节,空类所占字节数为0
4、不调用C语言库函数,编程实分别实现strcpy、memcpy、memmove。
(1)strcpy
C语言库函数strcpy的原型如下:
char* strcpy(char *strDestination,const char *strSource);
实现代码如下:
- //实现从strSource到strDestination的复制
- char* strcpy(char* strDestination,const char* strSource)
- {
- //判断strDestination和strSource的有效性
- assert((strDestination == NULL) || (strSource == NULL));
- char* strDestCopy = strDestination; //保存目标字符串的首地址
- while ((*strDestination++ = *strSource++) != '\0') //把strSource字符串的内容复制到
- strDestination中
- {
- ;
- }
- return strDestCopy;
- }
(2)memcpy
C语言库函数mempy的原型如下:
void *memcpy( void *dest, const void *src, size_t count );
内存复制函数memcpy实现代码如下:
- void *memcpy( void *memDest, const void *memSrc, size_t count )
- {
- assert((NULL != memDest) && (NULL != memSrc)); //memDest和memSrc必须有效
- char* tempDest = (char*)memDest; //保存memDest的首地址
- char *tempSrc = (char*)memSrc; //保存memSrc的首地址
- while (count-- > 0) //循环count次,复制memSrc的值到memDest中
- {
- *tempDest++ = *tempSrc++;
- }
- return memDest;
- }
(3)memmove
C语言库函数mempy的原型如下:
void *memmove( void *dest, const void *src, size_tcount );
功能:由src所指内存区域复制count个字节到dest所指内存区域。
说明:src和dest所指内存区域可以重叠,但复制后src内容会被更改。函数返回指向dest的指针。
内存转移函数memcpy实现代码如下:
- void * MyMemMove(void *dst,const void *src,int count)
- {
- assert(dst);
- assert(src);
- void * ret = dst;
- if (dst <= src || (char *)dst >= ((char *)src + count)) {
- while (count--) {
- *(char *)dst = *(char *)src;
- dst = (char *)dst + 1;
- src = (char *)src + 1;
- }
- }
- else {
- dst = (char *)dst + count - 1;
- src = (char *)src + count - 1;
- while (count--) {
- *(char *)dst = *(char *)src;
- dst = (char *)dst - 1;
- src = (char *)src - 1;
- }
- }
- return(ret);
- }
参考资料:http://blog.csdn.net/yujun_wu/article/details/4999565
面试题之实现系统函数系列一:实现memmove函数
三、服务器端程序员面试
1、dynamic_cast与static_cast的区别。 (C++知识点) 再加上一个const_cast转换
答:dynamic_cast: 通常在基类和派生类之间转换时使用,run-time cast 只用于指针和引用。
const_cast: 主要针对const和volatile的转换.
static_cast: 一般的转换,no run-time check. static_cast会检查一下类型,给你一个警告。
reinterpret_cast: 用于进行没有任何关联之间的转换,比如一个字符指针转换为一个整形数。
参考文章:http://blog.csdn.net/goodluckyxl/archive/2005/01/19/259851.aspx
http://blog.csdn.net/boluo1982107/article/details/3239793
2、C++中下列数据类型所占的字节数以及数值表示范围。
char BYTE WORD DWORD unsigned int short
3、几道数据库题(凭印象回忆吧)
(1)一道选择题,从product表中选出价格最贵的产品名productName以及价格price。
方法一:select TOP 1 productName,price from product ORDER BY DESEND group br productName
方法二:select productName,price from product where price = (select MAX(price) from product
()联合查询和筛选 没做出来,好久没使用SQL了。
4、MFC中CSocket类能不能用在多个线程中,请说明原因。
5、IOCP在服务器中的应用,其特点和优势是什么,主要解决了什么问题。
6、存储过程是什么?在ADO和ODBC中存储过程如何使用?
7、说出进程间通讯的几种方式的名称。
答:
共享内存
管道
信号量
消息队列
信号
套接字
# 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
# 有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
# 信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
# 消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
# 信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
# 共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
# 套接字( socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。
http://www.cnblogs.com/mydomain/archive/2010/09/23/1833369.html
8、在C++ 程序中调用被 C编译器编译后的函数,为什么要加 extern “C”?
答:C++语言支持函数重载,C语言不支持函数重载。函数被C++编译后在库中的名字与C语言的不同。假设某个函数的原型为: void foo(int x, int y);
该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。
C++提供了C连接交换指定符号extern“C”来解决名字匹配问题。
9、内存的思考题(来自林锐博士的《C/C++高质量编程》)
(1)void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
请问运行Test函数会有什么样的结果?
答:程序崩溃。
因为GetMemory并不能传递动态内存,
Test函数中的 str一直都是 NULL。
strcpy(str, "hello world");将使程序崩溃。
(2)char *GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}
请问运行Test函数会有什么样的结果?
答:可能是乱码。
因为GetMemory返回的是指向“栈内存”的指针,该指针的地址不是 NULL,但其原现的内容已经被清除,新内容不可知。
(3)void GetMemory2(char **p, int num)
{
*p = (char *)malloc(num);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}
请问运行Test函数会有什么样的结果?
答:
(1)能够输出hello
(2)内存泄漏(没释放掉已经申请的动态内存)
(4)void Test(void)
{
char *str = (char *) malloc(100);
strcpy(str, “hello”);
free(str);
if(str != NULL)
{
strcpy(str, “world”);
printf(str);
}
}
请问运行Test函数会有什么样的结果?
答:篡改动态内存区的内容,后果难以预料,非常危险。
因为free(str);之后,str成为野指针,
if(str != NULL)语句不起作用。
10、MFC和STL中均有Hash表类模板,请说明其包含的函数(不要求写出实际具体的函数名称),说明其功能即可。
11、下列是线程的伪代码:
FuctionA()
{
LOCK(x)
LOCK(y)
......
UNLOCK(x)
UNLOCK(y)
}
FuctionB()
{
LOCK(y)
LOCK(x)
......
UNLOCK(y)
UNLOCK(x)
}
上述两个线程在执行时会出现线程死锁,请说出解决上述死锁问题的几种解决方案。
14、最后是计算一道UDP的丢包率的题目,
客户端每隔60s发给服务器端1个udp数据包,服务器端在距离上次向服务器端发送应答包超过90s会向客户端再次发送应答包。
客户端一共发送了500个udp包,服务器端发送150个包,假设服务器端和客户端的丢包率相同。
请计算该网络的丢包率。
具体问题记得不大清楚了。
反正最后是没做出来。
四、VC++程序员面试 图像处理
1、QT和C++什么关系,你认为QT和MFC相比有什么异同点,各自的优势什么?
2、谈谈VC++中ADO连接数据库的几种方式?
3、QT采用的编译器是什么?(我问了一个问题是:你们为什么使用VC++做图像处理,而不用QT呢?然后一个技术官反问了我这个问题。)
我直接回答说GCC、CLang、MinGW、VS2008的编译器什么的。没有分条理回答。
QT在Windows平台下一般采用MinGW或VS2008做编译器;
在Linux系统如Ubuntu等发行版下采用GCC作为编译器;
在MAC系统下采用GCC或CLang作为编译器。
然后面试官说错了,QT是采用GCC作为编译器,其他平台需要做移植的,所以我们采用VC++做而不是QT。这点说实话有点没搞懂。
不过做数字图像处理、工控系统仿真、网络游戏,VC++还是比较适合的,这点倒是正常。
这次面试给我的感觉是经验和表达能力都蛮重要的,三个面试官让我有点招架不住。
五、一家建筑/工程/结构类的设计公司,应聘职位为MFC软件开发,笔试题为C++。
1、说明typedef int (*pFun)(int,int *)中pFun的含义,这种类型的用途主要是什么?
pFun被定义为一个指向参数列表为in,int*,返回值为int的函数指针,这种类型即函数指针可以用于定义一种指针类型,指向某种系列类型的函数,通常用于回调函数。
2、以下C++代码段会输出什么?
- #include <iostream>
- using namespace std;
- class Base
- {
- public:
- void fun1()
- {
- cout<<"Base::fun1()"<<endl;
- }
- virtual void fun2()
- {
- cout<<"Base::fun2()"<<endl;
- }
- };
- class Derived : public Base
- {
- public:
- void fun1()
- {
- cout<<"Derived::fun1()"<<endl;
- }
- void fun2()
- {
- cout<<"Derived::fun2()"<<endl;
- }
- };
- int main(int argc,char *argv[])
- {
- Base *pBase = new Derived;
- pBase->fun1();
- pBase->fun2();
- return 0;
- }
输出结果是什么?
答:Base::fun1()
Derived::fun2()
分析:主要考察虚函数。
3、最后一道题:判断一个int类型的整型数字是否为回文数。回文数即从左往右,从右往左看,数字结果都一样的数字,例如:232、44、56365等。
使用用C++实现函数bool IsHuiWen(int iNumber);该函数用于判断一个数字是否为回文数。
代码如下:
- #include <iostream>
- #include <cmath>
- using namespace std;
- /**
- * @brief Determine whether an integer is a palindrome.
- *
- * @param[in] iNumber The number will be judge.
- *
- * @return true if iNumber is a palindrome, otherwise return false.
- */
- bool Ispalindrome(int iNumber)
- {
- char pStr[10];//由于int占4个字节,最大正数为65535,所以此处10个字符足够了
- //1.将整数转换成字符串
- //itoa(iNumber, pStr, 10);//Linux下POSIX库整数转换成字符串使用itoa()函数
- _itoa_s(iNumber, pStr, 10);//Windows下推荐使用的替代函数:_itoa_s
- cout<<"string:"<<pStr<<endl;
- int index_start=0;
- int index_end = strlen(pStr)-1;
- while(index_start <= index_end)
- {
- if(pStr[index_start] != pStr[index_end])
- {
- return false;
- }
- else
- {
- index_start++;
- index_end--;
- }
- }
- return true;
- }
- int main(int argc, char *argv[])
- {
- int n;
- cout<<"Please input an integer:";
- cin>>n;
- if(Ispalindrome(n))
- {
- cout<<n<<" is a palindrome."<<endl;
- }
- else
- {
- cout<<n<<" is not a palindrome."<<endl;
- }
- return 0;
- }