c++各个公司面试题目

上海聚力传媒技术有限公司VC笔试题解答

 

1.实模式和保护模式
实模式,又叫实地址模式,CPU完全按照8086的实际寻址方法访问00000h-FFFFFh(1MB)的地址范围额的内存,在这种模式下,cpu只能做单任务运行,寻址方式为物理地址=左移4位的段地址+偏移地址,即物理地址是由16位的段地址和16为的段内偏移地址组成。
保护模式,又叫内存保护模式,寻址采用32位段和偏移量,最大寻址空间4g,在这种模式下,系统运行与多任务,设计这种模式的原因和好处是:保护模式增加了寻址空间,增加了对多任务的支持,增加了段页寻址机制的内存管理(分段机制使得段具有访问权限和特权级,各应用程序和操作系统的代码和核心是被保护的,这也是多任务支持的实现关键和保护这个名字的又来)。寻址过程:物理地址= 由段地址查询全局描述符表中给出的段基址+偏移地址,即:物理地址由影像寄存器中的基址加上16位或者32位的偏移组成。

2.描述并比较以下对象:事件,信标,临界区,互斥对象。
临界区:一种保证在某一时刻只有一个线程能访问数据的简便办法。它只可以在同一进程内部使用。主要API函数有,产生临界区: InitializeCriticalSection,删除临界区:DeleteCriticalSection,进入临界区: EnterCriticalSection,退出临界区:LeaveCriticalSection。
互斥对象:互斥对象跟临界区相似,但它不仅仅能够在同一应用程序不同线程中实现资源的安全共享,而且可以在不同应用程序的线程之间实现对资源的安全共享,当然下面两者也有这个特点。主要API函数有,创建互斥量: CreateMutex,打开一个存在的互斥量: OpenMutex,释放互斥量的使用权:ReleaseMutex,关闭互斥量:CloseHandle。
信标:使用信号量(信标)最重要用途是:信号允许多个线程同时使用共享资源,它指出了同时访问共享资源的线程最大数目。它的API函数和使用方法都与互斥对象相似,如创建信号灯:CreateSemaphore,传入的参数可以指定信号灯的初始值。
事件:用来通知其他进程/线程某件操作已经完成。API函数有创建,打开事件对象等,特殊点的是可以用函数SetEvent人工设置事件为有无信号状态,因此创建事件对象时可以有两种方式,一种为自动重置,一种为人工重置。只有人工重置方式创建的事件对象才能正确使用函数SetEvent。
在MFC中对于各种同步对象都提供了相对应的类CCtiticalSection,CMutex,CSemaphore ,CEvent,另外为使用等待功能封装了两个类:CSingleLock和CMultiLock。这些类方便了使用这些同步对象。

3.cdecl、stdcall、fastcall是什么?哪种可以实现个数不定的入口参数,为什么?
都是函数调用的约定。
cdecl:c declare(C调用约定)的缩写,是C和C++程序的缺省调用方式,规则是,按从右至左的顺序压参数入栈,由调用者把参数弹出栈,对于传送参数的内存栈是由调用者来维护的,正因为如此,只有这种调用方式可实现个数不定的入口参数(可变参数)。
stdcall:是Pascal程序的缺省调用方式,规则是,按从右至左的顺序压参数入栈,被调用的函数在返回前清理传送参数的内存栈。
上两者的主要区别是前者由调用者清理栈,后者由被调用的函清理栈。当然函数名的修饰部分也是不同的。
fastcall:采用寄存器传递参数,特点就是快了。

4、有一段文本,统计其中的单词数。

/*----------------------------------------------------

如果一个字符串,他的前后都是空格
那么这就是一个单词而不能用字符来判断
--------------------------------------------------------*/
int WordNum(char* WordSting)
{
int wordnum = 0;
int len = (int)strlen(WordSting);
char* pTemp = WordSting;
int index = 0;
while (index < len)
{
while (*pTemp!=' ')
{
pTemp++;
++index;
}
wordnum++;//单词数加一
while (*pTemp==' ')
{
pTemp++;
++index;
}
}

return wordnum;
}

int main()
{
char* text = "As a technology, 'HailStorm' is so new that it is still only known by its code name.";
printf("Word number is %d/n", WordNum(text));
return 0;
}

 

瑞星笔试题目

1.判断回文。 2.求N!。 3.查找两个字符串的最大公共字串。 4.二叉树的分层遍历。 5.什么是进程和线程,及其区别。 6.进程之间的通讯方法。

 

贝尔实验室笔试题目

 

一、请填写BOOL , float, 指针变量 与“零值”比较的 if 语句。(10分)

  请写出 BOOL flag 与“零值”比较的 if 语句。(3分)

  标准答案:
  if ( flag )
  if ( !flag ) 如下写法均属不良风格,不得分。
  if (flag == TRUE)
  if (flag == 1 )
  if (flag == FALSE)
  if (flag == 0)

  请写出 float x 与“零值”比较的 if 语句。(4分)
  标准答案示例:
  const float EPSINON = 0.00001;
  if ((x >= - EPSINON) && (x <= EPSINON)
  不可将浮点变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”此类形式。
  如下是错误的写法,不得分。
  if (x == 0.0)
  if (x != 0.0)

  请写出 char *p 与“零值”比较的 if 语句。(3分)
  标准答案:
  if (p == NULL)
  if (p != NULL) 如下写法均属不良风格,不得分。
  if (p == 0)
  if (p != 0)
  if (p)
  if (!)

  二、以下为Windows NT下的32位C++程序,请计算sizeof的值(10分)
  char str[] = “Hello” ;
  char *p = str ;
  int n = 10;
  请计算
  sizeof (str ) = 6 (2分)
  sizeof ( p ) = 4 (2分)
  sizeof ( n ) = 4 (2分) void Func ( char str[100])
  {
  请计算
  sizeof( str ) = 4 (2分)
  }
  void *p = malloc( 100 );
  请计算
  sizeof ( p ) = 4 (2分)

  三、简答题(25分)

  1、头文件中的 ifndef/define/endif 干什么用?(5分)
  答:防止该头文件被重复引用。

  2、#include? 和 #include “filename.h” 有什么区别?(5分)
  答:对于#include? ,编译器从标准库路径开始搜索 filename.h
  对于#include “filename.h” ,编译器从用户的工作路径开始搜索 filename.h

  3、const 有什么用途?(请至少说明两种)(5分)
  答:(1)可以定义 const 常量

  (2)const可以修饰函数的参数、返回值,甚至函数的定义体。被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。

  4、在C++ 程序中调用被 C编译器编译后的函数,为什么要加 extern “C”? (5分)

  答:C++语言支持函数重载,C语言不支持函数重载。函数被C++编译后在库中的名字与C语言的不同。假设某个函数的原型为: void foo(int x, int y);

  该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。C++提供了C连接交换指定符号extern“C”来解决名字匹配问题。

  5、请简述以下两个for循环的优缺点(5分)

  for (i=0; i<N; i++)
  {
   if (condition)
   DoSomething();
   else
   DoOtherthing();
  }

  if (condition)
  {
   for (i=0; i<N; i++)
   DoSomething();
  }
  else
  {
   for (i=0; i<N; i++)
   DoOtherthing();
  }

  优点:程序简洁
  缺点:多执行了N-1次逻辑判断,并且打断了循环“流水线”作业,使得编译器不能对循环进行优化处理,降低了效率。 优点:循环的效率高
  缺点:程序不简洁

  四、有关内存的思考题(每小题5分,共20分)

  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");将使程序崩溃。

  char *GetMemory(void)
  {
   char p[] = "hello world";
   return p;
  }

  void Test(void)
  {
char *str = NULL;
   str = GetMemory();
   printf(str);

  }

  请问运行Test函数会有什么样的结果?

  答:可能是乱码。

  因为GetMemory返回的是指向“栈内存”的指针,该指针的地址不是 NULL,但其原现的内容已经被清除,新内容不可知。

  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)内存泄漏
  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)语句不起作用。
  
五、编写strcpy函数(10分)已知strcpy函数的原型是char *strcpy(char *strDest, const char *strSrc);其中strDest是目的字符串,strSrc是源字符串。

  (1)不调用C++/C的字符串库函数,请编写函数 strcpy
  char *strcpy(char *strDest, const char *strSrc);
  {
   assert((strDest!=NULL) && (strSrc !=NULL)); // 2分
   char *address = strDest; // 2分
   while( (*strDest++ = * strSrc++) != ‘/0’ ) // 2分
   NULL ;
   return address ; // 2分

  }

  (2)strcpy能把strSrc的内容复制到strDest,为什么还要char * 类型的返回值?
  答:为了实现链式表达式。 // 2分

  例如 int length = strlen( strcpy( strDest, “hello world”) );
  六、编写类String的构造函数、析构函数和赋值函数(25分)

  已知类String的原型为:
  class String
  {

  public:
   String(const char *str = NULL); // 普通构造函数
   String(const String &other); // 拷贝构造函数
   ~ String(void); // 析构函数
  String & operate =(const String &other); // 赋值函数
   private:
  char *m_data; // 用于保存字符串
  };

  请编写String的上述4个函数。
  标准答案:

  // String的析构函数
  String::~String(void) // 3分
  {
   delete [] m_data;
   // 由于m_data是内部数据类型,也可以写成 delete m_data;
  }

  // String的普通构造函数
  String::String(const char *str) // 6分
 {
   if(str==NULL)
   {
   m_data = new char[1]; // 若能加 NULL 判断则更好
    *m_data = ‘/0’;
   }
   else
   {
   int length = strlen(str);
  m_data = new char[length+1]; // 若能加 NULL 判断则更好
   strcpy(m_data, str);
   }

  }

  // 拷贝构造函数
  String::String(const String &other) // 3分
  {
   int length = strlen(other.m_data);
   m_data = new char[length+1]; // 若能加 NULL 判断则更好
   strcpy(m_data, other.m_data);
  }

  // 赋值函数
  String & String::operate =(const String &other) // 13分
  {
   // (1) 检查自赋值 // 4分
   if(this == &other)
   return *this;
   // (2) 释放原有的内存资源 // 3分
   delete [] m_data;
   // (3)分配新的内存资源,并复制内容 // 3分
   int length = strlen(other.m_data);
   m_data = new char[length+1]; // 若能加 NULL 判断则更好
   strcpy(m_data, other.m_data);
   // (4)返回本对象的引用 // 3分
return *this;
}

 

sony 笔试题目

 

//冒泡排序//最小的放在最后

void BubbleInsertSort(int arr[], int size)
{
   for(int i = 0; i < size-1; ++i)
   {   //最小的放在后面
        for(int j = 0; j < size-1-i; ++j)
        {
              if(arr[j+1]>arr[j])
              {
                    int temp = arr[j+1];
                    arr[j+1] = arr[j];
                    arr[j] = temp;
              }
      }
  }
}

//直接插入排序

void InsertSort(int arr[], int size)
{
    for(int i = 1; i < size; ++i)
   {
         int temp = arr[i];
        for(int j = i-1; (j>-1)&&(arr[j]        {
             arr[j+1] = arr[j];
        }
       arr[j+1] = temp;
    }
}

//二分插入排序

void HalfInsertSort(int arr[], int size) {
    for(int i = 1; i < size; ++i)
     {
           int temp = arr[i];
           int low = 0;
           int high = i-1;
          while(low<=high)
          {
                int middle = (low+high)/2;
                if(temp>arr[middle])
                {
                       high = middle-1;
                 }
                else
                {
                         low = middle+1;
                 }
         }
         for(int k = i-1; k > high; --k)
         {
              arr[k+1] = arr[k];
         }

        arr[high+1] = temp;
  
   }
}

//选择排序
void SelectSort(int arr[], int size)
{
     for(int i = 0; i < size -1; ++i)
     {
         int temp = arr[i]; 
         int k = i;
         for(int j = i ; j < size; ++j)
         {
                if(arr[j]>temp)
               {
                   k = j;

                  temp = arr[j];
               }
         }
         if(k!=i)
        {
               int temp = arr[k];
               arr[k] = arr[i];
               arr[i] = temp;
        }
    }
}

//快速排序

int FastSort(int arr[], int low, int high)
{
     int key = arr[low];
     while (low<high )
  {
          while(low < high && (arr[high] >= key))
         high--;        
          arr[low] = arr[high];   //将比轴大的移动到低端

         while(low<high && (arr[low] <= key))
              low++;
          arr[high] = arr[low];  //将比轴小的移动到高端
    }

    arr[low] = key;            //update轴
    return low;                //返回轴的位置
}

void QuickFastSort(int arr[], int low, int high)
{
       if(low<=high)
    {
               int split = FastSort(arr, low, high);
               QuickFastSort(arr, low, split-1);
               QuickFastSort(arr, split+1, high);   
      }
}
 

int main()
{
     int array[]={45,56,76,234,1,34,23,2,3}; //数字任意给出
     QuickFastSort(array, 0, 8);
    for(int i = 0; i < 9 ; ++i)
    {
           printf("%d  ", array[i]);
    } 
     return 0;
}

 

复合类

 

1.在C++怎样中检测内存泄漏。
2.设备坐标和逻辑坐标的区别(MFC).
3.如何不失真的放大和缩小一个图片?
4.GDI是属于系统还是进程的?
5.系统的资源有那些(MFC)?
6.如何局部刷新视图?
7.MFC的消息机制?
8.下面的程序有什么错误?
 detyped unsinged long DWORD;
void Test(DWORD i, DWORD j)
{
   if (i -j < 0)
   {
     return ;
   }
}

最近看到几家软件公司的笔试题目,发现竟然存在错误。

1.类的常量在声明时赋值。

2.指针没有初始化,这个错误最多。

3.带返回值的函数参数没有定义为指针或者引用。

 

另附:

1线程是指进程内的一个执行单元,也是进程内的可调度实体。线程作为调度和分配的基本单位,进程作为拥有资源的基本单位。
进程是拥有资源的 一个独立的单位, 线程不拥有系统资源,但可访问隶属进程的资源。
2.系统开销,在创建或者撤销进程时, 由于系统都要为之 分配和回收资源,导致系统明显大于创建或者撤销线程的开销。

windows的内存管理??
c++编译器的需表是怎样完成的??

如果只想程序只有一个实例运行怎样实现?
用内存映射,互斥变量,查找窗口句柄。

如何截取键盘的响应,让所有的‘a’变成‘b’?
键盘钩子setwindowHookEX.

Template 有什么特点?什么时候用?

 


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";

if(str1==str2)
{
printf("%s","ok/n");
}
if(str3==str4)
{
printf("%s","ok/n");
}
if(str5==str6)//str5==str6==str7==str8 all these pointers all point to the same address of"abc" namely, these of "abc" 实际是在内存中仅仅分配了一个存储区。
{
printf("%s","ok/n");
}
if(str7==str8)
{
printf("%s","ok/n");
}

str1,str2,str3,str4是数组变量,他们有各自的内存空间。
str5,str6,str7,str8是指针,他们指向相同的常量区。

 

void main()
{

int a[]={1,2,3,4,5};
int *ptr=(int*)(&a+1);

printf("%d,%d",*(a+1),*(ptr-1));
}

输出 2,5

&a+1不是首地址+1,系统会认为加上一个a数组的偏移,是偏移了一个数组的大小,5个int
int *ptr = (int*)(&a+1);则ptr实际上&a[5],也就是a+5。
&a是数组指针,其类型是int(*)[5]; a,&a的地址是一样的,但意思不一样,a是数组首地址,&a是对象(数组)首地址,a+1是 数组下一个元素
的地址,即a[1],而&a+1是一个对象的地址,即a[5].

下面代码会出现什么问题?
char a;
char* str = &a;
strcpy(str, "hello");
printf("%s",str);


#define Min(X,Y) ((X)<(Y)?(X):(Y))


int (*s[10])(int) 是函数指针数组,也就是是一个数组,共有10也元素,每个成员是指向int fun(int)函数的函数指针。

进程死锁的原因?资源竞争及进程推进顺序非法。
死锁的4个必要条件?互斥 请求保持 不可剥夺 环路。
死锁的处理?鸵鸟策略 预防策略 避免策略 检测与解除策略。

数组顺序存储,固定大小
链表随机存储,大小可以改变。

应用层 会话层,表示层,传输层,网络层,数据链路层,物理层。
tcp/udp传输层
tcp 服务提供了数据流传输,可靠,有效流控制,全双工操作和多路服用技术等。
UDP并不提供对IP的可靠机制,流控制及错误恢复功能,

用绝对地址执行一个函数的调用
typedef void(*)() voidFuncPtr.

(void(*)())0x10000;
*((void(*)())0x10000)();


char(*str)[20]:str数组指针,指向数组的指针
char* str[20]:指针数组,元素为指针型数据。

struct A
{
char t:4;
char K:4;
unsigned short i:8;
unsigned long m;
};

int size = sizeof(A);//size = 8

5. 以下代码有什么问题?
cout << (true?1:"1") << endl;
答:三元表达式“?:”问号后面的两个操作数必须为同一类型。


6. 以下代码能够编译通过吗,为什么?
unsigned int const size1 = 2;
char str1[ size1 ];
unsigned int temp = 0;
cin >> temp;
unsigned int const size2 = temp;
char str2[ size2 ];
答:str2定义出错,size2非编译器期间常量,而数组定义要求长度必须为编译期常量。


struct CLS
{
int m_i;
CLS(int i):m_i(i){}
CLS()
{
CLS(0);//不会调用m_i(i)也就是不会初始化m_i
}

};
int _tmain(int argc, _TCHAR* argv[])
{

CLS obj;
int i = obj.m_i;
int kp = 3;
}

class Empty
{
public:
Empty(); // 缺省构造函数
Empty( const Empty& ); // 拷贝构造函数
~Empty(); // 析构函数
Empty& operator=( const Empty& ); // 赋值运算符
Empty* operator&(); // 取址运算符
const Empty* operator&() const; // 取址运算符 const
};

11. 以下代码有什么问题?
typedef vector IntArray;
IntArray array;
array.push_back( 1 );
array.push_back( 2 );
array.push_back( 2 );
array.push_back( 3 );
// 删除array数组中所有的2
for( IntArray::iterator itor=array.begin(); itor!=array.end(); ++itor )
{
if( 2 == *itor ) array.erase( itor );
}

答:同样有缺少类型参数的问题。另外,每次调用“array.erase( itor );”,被删除元素之后的内容会自动往前移,导致迭代漏项,应在删除一项后使itor--,使之从已经前移的下一个元素起继续遍历。

1.3 如何“动态联编”

编译器是如何针对虚函数产生可以再运行时刻确定被调用函数的代码呢?也就是说,虚函数实际上是如何被编译器处理的呢?Lippman在深度探索C++对象模型[1]中的不同章节讲到了几种方式,这里把“标准的”方式简单介绍一下。

我所说的“标准”方式,也就是所谓的“VTABLE”机制。编译器发现一个类中有被声明为virtual的函数,就会为其搞一个虚函数表,也就是VTABLE。VTABLE实际上是一个函数指针的数组,每个虚函数占用这个数组的一个slot。一个类只有一个VTABLE,不管它有多少个实例。派生类有自己的VTABLE,但是派生类的VTABLE与基类的VTABLE有相同的函数排列顺序,同名的虚函数被放在两个数组的相同位置上。在创建类实例的时候,编译器还会在每个实例的内存布局中增加一个vptr字段,该字段指向本类的VTABLE。通过这些手段,编译器在看到一个虚函数调用的时候,就会将这个调用改写,针对1.1中的例子:

void bar(A * a)
{
a->foo();
}

会被改写为:

void bar(A * a)
{
(a->vptr[1])();
}

因为派生类和基类的foo()函数具有相同的VTABLE索引,而他们的vptr又指向不同的VTABLE,因此通过这样的方法可以在运行时刻决定调用哪个foo()函数。

虽然实际情况远非这么简单,但是基本原理大致如此。

 

38. 如何判断一段程序是由C 编译程序还是由C++编译程序编译的?
答案:
#ifdef __cplusplus
cout<<"c++";
#else
cout<<"c";
#endif

 

TCL 笔试题目

 

void ex(char **a,char **b)
{
char *c;
c=*a;
*a=*b;
*b=c;
}
int main()
{
char *pt="pt/n";
char *pt_another="pt_another/n";
cout<<pt<<pt_another;
ex(&pt,&pt_another);
cout<<pt<<pt_another;
system("pause");
}

 百度面试

 

问到的题目如下:1.排序二叉树,线性表,hash的区别?2.然后一道查找算法?3.java多线程知道多少说多少?4.设计模式知道多少说多少,画UML图,写单件模式,考虑同步?5.堆排序,写代码

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值