zoukankan      html  css  js  c++  java
  • C++/C 程序员要掌握的问题集锦之一

    Q:请定义一个宏,比较两个数a、b的大小,不能使用大于、小于、if语句
    A:define max(a,b) ( a/b)?a:b

    //---------------------------------------------------------------------------------------

    Q:写一个病毒
    A:
     while (1)
            {
                   int *p = new int[10000000];
            }

    //---------------------------------------------------------------------------------------

    Q:有A、B、C、D四个人,要在夜里过一座桥。他们通过这座桥分别需要耗时1、2、5、10分钟,只有
    一支手电,并且同时最多只能两个人一起过桥。请问,如何安排,能够在17分钟内这四个人都过桥?
    A:
    答案:
    第一步:A(1)和B(2)过桥,A(1)返回 Cost:1+2
    第二步: C(5)和D(10)过桥,B(2)返回 Cost:10+2
    第三步: A(1)和B(2)过桥 Cost:2

    //---------------------------------------------------------------------------------------

    Q:实现strlen函数,不许用任何变量~
    A:
    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string>

    using namespace std;

    int myStrlen(const char *str)
    {
     return  *str ? ( *(str+1) ? ( 1 + myStrlen(str+1) ) : 1 ) : 0 ;
    }

    int main()
    {
     char *orig = "Hello, World!";
     
     cout << orig << " (char *)" << endl;
     cout << myStrlen(orig) << endl;

     return 0;
    }

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    把 *str ? ( *(str+1) ? ( 1 + myStrlen(str+1) ) : 1 ) : 0  展开来

    int myStrlen(const char *str)
    {
     if( *str != 0 )
     {
      if( *(str+1) != 0 )
      {
       return ( 1 + myStrlen(str+1) );
      }
      else
      {
       return 1;
      } 
     }
     else
     {
      return 0;
     } 
    }

    //---------------------------------------------------------------------------------------

    Q:用递归写出 x! = x * (x-1) * (x-2) * (x-3) * ... * 2 * 1
    A:

    unsigned short factorial(unsigned short a);

    int main(void)
    {
     int num;
     int total;
     cout<<"请输入数据: "<<endl;
     cin>>num; 
     total = factorial(num);
     cout<<"结果为: "<<total<<endl;
     return 0;
    }

    factorial(a)
    {
     if( a == 1 )
     {
      return 1;
     }
     else
     {
      a *= factorial(a-1);
      return a;
     }
    }

    //---------------------------------------------------------------------------------------

    Q:下列哪两个是等同的
    int b;
    A const int* a = &b;
    B const* int a = &b;
    C const int* const a = &b;
    D int const* const a = &b;

    答:  (C = D) 这两个是等同的  都表示常量指针常量(指针本身是常量,而且所指内容也是常量)  
    A const int* a = &b;         //常量指针,只能够读出内存的数据,却不能修改内存的数据。
    B const* int a = &b;         //非法的。
    C const int* const a = &b;   //内存数据和指针的地址都不能够修改
    D int const* const a = &b;   //内存数据和指针的地址都不能够修改
    E int * const a = &b;        //指针常量,指针的地址不能够修改,只能指向b。

    //---------------------------------------------------------------------------------------

    Q:内联函数在编译时是否做参数类型检查?  
    void g(base & b)
    {
     b.play;    
    }    
       
    void main()
    {
     son s;    
     g(s);    
     return;    
    }

    A:
    内联函数要做参数类型检查, 这是内联函数跟宏相比的优势。

    //---------------------------------------------------------------------------------------

    Q:C++函数中值的传递方式有哪几种?
    A:
    C++函数中值的传递有三种传递方式:1.值传递 2.指针传递 3.引用传递

    //---------------------------------------------------------------------------------------

    Q:头文件的作用是什么?
    A:
    1.通过头文件调用程序库功能,用户只需要按照头文件中的接口声明来调用库功能,而不必关心接口怎么实现的,编译器会从程序库里提取相应的代码。
    2.加强类型的安全检查,函数或者接口被使用时候,方式和头文件中的声明不一致,编译器会之处错误。

    //---------------------------------------------------------------------------------------

    Q:内存的分配方式的分配方式有几种?
    A:
    1.从静态存储区域分配,内存编译的时候就已经分配好了,这块内存在程序的整个运行期间都存在,例如:全局变量,静态变量。
    2.在栈上创建,在执行函数时,函数内局部变量的存储单元可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内分配运算内置于处理器的指令集中,效率很高,但是分配内存容量有限。
    3.从堆上分配,亦称动态内存分配。程序运行的时候用malloc或new申请任意多少的内存,程序员自己负责在任何时用free或delete释放内存。

    //---------------------------------------------------------------------------------------

    Q:实现双向链表删除一个节点P,在节点P后插入一个节点,写出这两个函数;
    A:
    typedef struct DNode
    {
     int date;
     DNode * prior;
     DNode * next;
    };

    DNode * DList;

    void insertNode(DList &list, int pValue)
    {
     DList p = list;
     
     if( p == NULL )
      return;
      
     while( p->date != pValue )
     {
      p = p->next;
     }
     
     DNode *q = new DNode();
     
     p->date = pValue;
     p->next->prior = q;
     q->next = p->next;
     p->next = q;
     q->prior = p;

    }

    void deleteNode(DList &list, int pValue)
    {
     DList p = list;
     
     if( p == NULL )
      return;
     
     while( p->date != NULL )
     {
      p = p->next;
     }
     
     p->prior->next = p->next;
     p->next->prior = p->prior;
     
     //free p;
     delete p;
    }

    //---------------------------------------------------------------------------------------

    Q:C++里面是不是所有的动作都是main()引起的?如果不是,请举例.
    A:
    当然不是所有的动作都是main()引起的,只是编译器由main()开始执行的
    静态变量和全局变量的分配早在main之前完成
    内联,模板,函数声明,宏的扩展全是预编译期行为,也不是main()完成的
    注:C++和main()逻辑上没有必然的联系。

    //---------------------------------------------------------------------------------------

    Q:如何定义和实现一个类的成员函数为回调函数?
    A:
      把成员函数申明为static就可以了。
     
    //---------------------------------------------------------------------------------------

    Q:C++里面如何声明const void f(void)函数为C程序中的库函数?
    A:
    extern "C" void f(void);
    所以extern "C"是强迫C++编译器对函数名进行修饰的时候采用C命名约定。

    //---------------------------------------------------------------------------------------

    Q:Windows程序的入口是哪里?写出Windows消息机制的流程。
    A:
    入口点是WinMain函数.

    Windows消息机制的流程:

    1.Windows中有一个系统消息队列,对于每一个正在执行的Windows应用程序,系统为其建立一个“消息队列”,即应用程序队列,用来存放该程序可能创建的各种窗口的消息。应用程序中含有一段称作“消息循环”的代码,用来从消息队列中检索这些消息并把它们分发到相应的窗口函数中。

    2.Windows为当前执行的每个Windows程序维护一个「消息队列」。在发生输入事件之后,Windows将事件转换为一个「消息」并将消息放入程序的消息队列中。程序通过执行一块称之为「消息循环」的程序代码从消息队列中取出消息:

    while(GetMessage (&msg, NULL, 0, 0))
    {
        TranslateMessage (&msg) ;
        DispatchMessage (&msg) ;
    }

    TranslateMessage(&msg);将msg结构传给Windows,进行一些键盘转换。
    DispatchMessage (&msg);又将msg结构回传给Windows。然后,Windows将该消息发送给适当的窗口消息处理程序,让它进行处理。

    SendMessage()与PostMessage()之间的区别是什么?
    它们两者是用于向应用程序发送消息的。PostMessagex()将消息直接加入到应用程序的消息队列中,不等程序返回就退出;而SendMessage()则刚好相反,应用程序处理完此消息后,它才返回。

    //---------------------------------------------------------------------------------------

    Q:把一个链表反向填空
    A:
    void reverse(test* head)
    {
     test* pe = head;
     test* ps = head->next;
     while(ps)
     {
      //方法一 pe是固定不动
      pe->next = ps->next;
      ps->next = head;
      head = ps;
      ps = pe->next;
      
      //方法二 pe ps head 都向后移动
      //head = ps->next;
      //ps->next = pe;
      //pe = ps;
      //ps = head;
     }
    }

    //---------------------------------------------------------------------------------------

    Q:什么函数不能成为虚函数?
    A:
    构造函数()
    内联函数(因为没有函数地址,在编译时插入,是个静态行为。)
    静态成员函数(因为静态成员函数类似于全局函数,但是属于相应的类,在相应类的作用域下,没有this指针)

    //--------------------------------------------------------------------------------------

    Q:虚函数与接口的区别?
    A:
    虚函数的概念:
    虚函数是动态联编的基础,它是引入派生概念之后用来表现基类和派生类成员函数之间的一种关系。虚函数在基类中定义,它也是一种成员函数,而且非静态成员函数。
    若一个实例方法的声明中含有virtual修饰符,则称该方法为虚拟方法;一个虚拟方法的实现可以派生类取代。取代所继承的虚拟方法的实现的过程称为重写(覆盖)该方法;在一个虚拟方法调用中,该调用所涉及的那个实例的运行时类型确定了要被调用的究竟是该方法的哪一个实现。
    虚函数的限制:
    1.虚函数仅适用于有继承关系的类对象,所以只有类的成员函数才能说明为虚函数。
    2.静态成员函数不能是虚函数。
    3.内联函数不能是虚函数。
    4.构造函数不能是虚函数。
    5.析构函数可以是虚函数。

    接口可以有静态成员、嵌套类型、抽象、虚拟成员、属性和事件。实现接口的任何类都必须提供接口中所声明的抽象成员的定义。接口可以要求任何实现类必须实现一个或多个其他接口。
    对接口有以下限制:
    接口可以任何可访问性来声明,但接口成员必须全都具有公共可访问性。
    不能向成员或接口自身附加安全性权限。
    接口可以定义类构造函数,但不能定义实例构造函数。
    每种语言都必须为需要成员的接口映射一个实现提供规则,因为不只一个接口可以用相同的签名声明成员,且这些成员可以有单独的实现。
    接口可以有类和结构来实现。为了只是类或结构实现了某接口,在该类或结构的基类列表中应该包含该接口的标识符。如果一个类或结构实现某接口,则它还隐式实现该接口的所有基接口。即使在类或结构的基类列表中没有显式列出所有基类接口,也是这样。


    //--------------------------------------------------------------------------------------

    Q:C++中虚函数怎么实现的?  
    A:
    每个定义了虚函数的类都有一张虚函数表vtbl(virtual function table),这张表实际上是一个函数指针的数组,记录了虚函数的入口地址。只要这个类有虚函数,不管是自己定义的还是从父类继承过来的,那么类的每个实例---对象都有一个指针vptr(virtual function table pointer),它指向类的虚函数表。
    虚函数(多态)机制的三个条件:
    1.派生关系
    2.virtual 属性
    3.指针-->访问方式

    //---------------------------------------------------------------------------------------

    Q:有12个小球,外形相同,其中一个小球的质量与其他11个不同,给一个天平,问如何用3次把这个小球找出来并且求出这个小球是比其他的轻还是重?

    A:
    将12个球分别编号为a1,a2,a3.......a10,a11,a12.
    第一步:将12球分开3拨,每拨4个,a1~a4第一拨,记为b1, a5~a8第2拨,记为b2,其余第3拨,记为b3;
    第二步:将b1和b2放到天平两盘上,记左盘为c1,右为c2;这时候分两中情况:

    1.c1和c2平衡,此时可以确定从a1到a8都是常球;然后把c2拿空,并从c1上拿下a4,从a9到a12四球里随便取三球,假设为a9到a11,放到c2上。此时c1上是a1到a3,c2上是a9到a11。从这里又分三种情况:
     A:天平平衡,很简单,说明没有放上去的a12就是异球,而到此步一共称了两次,所以将a12随便跟11个常球再称一次,也就是第三次,马上就可以确定a12是重还是轻;
     B:若c1上升,则这次称说明异球为a9到a11三球中的一个,而且是比常球重。取下c1所有的球,并将a8放到c1上,将a9取下,比较a8和a11(第三次称),如果平衡则说明从c2上取下的a9是偏重异球,如果不平衡,则偏向哪盘则哪盘里放的就是偏重异球;
     C:若c1下降,说明a9到a11里有一个是偏轻异球。次种情况和B类似,所以接下来的步骤照搬B就是;

    2.c1和c2不平衡,这时候又分两种情况,c1上升和c1下降,但是不管哪种情况都能说明a9到a12是常球。这步是解题的关键。也是这个题最妙的地方。
     A:c1上升,此时不能判断异球在哪盘也不能判断是轻还是重。取下c1中的a2到a4三球放一边,将c2中的a5和a6放到c1上,然后将常球a9放到c2上。至此,c1上是a1,a5和a6,c2上是a7,a8和a9。此时又分三中情况:

      1)如果平衡,说明天平上所有的球都是常球,异球在从c1上取下a2到a4中。而且可以断定异球轻重。因为a5到a8都是常球,而第2次称的时候c1是上升的,所以a2到a4里必然有一个轻球。那么第三次称就用来从a2到a4中找到轻球。这很简单,随便拿两球放到c1和c2,平衡则剩余的为要找球,不平衡则哪边低则哪个为要找球;

      2)c1仍然保持上升,则说明要么a1是要找的轻球,要么a7和a8两球中有一个是重球(这步懂吧?好好想想,很简单的。因为a9是常球,而取下的a2到a4肯定也是常球,还可以推出换盘放置的a5和a6也是常球。所以要么a1轻,要么a7或a8重)。至此,还剩一次称的机会。只需把a7和a8放上两盘,平衡则说明a1是要找的偏轻异球,如果不平衡,则哪边高说明哪个是偏重异球;
     
      3)如果换球称第2次后天平平衡打破,并且c1降低了,这说明异球肯定在换过来的a5和a6两求中,并且异球偏重,否则天平要么平衡要么保持c1上升。确定要找球是偏重之后,将a5和a6放到两盘上称第3次根据哪边高可以判定a5和a6哪个是重球;

     B:第1次称后c1是下降的,此时可以将c1看成c2,其实以后的步骤都同A,所以就不必要再重复叙述了。至此,不管情况如何,用且只用三次就能称出12个外观手感一模一样的小球中有质量不同于其他11球的偏常的球。而且在称的过程中可以判定其是偏轻还是偏重。
     

  • 相关阅读:
    HEOI2017游记
    uoj228:基础数据结构练习题
    bzoj1494【Noi2007】生成树计数
    bzoj1975【Sdoi2010】魔法猪学院
    bzoj2957:楼房重建
    uoj169:元旦老人与数列
    bzoj2178:圆的面积并
    一道好题
    Codeforces Round #440(Div.2)
    Codeforces Round #439 (Div. 2)
  • 原文地址:https://www.cnblogs.com/mtcnn/p/9410152.html
Copyright © 2011-2022 走看看