• 宝典


       1  
       2 
       3 1.new、delete、malloc、free关系
       4 delete会调用对象的析构函数,和new对应free只会释放内存,new调用构造函数。malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。
       5 
       6 2.delete与 delete []区别
       7 delete只会调用一次析构函数,而delete[]会调用每一个成员的析构函数。在More Effective  C++中有更为详细的解释:“当delete操作符用于数组时,它为每个数组元素调用析构函数,然后调用operatordelete来释放内存。”delete与New配套,delete []与new []配套
       8 
       9   MemTest*mTest1=newMemTest[10];
      10 
      11   MemTest*mTest2=newMemTest;
      12 
      13   int*pInt1=newint[10];
      14 
      15   int*pInt2=newint;
      16 
      17   delete[]pInt1;  //-1-
      18 
      19   delete[]pInt2;  //-2-
      20 
      21   delete[]mTest1;//-3-
      22 
      23   delete[]mTest2;//-4-
      24 
      25   在-4-处报错。
      26 
      27 这就说明:对于内建简单数据类型,delete和delete[]功能是相同的。对于自定义的复杂数据类型,delete和delete[]不能互用。delete[]删除一个数组,delete删除一个指针简单来说,用new分配的内存用delete删除用new[]分配的内存用delete[]删除delete[]会调用数组元素的析构函数。内部数据类型没有析构函数,所以问题不大。如果你在用delete时没用括号,delete就会认为指向的是单个对象,否则,它就会认为指向的是一个数组。
      28 
      29 3.C和C++ 的共同点?不同之处?
      30 4.继承的优缺点。
      31 类继承是在编译时刻静态定义的,且可直接使用,类继承可以较方便地改变父类的实现。但是类继承也有一些不足之处。首先,因为继承在编译时刻就定义了,所以无法在运行时刻改变从父类继承的实现。更糟的是,父类通常至少定义了子类的部分行为,父类的任何改变都可能影响子类的行为。如果继承下来的实现不适合解决新的问题,则父类必须重写或被其他更适合的类替换。这种依赖关系限制了灵活性并最终限制了复用性。
      32 
      33 (待补充)
      34 
      35  
      36 
      37 5.C++有哪些性质(面向对象特点)
      38 封装,继承和多态。
      39 
      40 在面向对象程序设计语言中,封装是利用可重用成分构造软件系统的特性,它不仅支持系统的可重用性,而且还有利于提高系统的可扩充性;消息传递可以实现发送一个通用的消息而调用不同的方法;封装是实现信息隐蔽的一种技术,其目的是使类的定义和实现分离。
      41 
      42 6.子类析构时要调用父类的析构函数吗?
      43 析构函数调用的次序是先派生类的析构后基类的析构,也就是说在基类的的析构调用的时候,派生类的信息已经全部销毁了定义一个对象时先调用基类的构造函数、然后调用派生类的构造函数;析构的时候恰好相反:先调用派生类的析构函数、然后调用基类的析构函数JAVA无析构函数深拷贝和浅拷贝
      44 
      45 7.多态,虚函数,纯虚函数
      46 多态:是对于不同对象接收相同消息时产生不同的动作。C++的多态性具体体现在运行和编译两个方面:在程序运行时的多态性通过继承和虚函数来体现;
      47 
      48 在程序编译时多态性体现在函数和运算符的重载上
      49 
      50  
      51 
      52 虚函数:在基类中冠以关键字 virtual 的成员函数。 它提供了一种接口界面。允许在派生类中对基类的虚函数重新定义。
      53 
      54 纯虚函数的作用:在基类中为其派生类保留一个函数的名字,以便派生类根据需要对它进行定义。作为接口而存在 纯虚函数不具备函数的功能,一般不能直接被调用。
      55 
      56 从基类继承来的纯虚函数,在派生类中仍是虚函数。如果一个类中至少有一个纯虚函数,那么这个类被称为抽象类(abstract class)。
      57 
      58 抽象类中不仅包括纯虚函数,也可包括虚函数。l抽象类必须用作派生其他类的基类,而不能用于直接创建对象实例。但仍可使用指向抽象类的指针支持运行时多态性。
      59 
      60  
      61 
      62  
      63 
      64  
      65 
      66 8.求下面函数的返回值(微软)
      67 int func(x) 
      68 { 
      69     int countx = 0; 
      70     while(x) 
      71     { 
      72           countx ++; 
      73           x = x&(x-1); 
      74      } 
      75     return countx; 
      76 } 
      77 
      78 假定x = 9999。 答案:8
      79 
      80 思路:将x转化为2进制,看含有的1的个数。
      81 
      82 9.什么是“引用”?申明和使用“引用”要注意哪些问题?
      83 答:引用就是某个目标变量的“别名”(alias),对应用的操作与对变量直接操作效果完全相同。申明一个引用的时候,切记要对其进行初始化。引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,不能再把该引用名作为其他变量名的别名。声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。不能建立数组的引用。
      84 
      85 10.将“引用”作为函数参数有哪些特点?
      861)传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。
      87 
      882)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。
      89 
      903)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。
      91 
      92 11.在什么时候需要使用“常引用”? 
      93 如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。常引用声明方式:const 类型标识符 &引用名=目标变量名;
      94 
      95 例1
      96 
      97 int a ;
      98 const int &ra=a;
      99 ra=1; //错误
     100 a=1; //正确
     101 
     102 例2
     103 
     104 string foo( );
     105 void bar(string & s);
     106 
     107 那么下面的表达式将是非法的:
     108 
     109 bar(foo( ));
     110 bar("hello world");
     111 
     112 原因在于foo( )和"hello world"串都会产生一个临时对象,而在C++中,这些临时对象都是const类型的。因此上面的表达式就是试图将一个const类型的对象转换为非const类型,这是非法的。引用型参数应该在能被定义为const的情况下,尽量定义为const 。
     113 
     114 12.将“引用”作为函数返回值类型的格式、好处和需要遵守的规则?
     115 格式:类型标识符 &函数名(形参列表及类型说明){ //函数体 }
     116 
     117 好处:在内存中不产生被返回值的副本;(注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的。因为随着该局部变量生存期的结束,相应的引用也会失效,产生runtime error! 注意事项:
     118 
     1191)不能返回局部变量的引用。这条可以参照Effective C++[1]的Item 31。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态。
     120 
     1212)不能返回函数内部new分配的内存的引用。这条可以参照Effective C++[1]的Item 31。虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak。
     122 
     1233)可以返回类成员的引用,但最好是const。这条原则可以参照Effective C++[1]的Item 30。主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。
     124 
     1254)流操作符重载返回值申明为“引用”的作用:
     126 
     127 流操作符<<和>>,这两个操作符常常希望被连续使用,例如:cout << "hello" << endl; 因此这两个操作符的返回值应该是一个仍然支持这两个操作符的流引用。可选的其它方案包括:返回一个流对象和返回一个流对象指针。但是对于返回一个流对象,程序必须重新(拷贝)构造一个新的流对象,也就是说,连续的两个<<操作符实际上是针对不同对象的!这无法让人接受。对于返回一个流指针则不能连续使用<<操作符。因此,返回一个流对象引用是惟一选择。这个唯一选择很关键,它说明了引用的重要性以及无可替代性,也许这就是C++语言中引入引用这个概念的原因吧。 赋值操作符=。这个操作符象流操作符一样,是可以连续使用的,例如:x = j = 10;或者(x=10)=100;赋值操作符的返回值必须是一个左值,以便可以被继续赋值。因此引用成了这个操作符的惟一返回值选择。
     128 
     129 例3
     130 
     131 #i nclude <iostream.h>
     132 int &put(int n);
     133 int vals[10];
     134 int error=-1;
     135 void main()
     136 {
     137 put(0)=10; //以put(0)函数值作为左值,等价于vals[0]=10; 
     138 put(9)=20; //以put(9)函数值作为左值,等价于vals[9]=20; 
     139 cout<<vals[0]; 
     140 cout<<vals[9];
     141 } 
     142 int &put(int n)
     143 {
     144 if (n>=0 && n<=9 ) return vals[n]; 
     145 else { cout<<"subscript error"; return error; }
     146 }
     147 
     1485)在另外的一些操作符中,却千万不能返回引用:+-*/ 四则运算符。它们不能返回引用,Effective C++[1]的Item23详细的讨论了这个问题。主要原因是这四个操作符没有side effect,因此,它们必须构造一个对象作为返回值,可选的方案包括:返回一个对象、返回一个局部变量的引用,返回一个new分配的对象的引用、返回一个静态对象引用。根据前面提到的引用作为返回值的三个规则,第2、3两个方案都被否决了。静态对象的引用又因为((a+b) == (c+d))会永远为true而导致错误。所以可选的只剩下返回一个对象了。
     149 
     150 13.“引用”与多态的关系?
     151 引用是除指针外另一个可以产生多态效果的手段。这意味着,一个基类的引用可以指向它的派生类实例。例4
     152 
     153 Class A; Class B : Class A{...};  B b; A& ref = b;
     154 
     155 14.“引用”与指针的区别是什么?
     156 指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。此外,就是上面提到的对函数传ref和pointer的区别。
     157 
     158 15.什么时候需要“引用”?
     159 流操作符<<和>>、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、其它情况都推荐使用引用。以上 2-8 参考:http://develop.csai.cn/c/NO0000021.htm
     160 
     161 16.结构与联合有和区别?
     162 
     163 (1). 结构和联合都是由多个不同的数据类型成员组成, 但在任何同一时刻, 联合中只存放了一个被选中的成员(所有成员共用一块地址空间), 而结构的所有成员都存在(不同成员的存放地址不同)。 
     164  (2). 对于联合的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于结构的不同成员赋值是互不影响的。
     165 
     166 17.面关于“联合”的题目的输出?
     167 a)
     168 
     169 #i nclude <stdio.h>
     170 union
     171 {
     172 int i;
     173 char x[2];
     174 }a;
     175 
     176 
     177 void main()
     178 {
     179 a.x[0] = 10; 
     180 a.x[1] = 1;
     181 printf("%d",a.i);
     182 }
     183 答案:266 (低位低地址,高位高地址,内存占用情况是Ox010A)
     184 
     185 b)
     186 
     187 main() 
     188      { 
     189           union{                   /*定义一个联合*/ 
     190                int i; 
     191                struct{             /*在联合中定义一个结构*/ 
     192                     char first; 
     193                     char second; 
     194                }half; 
     195           }number; 
     196           number.i=0x4241;         /*联合成员赋值*/ 
     197           printf("%c%cn", number.half.first, mumber.half.second); 
     198           number.half.first='a';   /*联合中结构成员赋值*/ 
     199           number.half.second='b'; 
     200           printf("%xn", number.i); 
     201           getch(); 
     202      } 
     203 答案: AB   (0x41对应'A',是低位;Ox42对应'B',是高位)
     204 
     205        6261 (number.i和number.half共用一块地址空间)
     206 
     207 18.关联、聚合(Aggregation)以及组合(Composition)的区别?
     208 涉及到UML中的一些概念:关联是表示两个类的一般性联系,比如“学生”和“老师”就是一种关联关系;聚合表示has-a的关系,是一种相对松散的关系,聚合类不需要对被聚合类负责,如下图所示,用空的菱形表示聚合关系:从实现的角度讲,聚合可以表示为:
     209 
     210 class A {...}  class B { A* a; .....}
     211 
     212 而组合表示contains-a的关系,关联性强于聚合:组合类与被组合类有相同的生命周期,组合类要对被组合类负责,采用实心的菱形表示组合关系:实现的形式是:
     213 
     214 class A{...} class B{ A a; ...}
     215 
     216 19.面向对象的三个基本特征,并简单叙述之?
     217 1. 封装:将客观事物抽象成类,每个类对自身的数据和方法实行protection(private, protected,public)
     218 
     219 2. 继承:广义的继承有三种实现形式:实现继承(指使用基类的属性和方法而无需额外编码的能力)、可视继承(子窗体使用父窗体的外观和实现代码)、接口继承(仅使用属性和方法,实现滞后到子类实现)。前两种(类继承)和后一种(对象组合=>接口继承以及纯虚函数)构成了功能复用的两种方式。
     220 
     221 3. 多态:是将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。
     222 
     223 20.重载(overload)和重写(overried,有的书也叫做“覆盖”)的区别?
     224 常考的题目。从定义上来说:
     225 
     226 重载:是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。
     227 
     228 重写:是指子类重新定义父类虚函数的方法。
     229 
     230 从实现原理上来说:
     231 
     232 重载:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。如,有两个同名函数:function func(p:integer):integer;和function func(p:string):integer;。那么编译器做过修饰后的函数名称可能是这样的:int_func、str_func。对于这两个函数的调用,在编译器间就已经确定了,是静态的。也就是说,它们的地址在编译期就绑定了(早绑定),因此,重载和多态无关!
     233 
     234 重写:和多态真正相关。当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的(晚绑定)。
     235 
     236 21.多态的作用?
     237 主要是两个:
     238 
     239 1. 隐藏实现细节,使得代码能够模块化;扩展代码模块,实现代码重用;
     240 
     241 2. 接口重用:为了类在继承和派生的时候,保证使用家族中任一类的实例的某一属性时的正确调用。
     242 
     243 22.Ado与Ado.net的相同与不同?
     244 除了“能够让应用程序处理存储于DBMS 中的数据“这一基本相似点外,两者没有太多共同之处。但是Ado使用OLE DB 接口并基于微软的COM 技术,而ADO.NET 拥有自己的ADO.NET 接口并且基于微软的.NET 体系架构。众所周知.NET 体系不同于COM 体系,ADO.NET 接口也就完全不同于ADO和OLE DB 接口,这也就是说ADO.NET 和ADO是两种数据访问方式。ADO.net 提供对XML 的支持。
     245 
     246 23.New delete 与malloc free 的联系与区别?
     247 答案:都是在堆(heap)上进行动态的内存操作。用malloc函数需要指定内存分配的字节数并且不能初始化对象,new 会自动调用对象的构造函数。delete 会调用对象的destructor,而free 不会调用对象的destructor.
     248 
     249 24.#define DOUBLE(x) x+x ,i = 5*DOUBLE(5); i 是多少?
     250 答案:i 为30。
     251 
     252 25.有哪几种情况只能用intialization list 而不能用assignment?
     253 答案:当类中含有const、reference 成员变量;基类的构造函数都需要初始化表。
     254 
     255 26. C++是不是类型安全的?
     256 答案:不是。两个不同类型的指针之间可以强制转换(用reinterpret cast)。C#是类型安全的。
     257 
     258 27. main 函数执行以前,还会执行什么代码?
     259 答案:全局对象的构造函数会在main 函数之前执行。
     260 
     261 28. 描述内存分配方式以及它们的区别?
     262 1) 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static 变量。
     263 2) 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集。
     264 3) 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc 或new 申请任意多少的内存,程序员自己负责在何时用free 或delete 释放内存。动态内存的生存期由程序员决定,使用非常灵活,但问题也最多。
     265 
     266 29.structclass 的区别
     267 答案:struct 的成员默认是公有的,而类的成员默认是私有的。structclass 在其他方面是功能相当的。从感情上讲,大多数的开发者感到类和结构有很大的差别。感觉上结构仅仅象一堆缺乏封装和功能的开放的内存位,而类就象活的并且可靠的社会成员,它有智能服务,有牢固的封装屏障和一个良好定义的接口。既然大多数人都这么认为,那么只有在你的类有很少的方法并且有公有数据(这种事情在良好设计的系统中是存在的!)时,你也许应该使用 struct 关键字,否则,你应该使用 class 关键字。 
     268 
     269 30.当一个类A 中没有任何成员变量与成员函数,这时sizeof(A)的值是多少?
     270 答案:如果不是零,请解释一下编译器为什么没有让它为零。(Autodesk)肯定不是零。举个反例,如果是零的话,声明一个class A[10]对象数组,而每一个对象占用的空间是零,这时就没办法区分A[0],A[1]…了。
     271 
     272 31. 在8086 汇编下,逻辑地址和物理地址是怎样转换的?(Intel)
     273 答案:通用寄存器给出的地址,是段内偏移地址,相应段寄存器地址*10H+通用寄存器内地址,就得到了真正要访问的地址。
     274 
     275 32. 比较C++中的4种类型转换方式?
     276 重点是static_cast, dynamic_cast和reinterpret_cast的区别和应用。
     277 
     278 dynamic_casts在帮助你浏览继承层次上是有限制的。它不能被用于缺乏虚函数的类型上,它被用于安全地沿着类的继承关系向下进行类型转换。如你想在没有继承关系的类型中进行转换,你可能想到static_cast
     279 
     280 33.分别写出BOOL,int,float,指针类型的变量a 与“零”的比较语句。
     281 答案:
     282 BOOL :    if ( !a ) or if(a)
     283 int :     if ( a == 0)
     284 float :   const EXPRESSION EXP = 0.000001
     285           if ( a < EXP && a >-EXP)
     286 pointer : if ( a != NULL) or if(a == NULL)
     287 
     288  
     289 
     290 34.请说出const与#define 相比,有何优点?
     291 答案:
     292 
     293 Const作用:定义常量、修饰函数参数、修饰函数返回值三个作用。被Const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。
     294 
     295 1const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。
     296       2) 有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。
     297 
     298 35.简述数组与指针的区别?
     299 数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。指针可以随时指向任意类型的内存块。
     300 (1)修改内容上的差别
     301 char a[] = “hello”;
     302 a[0] = ‘X’;
     303 char *p = “world”; // 注意p 指向常量字符串
     304 p[0] = ‘X’; // 编译器不能发现该错误,运行时错误
     305 (2) 用运算符sizeof 可以计算出数组的容量(字节数)。sizeof(p),p 为指针得到的是一个指针变量的字节数,而不是p 所指的内存容量。C++/C 语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。
     306 char a[] = "hello world";
     307 char *p = a;
     308 cout<< sizeof(a) << endl; // 12 字节
     309 cout<< sizeof(p) << endl; // 4 字节
     310 计算数组和指针的内存容量
     311 void Func(char a[100])
     312 {
     313 cout<< sizeof(a) << endl; // 4 字节而不是100 字节
     314 }
     315 
     316 36.类成员函数的重载、覆盖和隐藏区别?
     317 答案:a.成员函数被重载的特征:
     3181)相同的范围(在同一个类中);
     3192)函数名字相同;
     3203)参数不同;
     3214virtual 关键字可有可无。
     322 b.覆盖是指派生类函数覆盖基类函数,特征是:
     3231)不同的范围(分别位于派生类与基类);
     3242)函数名字相同;
     3253)参数相同;
     3264)基类函数必须有virtual 关键字。
     327  c.“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
     3281)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
     3292)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)
     330 
     331 37.求出两个数中的较大这
     332 There are two int variables: a and b, don’t use “if”, “? :”, “switch”or other judgement statements, find out the biggest one of the two numbers.
     333 
     334 答案:( ( a + b ) + abs( a - b ) ) / 2
     335 
     336 38.如何打印出当前源文件的文件名以及源文件的当前行号?
     337 答案:
     338 cout << __FILE__ ;
     339 cout<<__LINE__ ;
     340 __FILE__和__LINE__是系统预定义宏,这种宏并不是在某个文件中定义的,而是由编译器定义的。
     341 
     342 39. main 主函数执行完毕后,是否可能会再执行一段代码,给出说明?
     343 答案:可以,可以用_onexit 注册一个函数,它会在main 之后执行int fn1(void), fn2(void), fn3(void), fn4 (void);
     344 void main( void )
     345 {
     346 String str("zhanglin");
     347 _onexit( fn1 );
     348 _onexit( fn2 );
     349 _onexit( fn3 );
     350 _onexit( fn4 );
     351 printf( "This is executed first.n" );
     352 }
     353 int fn1()
     354 {
     355 printf( "next.n" );
     356 return 0;
     357 }
     358 int fn2()
     359 {
     360 printf( "executed " );
     361 return 0;
     362 }
     363 int fn3()
     364 {
     365 printf( "is " );
     366 return 0;
     367 }
     368 int fn4()
     369 {
     370 printf( "This " );
     371 return 0;
     372 }
     373 The _onexit function is passed the address of a function (func) to be called when the program terminates normally. Successive calls to _onexit create a register of functions that are executed in LIFO (last-in-first-out) order. The functions passed to _onexit cannot take parameters.
     374 
     375 40.如何判断一段程序是由C 编译程序还是由C++编译程序编译的?
     376 答案:
     377 #ifdef __cplusplus
     378 cout<<"c++";
     379 #else
     380 cout<<"c";
     381 #endif
     382 
     383 41.文件中有一组整数,要求排序后输出到另一个文件中
     384 
     385 答案:
     386 
     387 #i nclude<iostream>
     388 
     389 #i nclude<fstream>
     390 
     391 using namespace std;
     392 
     393 
     394 void Order(vector<int>& data) //bubble sort
     395 {
     396 int count = data.size() ;
     397 for ( int i = 0 ; i < count ; i++)
     398 {
     399 for ( int j = 0 ; j < count - i - 1 ; j++)
     400 {
     401 if ( data[j] > data[j+1])
     402 {
     403 
     404 int temp = data[j] ;
     405 data[j] = data[j+1] ;
     406 data[j+1] = temp ;
     407 }
     408 }
     409 }
     410 
     411 
     412 void main( void )
     413 {
     414 vector<int>data;
     415 ifstream in("c:data.txt");
     416 if ( !in)
     417 {
     418 cout<<"file error!";
     419 exit(1);
     420 }
     421 int temp;
     422 while (!in.eof())
     423 {
     424 in>>temp;
     425 data.push_back(temp);
     426 }
     427 in.close(); //关闭输入文件流
     428 Order(data);
     429 ofstream out("c:
    esult.txt");
     430 if ( !out)
     431 {
     432 cout<<"file error!";
     433 exit(1);
     434 }
     435 for ( i = 0 ; i < data.size() ; i++)
     436 out<<data[i]<<" ";
     437 out.close(); //关闭输出文件流
     438 }
     439 
     440  
     441 
     442 42.链表题:一个链表的结点结构
     443 struct Node
     444 {
     445 int data ;
     446 Node *next ;
     447 };
     448 typedef struct Node Node ;
     449 
     450 
     451 (1)已知链表的头结点head,写一个函数把这个链表逆序 ( Intel)
     452 
     453 Node * ReverseList(Node *head) //链表逆序
     454 {
     455 if ( head == NULL || head->next == NULL )
     456 return head;
     457 Node *p1 = head ;
     458 Node *p2 = p1->next ;
     459 Node *p3 = p2->next ;
     460 p1->next = NULL ;
     461 while ( p3 != NULL )
     462 {
     463 p2->next = p1 ;
     464 p1 = p2 ;
     465 p2 = p3 ;
     466 p3 = p3->next ;
     467 }
     468 p2->next = p1 ;
     469 head = p2 ;
     470 return head ;
     471 }
     472 (2)已知两个链表head1 和head2 各自有序,请把它们合并成一个链表依然有序。(保留所有结点,即便大小相同)
     473 Node * Merge(Node *head1 , Node *head2)
     474 {
     475 if ( head1 == NULL)
     476 return head2 ;
     477 if ( head2 == NULL)
     478 return head1 ;
     479 Node *head = NULL ;
     480 Node *p1 = NULL;
     481 Node *p2 = NULL;
     482 if ( head1->data < head2->data )
     483 {
     484 head = head1 ;
     485 p1 = head1->next;
     486 p2 = head2 ;
     487 }
     488 else
     489 {
     490 head = head2 ;
     491 p2 = head2->next ;
     492 p1 = head1 ;
     493 }
     494 Node *pcurrent = head ;
     495 while ( p1 != NULL && p2 != NULL)
     496 {
     497 if ( p1->data <= p2->data )
     498 {
     499 pcurrent->next = p1 ;
     500 pcurrent = p1 ;
     501 p1 = p1->next ;
     502 }
     503 else
     504 {
     505 pcurrent->next = p2 ;
     506 pcurrent = p2 ;
     507 p2 = p2->next ;
     508 }
     509 }
     510 if ( p1 != NULL )
     511 pcurrent->next = p1 ;
     512 if ( p2 != NULL )
     513 pcurrent->next = p2 ;
     514 return head ;
     515 }
     516 (3)已知两个链表head1 和head2 各自有序,请把它们合并成一个链表依然有序,这次要求用递归方法进行。 (Autodesk)
     517 答案:
     518 Node * MergeRecursive(Node *head1 , Node *head2)
     519 {
     520 if ( head1 == NULL )
     521 return head2 ;
     522 if ( head2 == NULL)
     523 return head1 ;
     524 Node *head = NULL ;
     525 if ( head1->data < head2->data )
     526 {
     527 head = head1 ;
     528 head->next = MergeRecursive(head1->next,head2);
     529 }
     530 else
     531 {
     532 head = head2 ;
     533 head->next = MergeRecursive(head1,head2->next);
     534 }
     535 return head ;
     536 
     537  
     538 
     539 ----------
     540 
     541 41. 分析一下这段程序的输出 (Autodesk)
     542 class B
     543 {
     544 public:
     545 B()
     546 {
     547 cout<<"default constructor"<<endl;
     548 }
     549 ~B()
     550 {
     551 cout<<"destructed"<<endl;
     552 }
     553 B(int i):data(i)    //B(int) works as a converter ( int -> instance of  B)
     554 {
     555 cout<<"constructed by parameter " << data <<endl;
     556 }
     557 private:
     558 int data;
     559 };
     560 
     561 
     562 B Play( B b) 
     563 {
     564 return b ;
     565 }
     566 
     567 (1)                                            results:
     568 int main(int argc, char* argv[])      constructed by parameter 5
     569 {                                     destructed  B(5)形参析构
     570 B t1 = Play(5); B t2 = Play(t1);     destructed  t1形参析构
     571 return 0;               destructed  t2 注意顺序!
     572 }                                     destructed  t1
     573 
     574 (2)                                   results:
     575 int main(int argc, char* argv[])      constructed by parameter 5
     576 {                                     destructed  B(5)形参析构
     577 B t1 = Play(5); B t2 = Play(10);     constructed by parameter 10
     578 return 0;               destructed  B(10)形参析构
     579 }                                     destructed  t2 注意顺序!
     580 
     581                                       destructed  t1
     582 
     583 43.写一个函数找出一个整数数组中,第二大的数 (microsoft)
     584 答案:
     585 const int MINNUMBER = -32767 ;
     586 int find_sec_max( int data[] , int count)
     587 {
     588 int maxnumber = data[0] ;
     589 int sec_max = MINNUMBER ;
     590 for ( int i = 1 ; i < count ; i++)
     591 {
     592 if ( data[i] > maxnumber )
     593 {
     594 sec_max = maxnumber ;
     595 maxnumber = data[i] ;
     596 }
     597 else
     598 {
     599 if ( data[i] > sec_max )
     600 sec_max = data[i] ;
     601 }
     602 }
     603 return sec_max ;
     604 }
     605 
     606 44.写一个在一个字符串(n)中寻找一个子串(m)第一个位置的函数。
     607 KMP算法效率最好,时间复杂度是O(n+m),
     608 
     609 46.多重继承的内存分配问题:
     610 
     611 比如有class A : public class B, public class C {} 那么A的内存结构大致是怎么样的?
     612 这个是compiler-dependent的, 不同的实现其细节可能不同。如果不考虑有虚函数、虚继承的话就相当简单;否则的话,相当复杂。可以参考《深入探索C++对象模型
     613 
     614 47.如何判断一个单链表是有环的?(注意不能用标志位,最多只能用两个额外指针)
     615 
     616 struct node { char val; node* next;}
     617 bool check(const node* head) {} //return false : 无环;true: 有环一种O(n)的办法就是(搞两个指针,一个每次递增一步,一个每次递增两步,如果有环的话两者必然重合,反之亦然):
     618 bool check(const node* head)
     619 {
     620     if(head==NULL)  return false;
     621     node *low=head, *fast=head->next;
     622     while(fast!=NULL && fast->next!=NULL)
     623     {
     624         low=low->next;
     625         fast=fast->next->next;
     626         if(low==fast) return true;
     627     }
     628     return false;
     629 }
     630 
     631  
     632 
     633 48.指针找错题
     634 分析这些面试题,本身包含很强的趣味性;而作为一名研发人员,通过对这些面试题的深入剖析则可进一步增强自身的内功。
     635   2.找错题 试题1:
     636 以下是引用片段:
     637 void test1()  //数组越界
     638   {
     639   char string[10];
     640   char* str1 = "0123456789";
     641   strcpy( string, str1 );
     642   }
     643   试题2: 
     644 以下是引用片段:
     645  void test2()
     646   {
     647   char string[10], str1[10]; 
     648   int i;
     649   for(i=0; i<10; i++)
     650   {
     651   str1= 'a';
     652   }
     653   strcpy( string, str1 );
     654   }
     655   试题3:  
     656 以下是引用片段:
     657 void test3(char* str1)
     658   {
     659   char string[10];
     660   if( strlen( str1 ) <= 10 )
     661   {
     662   strcpy( string, str1 );
     663   }
     664   }
     665   解答:
     666   试题1字符串str1需要11个字节才能存放下(包括末尾的’0’),而string只有10个字节的空间,strcpy会导致数组越界;对试题2,如果面试者指出字符数组str1不能在数组内结束可以给3分;如果面试者指出strcpy(string,str1)调用使得从 str1内存起复制到string内存起所复制的字节数具有不确定性可以给7分,在此基础上指出库函数strcpy工作方式的给10分;
     667 对试题3,if(strlen(str1) <= 10)应改为if(strlen(str1) <10),因为strlen的结果未统计’0’所占用的1个字节。剖析:考查对基本功的掌握
     668   (1)字符串以’0’结尾;
     669   (2)对数组越界把握的敏感度;
     670   (3)库函数strcpy的工作方式,
     671 
     672 49.如果编写一个标准strcpy函数
     673 总分值为10,下面给出几个不同得分的答案:2分 以下是引用片段:
     674 void strcpy( char *strDest, char *strSrc )
     675   {
     676   while( (*strDest++ = * strSrc++) != ‘0’ );
     677   }
     678   4分 以下是引用片段:
     679  void strcpy( char *strDest, const char *strSrc )
     680   //将源字符串加const,表明其为输入参数,加2分
     681   {
     682   while( (*strDest++ = * strSrc++) != ‘0’ );
     683   }
     684   7分 以下是引用片段:
     685 void strcpy(char *strDest, const char *strSrc)
     686   {
     687   //对源地址和目的地址加非0断言,加3分
     688   assert( (strDest != NULL) &&(strSrc != NULL) );
     689   while( (*strDest++ = * strSrc++) != ‘0’ );
     690   }
     691   10分 以下是引用片段:
     692 //为了实现链式操作,将目的地址返回,加3分!
     693   char * strcpy( char *strDest, const char *strSrc )
     694   {
     695   assert( (strDest != NULL) &&(strSrc != NULL) ); 
     696   char *address = strDest;
     697   while( (*strDest++ = * strSrc++) != ‘0’ );
     698   return address;
     699   }
     700   从2分到10分的几个答案我们可以清楚的看到,小小的strcpy竟然暗藏着这么多玄机,真不是盖的!需要多么扎实的基本功才能写一个完美的strcpy啊!
     701   (4)对strlen的掌握,它没有包括字符串末尾的'' 702   读者看了不同分值的strcpy版本,应该也可以写出一个10分的strlen函数了,完美的版本为: int strlen( const char *str ) //输入参数const 以下是引用片段:
     703  {
     704   assert( strt != NULL ); //断言字符串地址非0
     705   int len=0; //注,一定要初始化。
     706   while( (*str++) != '' )
     707   {
     708   len++;
     709   }
     710   return len;
     711   }
     712   试题4:以下是引用片段:
     713 void GetMemory( char *p )
     714   {
     715   p = (char *) malloc( 100 );
     716   }
     717   void Test( void )
     718   {
     719   char *str = NULL;
     720   GetMemory( str );
     721   strcpy( str, "hello world" );
     722   printf( str );
     723   } 
     724   试题5: 
     725 以下是引用片段:
     726 char *GetMemory( void )
     727   {
     728   char p[] = "hello world";
     729   return p;
     730   }
     731   void Test( void )
     732   {
     733   char *str = NULL;
     734   str = GetMemory();
     735   printf( str );
     736   }
     737   试题6:以下是引用片段:
     738 void GetMemory( char **p, int num )
     739   {
     740   *p = (char *) malloc( num );
     741   }
     742   void Test( void )
     743   {
     744   char *str = NULL;
     745   GetMemory( &str, 100 );
     746   strcpy( str, "hello" );
     747   printf( str );
     748   }
     749   试题7:以下是引用片段:
     750  void Test( void )
     751   {
     752   char *str = (char *) malloc( 100 );
     753   strcpy( str, "hello" );
     754   free( str );
     755   ... //省略的其它语句
     756   }
     757   解答:试题4传入中GetMemory( char *p )函数的形参为字符串指针,在函数内部修改形参并不能真正的改变传入形参的值,执行完
     758   char *str = NULL; 
     759   GetMemory( str );
     760   后的str仍然为NULL;试题5中
     761   char p[] = "hello world";
     762   return p;
     763   的p[]数组为函数内的局部自动变量,在函数返回后,内存已经被释放。这是许多程序员常犯的错误,其根源在于不理解变量的生存期。
     764   试题6的GetMemory避免了试题4的问题,传入GetMemory的参数为字符串指针的指针,但是在GetMemory中执行申请内存及赋值语句 tiffanybracelets
     765   *p = (char *) malloc( num );
     766   后未判断内存是否申请成功,应加上:
     767   if ( *p == NULL )
     768   {
     769   ...//进行申请内存失败处理
     770 
     771   }
     772   试题7存在与试题6同样的问题,在执行
     773   char *str = (char *) malloc(100);
     774   后未进行内存是否申请成功的判断;另外,在free(str)后未置str为空,导致可能变成一个“野”指针,应加上:
     775   str = NULL;
     776   试题6的Test函数中也未对malloc的内存进行释放。
     777   剖析:
     778   试题4~7考查面试者对内存操作的理解程度,基本功扎实的面试者一般都能正确的回答其中50~60的错误。但是要完全解答正确,却也绝非易事。
     779 
     780 
     781   对内存操作的考查主要集中在:
     782   (1)指针的理解;
     783   (2)变量的生存期及作用范围;
     784   (3)良好的动态内存申请和释放习惯。
     785   再看看下面的一段程序有什么错误:  
     786 以下是引用片段:
     787 swap( int* p1,int* p2 )
     788   {
     789   int *p;
     790   *p = *p1;
     791   *p1 = *p2;
     792   *p2 = *p;
     793   }
     794   在swap函数中,p是一个“野”指针,有可能指向系统区,导致程序运行的崩溃。在VC++中DEBUG运行时提示错误“Access Violation”。该程序应该改为
     795 以下是引用片段:
     796 swap( int* p1,int* p2 )
     797   {
     798   int p;
     799   p = *p1;
     800   *p1 = *p2;
     801   *p2 = p;
     802   }
     803 
     804 50.String 的具体实现
     805  
     806 
     807 已知String类定义如下:
     808 
     809 class String
     810 {
     811 public:
     812 String(const char *str = NULL); // 通用构造函数
     813 String(const String &another); // 拷贝构造函数
     814 ~ String(); // 析构函数
     815 String & operater =(const String &rhs); // 赋值函数
     816 private:
     817 char *m_data; // 用于保存字符串
     818 };
     819 
     820 尝试写出类的成员函数实现。
     821 
     822 答案:
     823 String::String(const char *str)
     824 {
     825 if ( str == NULL ) //strlen在参数为NULL时会抛异常才会有这步判断
     826 {
     827 m_data = new char[1] ;
     828 m_data[0] = '' ;
     829 }
     830 else
     831 {
     832 m_data = new char[strlen(str) + 1];
     833 strcpy(m_data,str);
     834 }
     835 
     836 } 
     837 
     838 String::String(const String &another)
     839 
     840 {
     841 m_data = new char[strlen(another.m_data) + 1];
     842 strcpy(m_data,other.m_data);
     843 }
     844 
     845 String& String::operator =(const String &rhs)
     846 {
     847 if ( this == &rhs)
     848 return *this ;
     849 delete []m_data; //删除原来的数据,新开一块内存
     850 m_data = new char[strlen(rhs.m_data) + 1];
     851 strcpy(m_data,rhs.m_data);
     852 return *this ;
     853 }
     854 
     855 
     856 String::~String()
     857 {
     858 delete []m_data ;
     859 }
     860 
     861 51.h头文件中的ifndef/define/endif 的作用?
     862 答:防止该头文件被重复引用。
     863 
     864 52.#i nclude<file.h> 与 #i nclude "file.h"的区别?
     865 答:前者是从Standard Library的路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h。
     866 
     867  
     868 
     869 53.在C++ 程序中调用被C 编译器编译后的函数,为什么要加extern “C”?
     870 C++语言支持函数重载,C语言不支持函数重载。C++提供了C连接交换指定符号extern “C”
     871 
     872 解决名字匹配问题。
     873 
     874 
     875 首先,作为extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。
     876 
     877 通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。例如,如果模块B欲引用该模块A中定义的全局变量和函数时只需包含模块A的头文件即可。这样,模块B中调用模块A中的函数时,在编译阶段,模块B虽然找不到该函数,但是并不会报错;它会在连接阶段中从模块A编译生成的目标代码中找到此函数
     878 
     879 extern "C"是连接申明(linkage declaration),被extern "C"修饰的变量和函数是按照C语言方式编译和连接的,来看看C++中对类似C的函数是怎样编译的:
     880 
     881 
     882 作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为:
     883 
     884 void foo( int x, int y );
     885   
     886 
     887 该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为“mangled name”)。
     888 
     889 _foo_int_int 这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。例如,在C++中,函数void foo( int x, int y )与void foo( int x, float y )编译生成的符号是不相同的,后者为_foo_int_float。
     890 
     891 同样地,C++中的变量除支持局部变量外,还支持类成员变量和全局变量。用户所编写程序的类成员变量可能与全局变量同名,我们以"."来区分。而本质上,编译器在进行编译时,与函数的处理相似,也为类中的变量取了一个独一无二的名字,这个名字与用户程序中同名的全局变量名字不同。
     892 
     893 未加extern "C"声明时的连接方式
     894 
     895 假设在C++中,模块A的头文件如下:
     896 
     897 // 模块A头文件 moduleA.h
     898 #ifndef MODULE_A_H
     899 #define MODULE_A_H
     900 int foo( int x, int y );
     901 #endif  
     902 
     903 在模块B中引用该函数:
     904 
     905 // 模块B实现文件 moduleB.cpp
     906 #i nclude "moduleA.h"
     907 foo(2,3);
     908 
     909 加extern "C"声明后的编译和连接方式
     910 
     911 加extern "C"声明后,模块A的头文件变为:
     912 
     913 // 模块A头文件 moduleA.h
     914 #ifndef MODULE_A_H
     915 #define MODULE_A_H
     916 extern "C" int foo( int x, int y );
     917 #endif  
     918 
     919 在模块B的实现文件中仍然调用foo( 2,3 ),其结果是:
     9201)模块A编译生成foo的目标代码时,没有对其名字进行特殊处理,采用了C语言的方式;
     921 
     9222)连接器在为模块B的目标代码寻找foo(2,3)调用时,寻找的是未经修改的符号名_foo。
     923 
     924 如果在模块A中函数声明了foo为extern "C"类型,而模块B中包含的是extern int foo( int x, int y ) ,则模块B找不到模块A中的函数;反之亦然。
     925 
     926 所以,可以用一句话概括extern “C”这个声明的真实目的(任何语言中的任何语法特性的诞生都不是随意而为的,来源于真实世界的需求驱动。我们在思考问题时,不能只停留在这个语言是怎么做的,还要问一问它为什么要这么做,动机是什么,这样我们可以更深入地理解许多问题):实现C++与C及其它语言的混合编程。  
     927 
     928 明白了C++中extern "C"的设立动机,我们下面来具体分析extern "C"通常的使用技巧:
     929 
     930 extern "C"的惯用法
     931 
     9321)在C++中引用C语言中的函数和变量,在包含C语言头文件(假设为cExample.h)时,需进行下列处理:
     933 
     934 
     935 extern "C"
     936 {
     937 #i nclude "cExample.h"
     938 }
     939 
     940 而在C语言的头文件中,对其外部函数只能指定为extern类型,C语言中不支持extern "C"声明,在.c文件中包含了extern "C"时会出现编译语法错误。
     941 
     942 C++引用C函数例子工程中包含的三个文件的源代码如下:
     943 
     944 /* c语言头文件:cExample.h */
     945 #ifndef C_EXAMPLE_H
     946 #define C_EXAMPLE_H
     947 extern int add(int x,int y);
     948 #endif
     949 
     950 
     951 /* c语言实现文件:cExample.c */
     952 #i nclude "cExample.h"
     953 int add( int x, int y )
     954 {
     955 return x + y;
     956 }
     957 
     958 
     959 // c++实现文件,调用add:cppFile.cpp
     960 extern "C"
     961 {
     962 #i nclude "cExample.h"
     963 }
     964 int main(int argc, char* argv[])
     965 {
     966 add(2,3);
     967 return 0;
     968 }
     969 
     970 如果C++调用一个C语言编写的.DLL时,当包括.DLL的头文件或声明接口函数时,应加extern "C" { }。
     971 
     9722)在C中引用C++语言中的函数和变量时,C++的头文件需添加extern "C",但是在C语言中不能直接引用声明了extern "C"的该头文件,应该仅将C文件中将C++中定义的extern "C"函数声明为extern类型。
     973 
     974 C引用C++函数例子工程中包含的三个文件的源代码如下:
     975 
     976 //C++头文件 cppExample.h
     977 #ifndef CPP_EXAMPLE_H
     978 #define CPP_EXAMPLE_H
     979 extern "C" int add( int x, int y );
     980 #endif
     981 
     982 
     983 //C++实现文件 cppExample.cpp
     984 #i nclude "cppExample.h"
     985 int add( int x, int y )
     986 {
     987 return x + y;
     988 }
     989 
     990 
     991 /* C实现文件 cFile.c
     992 /* 这样会编译出错:#i nclude "cExample.h" */
     993 
     994 int main( int argc, char* argv[] )
     995 {
     996 add( 2, 3 );
     997 return 0;
     998 }
     999 
    1000 15题目的解答请参考《C++中extern “C”含义深层探索》注解:
    1001 
    1002 几道c笔试题(含参考答案)
    1003 
    1004 1. 
    1005 What is displayed when f() is called given the code:
    1006 class Number {
    1007 public:
    1008 string type; 
    1009 
    1010 Number(): type(“void”) { }
    1011 explicit Number(short) : type(“short”) { } 
    1012 Number(int) : type(“int”) { }
    1013 };
    1014 void Show(const Number& n) { cout << n.type; }
    1015 void f()
    1016 {
    1017 short s = 42;
    1018 Show(s); 
    1019 }
    1020 a) void
    1021 b) short
    1022 c) int
    1023 d) None of the above
    1024 
    1025 2. Which is the correct output for the following code
    1026 double dArray[2] = {4, 8}, *p, *q;
    1027 p = &dArray[0];
    1028 q = p + 1;
    1029 cout << q – p << endl; 
    1030 cout << (int)q - (int)p << endl;
    1031 a) 1 and 8
    1032 b) 8 and 4
    1033 c) 4 and 8
    1034 d) 8 and 1
    1035 
    1036 
    1037 第一个选C;
    1038 虽然传入的是short类型,但是short类型的构造函数被生命被explicit,也就是只能显示类型转换,不能使用隐式类型转换。
    1039 第二个选A;
    1040 第一个是指针加减,按照的是指向地址类型的加减,只跟类型位置有关,q和p指向的数据类型以实际数据类型来算差一个位置,因此是1。而第二个加减是实际指针值得加减,在内存中一个double类型占据8个字节,因此是8
    1041 
    1042  
    1043 
    1044 54.Sony笔试题
    1045 
    1046   1.完成下列程序 
    1047   * 
    1048   *.*. 
    1049   *..*..*.. 
    1050   *...*...*...*... 
    1051   *....*....*....*....*.... 
    1052   *.....*.....*.....*.....*.....*..... 
    1053   *......*......*......*......*......*......*...... 
    1054   *.......*.......*.......*.......*.......*.......*.......*....... 
    1055   #include 
    1056   #define N 8 
    1057   int main() 
    1058   { 
    1059    int i; 
    1060    int j; 
    1061    int k; 
    1062    --------------------------------------------------------- 
    1063    | | 
    1064    | | 
    1065    | | 
    1066    --------------------------------------------------------- 
    1067    return 0; 
    1068   } 
    1069   2.完成程序,实现对数组的降序排序 
    1070   #include 
    1071   void sort( ); 
    1072   int main() 
    1073   { 
    1074    int array[]={4556762341342323}; //数字任//意给出 
    1075    sort( ); 
    1076    return 0; 
    1077   } 
    1078   void sort( ) 
    1079   { 
    1080    ____________________________________ 
    1081    | | 
    1082    | | 
    1083    |-----------------------------------------------------| 
    1084   } 
    1085   3.费波那其数列,11235……编写程序求第十项。可以用递归,也可以用其 
    1086 他方法,但要说明你选择的理由。 
    1087   #include 
    1088   int Pheponatch(int); 
    1089   int main() 
    1090   { 
    1091    printf("The 10th is %d",Pheponatch(10)); 
    1092    return 0; 
    1093   } 
    1094   int Pheponatch(int N) 
    1095   { 
    1096   -------------------------------- 
    1097   | | 
    1098   | | 
    1099   -------------------------------- 
    1100   } 
    1101   4.下列程序运行时会崩溃,请找出错误并改正,并且说明原因。 
    1102   #include 
    1103   #include 
    1104   typedef struct{ 
    1105    TNode* left; 
    1106    TNode* right; 
    1107    int value; 
    1108   } TNode; 
    1109   TNode* root=NULL; 
    1110   void append(int N); 
    1111   int main() 
    1112   { 
    1113    append(63); 
    1114    append(45); 
    1115    append(32); 
    1116    append(77); 
    1117    append(96); 
    1118    append(21); 
    1119    append(17); // Again, 数字任意给出 
    1120   } 
    1121   void append(int N) 
    1122   { 
    1123    TNode* NewNode=(TNode *)malloc(sizeof(TNode)); 
    1124    NewNode->value=N; 
    1125 
    1126 
    1127    if(root==NULL) 
    1128    { 
    1129    root=NewNode; 
    1130    return; 
    1131    } 
    1132    else 
    1133    { 
    1134    TNode* temp; 
    1135    temp=root; 
    1136 
    1137    while((N>=temp.value && temp.left!=NULL) || (N !=NULL 
    1138   )) 
    1139    { 
    1140    while(N>=temp.value && temp.left!=NULL) 
    1141    temp=temp.left; 
    1142    while(N    temp=temp.right; 
    1143    } 
    1144    if(N>=temp.value) 
    1145    temp.left=NewNode; 
    1146    else 
    1147    temp.right=NewNode; 
    1148    return; 
    1149    } 
    1150   } 
    1151 
    1152 
    1153 
    1154 ──────────────────────────────────────── 
    1155 55请你分别画出OSI的七层网络结构图和TCP/IP的五层结构图。
    1156 应用层:为应用程序提供服务
    1157 
    1158 表示层:处理在两个通信系统中交换信息的表示方式
    1159 
    1160 会话层:负责维护两个结点间会话连接的建立、管理和终止,以及数据交换
    1161 
    1162 传输层:向用户提供可靠的端到端服务。UDP TCP协议。
    1163 
    1164 网络层:通过路由选择算法为分组通过通信子网选择最适当的路径,以及实现拥塞控制、网络互联等功能。数据传输单元是分组。IP地址,路由器,IP协议。
    1165 
    1166 数据链路层:在物理层提供的服务基础上,数据链路层在通信的实体间建立数据链路连接,传输一帧为单位的数据包(,并采用差错控制与流量控制方法,使有差错的物理线路变成无差错的数据链路。)
    1167 
    1168 物理层:传输比特流。传输单元是比特。调制解调器。
    1169 
    1170 56请你详细地解释一下IP协议的定义,在哪个层上面?主要有什么作用?TCP与UDP呢 ?
    1171 网络层。
    1172 
    1173 57.请问交换机和路由器各自的实现原理是什么?分别在哪个层次上面实现的?
    1174 交换机:数据链路层。路由器:网络层。
    1175 
    1176 58.全局变量和局部变量有什么区别?是怎么实现的?操作系统和编译器是怎么知道的 ?
    1177  全局变量的生命周期是整个程序运行的时间,而局部变量的生命周期则是局部函数或过程调用的时间段。其实现是由编译器在编译时采用不同内存分配方法。全局变量在main函数调用后,就开始分配,如果是静态变量则是在main函数前就已经初始化了。而局部变量则是在用户栈中动态分配的(还是建议看编译原理中的活动记录这一块)
    1178 59.8086是多少位的系统?在数据总线上是怎么实现的? 
    1179 
    1180 
    1181 8086微处理器共有4个16位的段寄存器,在寻址内存单元时,用它们直接或间接地存放段地址。
    1182 
    1183   代码段寄存器CS:存放当前执行的程序的段地址。
    1184 
    1185   数据段寄存器DS:存放当前执行的程序所用操作数的段地址。
    1186 
    1187   堆栈段寄存器SS:存放当前执行的程序所用堆栈的段地址。
    1188 
    1189   附加段寄存器ES:存放当前执行程序中一个辅助数据段的段地址。
    1190 
    1191 由cs:ip构成指令地址,ss:sp构成堆栈的栈顶地址指针。DS和ES用作数据段和附加段的段地址(段起始地址或段值)
    1192 
    1193  
    1194 
    1195 8086/8088微处理器的存储器管理
    1196 
    1197    1.地址线(码)与寻址范围:N条地址线     寻址范围=2N
    1198 
    1199    2.8086有20地址线     寻址范围为1MB  由 00000H~FFFFFH
    1200 
    1201    3. 8086微处理器是一个16位结构,用户可用的寄存器均为16位:寻址64KB
    1202 
    1203    4. 8086/8088采用分段的方法对存储器进行管理。具体做法是:把1MB的存储器空间分成若干段,每段容量为64KB,每段存储器的起始地址必须是一个能被16整除的地址码,即在20位的二进制地址码中最低4位必须是“0”。每个段首地址的高16位二进制代码就是该段的段号(称段基地址)或简称段地址,段号保存在段寄存器中。我们可对段寄存器设置不同的值来使微处理器的存储器访问指向不同的段。
    1204 
    1205    5.段内的某个存储单元相对于该段段首地址的差值,称为段内偏移地址(也叫偏移量)用16位二进制代码表示。
    1206 
    1207    6.物理地址是由8086/8088芯片地址引线送出的20位地址码,它用来参加存储器的地址译码,最终读/写所访问的一个特定的存储单元。
    1208 
    1209    7.逻辑地址由某段的段地址和段内偏移地址(也叫偏移量)两部分所组成。写成:
    1210 
    1211      段地址:偏移地址(例如,1234H:0088H)。
    1212 
    1213    8.在硬件上起作用的是物理地址,物理地址=段基地址×10H十偏移地址
    1214 
    1215 
    1216 
    1217 联想笔试题 
    1218   1.设计函数 int atoi(char *s)。 
    1219   2int i=(j=4,k=8,l=16,m=32); printf(“%d”, i); 输出是多少? 
    1220 
    1221 60.解释局部变量、全局变量和静态变量的含义。
    1222  
    1223 
    1224 61.论述含参数的宏与函数的优缺点。 
    1225 
    1226 普天C++笔试题 
    1227   1.实现双向链表删除一个节点P,在节点P后插入一个节点,写出这两个函数。 
    1228   2.写一个函数,将其中的	都转换成4个空格。
    1229 
    1230  
    1231 
    1232 61.Windows程序的入口是哪里?写出Windows消息机制的流程。 
    1233 
    1234  
    1235 
    1236  
    1237 
    1238 62.C++里面是不是所有的动作都是main()引起的?如果不是,请举例。 
    1239   
    1240 4.如何定义和实现一个类的成员函数为回调函数?
    1241 5.解释堆和栈的区别。
    1242 
    1243 6.C++里面如何声明const void f(void)函数为C程序中的库函数? 
    1244   7.下列哪两个是等同的 
    1245   int b; 
    1246   A const int* a = &b; 
    1247   B const* int a = &b; 
    1248   C const int* const a = &b; 
    1249   D int const* const a = &b; 
    1250   8.内联函数在编译时是否做参数类型检查? 
    1251   void g(base & b){ 
    1252    b.play; 
    1253   } 
    1254   void main(){ 
    1255    son s; 
    1256    g(s); 
    1257    return; 
    1258   } 
    1259 
    1260 
    1261 
    1262 
    1263 
    1264 大唐电信 
    1265   DTT笔试题 
    1266   考试时间一小时,第一部分是填空和选择: 
    1267   1.数列6,101832,“?”,问“?”是几? 
    1268   2.某人出70买进一个x,80卖出,90买回,100卖出,这桩买卖怎么样? 
    1269   3.月球绕地球一圈,至少要多少时间? 
    1270   4.7个人用7小时挖了7米的沟,以同样的速度在50小时挖50米的沟要多少人? 
    1271   5.鱼头长9,鱼尾等于鱼头加半个鱼身,鱼身等于鱼头加鱼尾,问鱼全长多少? 
    1272   6.一个小姐买了一块手表,回家发现手表比她家的表慢了两分钟,晚上看新闻的时候 
    1273 又发现她家的表比新闻里的时间慢了两分钟,则 。 
    1274   A 手表和新闻里的时间一样 
    1275   B 手表比新闻里的时间慢 
    1276   C 手表比新闻里的时间快 
    1277   7.王先生看到一则招聘启事,发现两个公司除了以下条件不同外,其他条件都相同 
    1278 
    1279   A 半年年薪50万,每半年涨5万 
    1280   B 一年年薪100万,每一年涨20万 
    1281   王先生想去一家待遇比较优厚的公司,他会去哪家? 
    1282   10.问哪个袋子里有金子? 
    1283   A袋子上的标签是这样写的:B袋子上的话是对的,金子在A袋子。 
    1284   B袋子上的标签是这样写的:A袋子上的话是错的,金子在A袋子里。 
    1285   11.3个人住酒店30块钱,经理找回5块钱,服务生从中藏了2块钱,找给每人1块钱, 
    1286 3×(101)+2=29,问这是怎么回事? 
    1287   12.三篇写作,均为书信形式。 
    1288   (1)一片中文的祝贺信,祝贺某男当了某公司xx 
    1289   (2)两篇英文的,一是说有事不能应邀,派别人去;另一篇是讨债的,7天不给钱就 
    1290 走人(主要考business letter格式)。 
    1291   大唐面试试题 
    1292   1.什么是中断?中断发生时CPU做什么工作? 
    1293   2.CPU在上电后,进入操作系统的main()之前必须做什么工作? 
    1294   3.简述ISO OSI的物理层Layer1,链路层Layer2,网络层Layer3的任务。 
    1295   4.有线电话和无线电话有何区别?无线电话特别需要注意的是什么? 
    1296   
    1297 
    1298 63.软件开发五个主要step是什么?
    1299 
    1300   6.你在开发软件的时候,这5个step分别占用的时间百分比是多少? 
    1301   7.makefile文件的作用是什么? 
    1302   8.UNIX显示文件夹中,文件名的命令是什么?能使文件内容显示在屏幕的命令是什么 
    1303 1304   9.(选做)手机用户在从一个基站漫游到另一个基站的过程中,都会发生什么? 
    1305 
    1306 ──────────────────────────────────────── 
    1307 
    1308 
    1309 网通笔试题 
    1310   选择题(每题5分,只有一个正确答案) 
    1311   1.中国1号信令协议属于 的协议。 
    1312   A ccs B cas C ip D atm 
    1313   2.isdnpri协议全称是 。 
    1314   A 综合业务模拟网基速协议 
    1315   B 综合业务模拟网模拟协议 
    1316   C 综合业务数字网基率协议 
    1317   D 综合业务数字网基次协议 
    1318   3.路由协议中, 协议是用距离作为向量的。 
    1319   A ospf B bgp C is-is D rip 
    1320   4.中国智能网中,ssp与scp间最上层的ss7协议是 。 
    1321   A incs B is41b C is41c D inap 
    1322   5.dtmf全称是 。 
    1323   A 双音多频 B多音双频 C多音三频 D三音多频 
    1324   6.计算机的基本组成部分中,不包含下面设备的是 。 
    1325   A cpu B输入设备 C存储器 D接口 
    1326   7.脉冲编码调制的简称是 。 
    1327   A pcm B pam C (delta)M D atm 
    1328   8.普通电话线接口专业称呼是 。 
    1329   A rj11 B rj45 C rs232 D bnc 
    1330   9.现有的公共数据网都采用 。 
    1331   A电路交换技术 B报文交换技术 
    1332   C语音插空 D分组交换 
    1333   10.ss7协议中的制止市忙消息简写为 。 
    1334   A stb B slb C sub D spb 
    1335   简答题(每题10分) 
    1336   1.简述普通电话与IP电话的区别。 
    1337   2.简述随路信令与公路信令的根本区别。 
    1338   3.说明掩码的主要作用。 
    1339   4.ss7协议中,有三大要素决定其具体定位,哪三大要素? 
    1340   5.描述ss7的基本通话过程。 
    1341   6.简述通信网的组成结构。 
    1342   7.面向连接与面向非连接各有何利弊? 
    1343   8.写出爱尔兰的基本计算公式。 
    1344   9.数据网主要有哪些设备? 
    1345   10.中国一号协议是如何在被叫号码中插入主叫号码的? 
    1346 
    1347 
    1348 东信笔试题目 
    1349   笔试:30分钟。 
    1350   1.压控振荡器的英文缩写。 
    1351   2.动态随机存储器的英文缩写。 
    1352   3.选择电阻时要考虑什么? 
    1353   4.单片机上电后没有运转,首先要检查什么? 
    1354   5.计算机的基本组成部分及其各自的作用。 
    1355   6.怎样用D触发器、与或非门组成二分频电路?
    1356 
    1357  
    1358 
    1359 64.static有什么用途?(请至少说明两种)
    1360 答 、1.限制变量的作用域(文件级的)。
    1361 
    1362  2.设置变量的存储域(全局数据区)。
    1363 
    1364  
    1365 
    1366  
    1367 
    1368 65.引用与指针有什么区别?
    1369 答 、1) 引用必须被初始化,指针不必。
    1370 
    1371 2) 引用初始化以后不能被改变,指针可以改变所指的对象。
    1372 
    1373 3) 不存在指向空值的引用,但是存在指向空值的指针。
    1374 
    1375 66.描述实时系统的基本特性
    1376 答 、在特定时间内完成特定的任务,实时性与可靠性。
    1377 
    1378  
    1379 
    1380  
    1381 
    1382 67.全局变量和局部变量在内存中是否有区别?如果有,是什么区别?
    1383 答 、全局变量储存在静态数据区,局部变量在堆栈中。
    1384 
    1385  
    1386 
    1387  
    1388 
    1389 68.什么是平衡二叉树?
    1390 答 、左右子树都是平衡二叉树 且左右子树的深度差值的绝对值不大于1。
    1391 
    1392  
    1393 
    1394  
    1395 
    1396 69.堆栈溢出一般是由什么原因导致的?
    1397 答 、1.没有回收垃圾资源
    1398 
    1399         2.层次太深的递归调用     
    1400 
    1401  
    1402 
    1403  
    1404 
    1405 70.什么函数不能声明为虚函数?
    1406 答 、constructor
    1407 
    1408        Deconstructor 可以声明为虚函数。
    1409 
    1410        系统为一个空类创建的成员函数有那些。
    1411 
    1412  
    1413 
    1414 71.冒泡排序算法的时间复杂度是什么?
    1415 答 、O(n^2)
    1416 
    1417  
    1418 
    1419  
    1420 
    1421 72.写出float x 与“零值”比较的if语句。
    1422 答 、if(x>0.000001&&x<-0.000001)
    1423 
    1424  
    1425 
    1426  
    1427 
    1428 73.Internet采用哪种网络协议?该协议的主要层次结构?
    1429  
    1430 
    1431 答 、tcp/ip 应用层/传输层/网络层/数据链路层/物理层
    1432 
    1433  
    1434 
    1435  
    1436 
    1437 74.Internet物理地址和IP地址转换采用什么协议?
    1438 答 、ARP (Address Resolution Protocol)(地址解析协议)
    1439 
    1440  
    1441 
    1442  
    1443 
    1444 75.IP地址的编码分为哪俩部分?
    1445 答 、IP地址由两部分组成,网络号和主机号。不过是要和“子网掩码”按位与之后才能区分哪些是网络位哪些是主机位。
    1446 
    1447  
    1448 
    1449 76.用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出。写出C程序。
    1450 答 、循环链表,用取余操作做
    1451 
    1452  
    1453 
    1454  
    1455 
    1456 77.不能做switch()的参数类型是:
    1457 答 、switch的参数不能为实型。
    1458 
    1459 华为
    1460 
    1461 78.局部变量能否和全局变量重名?
    1462 答、能,局部会屏蔽全局。要用全局变量,需要使用"::"
    1463 
    1464 局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内
    1465 
    1466  
    1467 
    1468  
    1469 
    1470 79.如何引用一个已经定义过的全局变量?
    1471 答 、可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变理,假定你将那个变写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错
    1472 
    1473  
    1474 
    1475  
    1476 
    1477 80.全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?
    1478 答 、可以,在不同的C文件中以static形式来声明同名全局变量。
    1479 
    1480 可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错
    1481 
    1482  
    1483 
    1484  
    1485 
    1486 81.语句for( ;1 ;)有什么问题?它是什么意思?
    1487 答 、和while(1)相同。
    1488 
    1489  
    1490 
    1491  
    1492 
    1493 82.do……while和while……do有什么区别?
    1494 答 、前一个循环一遍再判断,后一个判断以后再循环
    1495 
    1496  
    1497 
    1498  
    1499 
    1500 83.请写出下列代码的输出内容
    1501 #i nclude
    1502 
    1503 main()
    1504 
    1505 {
    1506 
    1507 int a,b,c,d;
    1508 
    1509 a=10;
    1510 
    1511 b=a++;
    1512 
    1513 c=++a;
    1514 
    1515 d=10*a++;
    1516 
    1517 printf("b,c,d:%d,%d,%d",b,c,d);
    1518 
    1519 return 0;
    1520 
    1521 }
    1522 
    1523 答 、1012120
    1524 
    1525 84.static 全局变量、局部变量、函数与普通全局变量、局部变量、函数
    1526 static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
    1527 
    1528 答 、全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。 这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序, 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用, 因此可以避免在其它源文件中引起错误。
    1529 
    1530 从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域, 限制了它的使用范围。
    1531 
    1532 static函数与普通函数作用域不同。仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件
    1533 
    1534 static全局变量与普通的全局变量有什么区别:static全局变量只初使化一次,防止在其他文件单元中被引用;
    1535 
    1536 static局部变量和普通局部变量有什么区别:static局部变量只被初始化一次,下一次依据上一次结果值;
    1537 
    1538 static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝
    1539 
    1540 程序的局部变量存在于(堆栈)中,全局变量存在于(静态区 )中,动态申请数据存在于( 堆)中。
    1541 
    1542 85.设有以下说明和定义:
    1543 typedef union {long i; int k[5]; char c;} DATE;
    1544 
    1545 struct data { int cat; DATE cow; double dog;} too;
    1546 
    1547 DATE max;
    1548 
    1549 则语句 printf("%d",sizeof(struct date)+sizeof(max));的执行结果是?
    1550 
    1551 答 、结果是:___52____。DATE是一个union, 变量公用空间. 里面最大的变量类型是int[5], 占用20个字节. 所以它的大小是20
    1552 
    1553 data是一个struct, 每个变量分开占用空间. 依次为int4 + DATE20 + double8 = 32.
    1554 
    1555 所以结果是 20 + 32 = 52.
    1556 
    1557 当然...在某些16位编辑器下, int可能是2字节,那么结果是 int2 + DATE10 + double8 = 20
    1558 
    1559 86.-1,2,7,28,,126请问28和126中间那个数是什么?为什么?
    1560 答 、应该是4^3-1=63
    1561 
    1562 规律是n^3-1(当n为偶数0,24)
    1563 
    1564 n^3+1(当n为奇数1,35)
    1565 
    1566  
    1567 
    1568 87.用两个栈实现一个队列的功能?要求给出算法和思路!
    1569 答 、设2个栈为A,B, 一开始均为空.
    1570 
    1571 入队:
    1572 
    1573 将新元素push入栈A;
    1574 
    1575 出队:
    1576 
    1577 (1)判断栈B是否为空;
    1578 
    1579 (2)如果不为空,则将栈A中所有元素依次pop出并push到栈B;
    1580 
    1581 (3)将栈B的栈顶元素pop出;
    1582 
    1583 这样实现的队列入队和出队的平摊复杂度都还是O(1), 比上面的几种方法要好。
    1584 
    1585  
    1586 
    1587 88.在c语言库函数中将一个字符转换成整型的函数是atool()吗,这个函数的原型是什么?
    1588 答 、函数名: atol
    1589 
    1590 功 能: 把字符串转换成长整型数
    1591 
    1592 用 法: long atol(const char *nptr);
    1593 
    1594 程序例:
    1595 
    1596 #include
    1597 
    1598 #include
    1599 
    1600 int main(void)
    1601 
    1602 {
    1603 
    1604     long l;
    1605 
    1606     char *str = "98765432";
    1607 
    1608     l = atol(lstr);
    1609 
    1610     printf("string = %s integer = %ld
    ", str, l);
    1611 
    1612     return(0);
    1613 
    1614 }
    1615 
    1616  
    1617 
    1618  
    1619 
    1620 89.对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现?
    1621 答 、c用宏定义,c++用inline
    1622 
    1623  
    1624 
    1625 90.用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)
    1626  
    1627 
    1628 #define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL
    1629 
    1630 我在这想看到几件事情:
    1631 
    1632 1). #define 语法的基本知识(例如:不能以分号结束,括号的使用,等等)
    1633 
    1634 2). 懂得预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算一年中有多少秒而不是计算出实际的值,是更清晰而没有代价的。
    1635 
    1636 3). 意识到这个表达式将使一个16位机的整型数溢出-因此要用到长整型符号L,告诉编译器这个常数是的长整型数。
    1637 
    1638 4). 如果你在你的表达式中用到UL(表示无符号长整型),那么你有了一个好的起点。记住,第一印象很重要。
    1639 
    1640  
    1641 
    1642 91.写一个“标准”宏MIN,这个宏输入两个参数并返回较小的一个。
    1643  
    1644 
    1645 #define MIN(A,B) ((A) <= (B) (A) : (B))
    1646 
    1647 这个测试是为下面的目的而设的:
    1648 
    1649 1). 标识#define在宏中应用的基本知识。这是很重要的,因为直到嵌入(inline)操作符变为标准C的一部分,宏是方便产生嵌入代码的唯一方法,
    1650 
    1651 对于嵌入式系统来说,为了能达到要求的性能,嵌入代码经常是必须的方法。
    1652 
    1653 2). 三重条件操作符的知识。这个操作符存在C语言中的原因是它使得编译器能产生比if-then-else更优化的代码,了解这个用法是很重要的。
    1654 
    1655 3). 懂得在宏中小心地把参数用括号括起来
    1656 
    1657 4). 我也用这个问题开始讨论宏的副作用,例如:当你写下面的代码时会发生什么事?
    1658 
    1659 least = MIN(*p++, b);
    1660 
    1661  
    1662 
    1663 92.预处理器标识#error的目的是什么?
    1664  
    1665 
    1666 如果你不知道答案,请看参考文献1。这问题对区分一个正常的伙计和一个书呆子是很有用的。只有书呆子才会读C语言课本的附录去找出象这种
    1667 
    1668 问题的答案。当然如果你不是在找一个书呆子,那么应试者最好希望自己不要知道答案。
    1669 
    1670  
    1671 
    1672 死循环(Infinite loops)
    1673 
    1674  
    1675 
    1676 93.嵌入式系统中经常要用到无限循环,你怎么样用C编写死循环呢?
    1677  
    1678 
    1679 这个问题用几个解决方案。我首选的方案是:
    1680 
    1681 while(1)
    1682 
    1683 {
    1684 
    1685 }
    1686 
    1687 一些程序员更喜欢如下方案:
    1688 
    1689 for(;;)
    1690 
    1691 {
    1692 
    1693 }
    1694 
    1695 这个实现方式让我为难,因为这个语法没有确切表达到底怎么回事。如果一个应试者给出这个作为方案,我将用这个作为一个机会去探究他们这样做的
    1696 
    1697 基本原理。如果他们的基本答案是:“我被教着这样做,但从没有想到过为什么。”这会给我留下一个坏印象。
    1698 
    1699 第三个方案是用 goto
    1700 
    1701 Loop:
    1702 
    1703 ...
    1704 
    1705 goto Loop;
    1706 
    1707 应试者如给出上面的方案,这说明或者他是一个汇编语言程序员(这也许是好事)或者他是一个想进入新领域的BASIC/FORTRAN程序员。
    1708 
    1709  
    1710 
    1711 数据声明(Data declarations)
    1712 
    1713  
    1714 
    1715 94.用变量a给出下面的定义
    1716 a) 一个整型数(An integer)
    1717 
    1718 b) 一个指向整型数的指针(A pointer to an integer)
    1719 
    1720 c) 一个指向指针的的指针,它指向的指针是指向一个整型数(A pointer to a pointer to an integer)
    1721 
    1722 d) 一个有10个整型数的数组(An array of 10 integers)
    1723 
    1724 e) 一个有10个指针的数组,该指针是指向一个整型数的(An array of 10 pointers to integers)
    1725 
    1726 f) 一个指向有10个整型数数组的指针(A pointer to an array of 10 integers)
    1727 
    1728 g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a function that takes an integer as an argument and returns an integer)
    1729 
    1730 h) 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数( An array of ten pointers to functions that take an integer
    1731 
    1732 argument and return an integer )
    1733 
    1734  
    1735 
    1736 答案是:
    1737 
    1738 a) int a; // An integer
    1739 
    1740 b) int *a; // A pointer to an integer
    1741 
    1742 c) int **a; // A pointer to a pointer to an integer
    1743 
    1744 d) int a[10]; // An array of 10 integers
    1745 
    1746 e) int *a[10]; // An array of 10 pointers to integers
    1747 
    1748 f) int (*a)[10]; // A pointer to an array of 10 integers
    1749 
    1750 g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer
    1751 
    1752 h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer
    1753 
    1754  
    1755 
    1756 人们经常声称这里有几个问题是那种要翻一下书才能回答的问题,我同意这种说法。当我写这篇文章时,为了确定语法的正确性,我的确查了一下书。
    1757 
    1758 但是当我被面试的时候,我期望被问到这个问题(或者相近的问题)。因为在被面试的这段时间里,我确定我知道这个问题的答案。应试者如果不知道
    1759 
    1760 所有的答案(或至少大部分答案),那么也就没有为这次面试做准备,如果该面试者没有为这次面试做准备,那么他又能为什么出准备呢?
    1761 
    1762  
    1763 
    1764 Static
    1765 
    1766  
    1767 
    1768 95.关键字static的作用是什么?
    1769  
    1770 
    1771 这个简单的问题很少有人能回答完全。在C语言中,关键字static有三个明显的作用:
    1772 
    1773 1). 在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。
    1774 
    1775 2). 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。
    1776 
    1777 3). 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。
    1778 
    1779 大多数应试者能正确回答第一部分,一部分能正确回答第二部分,同是很少的人能懂得第三部分。这是一个应试者的严重的缺点,因为他显然不懂得本地化数
    1780 
    1781 据和代码范围的好处和重要性。
    1782 
    1783  
    1784 
    1785 Const
    1786 
    1787  
    1788 
    1789 96.关键字const是什么含意?
    1790 我只要一听到被面试者说:“const意味着常数”,我就知道我正在和一个业余者打交道。去年Dan Saks已经在他的文章里完全概括了const的所有用法,因此ESP(译者:Embedded Systems Programming)的每一位读者应该非常熟悉const能做什么和不能做什么.如果你从没有读到那篇文章,只要能说出const意味着“只读”就可以了。尽管这个答案不是完全的答案,但我接受它作为一个正确的答案。(如果你想知道更详细的答案,仔细读一下Saks的文章吧。)如果应试者能正确回答这个问题,我将问他一个附加的问题:下面的声明都是什么意思?
    1791 
    1792  
    1793 
    1794 const int a;
    1795 
    1796 int const a;
    1797 
    1798 const int *a;
    1799 
    1800 int * const a;
    1801 
    1802 int const * a const;
    1803 
    1804  
    1805 
    1806 前两个的作用是一样,a是一个常整型数。第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。如果应试者能正确回答这些问题,那么他就给我留下了一个好印象。顺带提一句,也许你可能会问,即使不用关键字 const,也还是能很容易写出功能正确的程序,那么我为什么还要如此看重关键字const呢?我也如下的几下理由:
    1807 
    1808 1). 关键字const的作用是为给读你代码的人传达非常有用的信息,实际上,声明一个参数为常量是为了告诉了用户这个参数的应用目的。如果你曾花很多时间清理其它人留下的垃圾,你就会很快学会感谢这点多余的信息。(当然,懂得用const的程序员很少会留下的垃圾让别人来清理的。)
    1809 
    1810 2). 通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。
    1811 
    1812 3). 合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug的出现。
    1813 
    1814  
    1815 
    1816 Volatile
    1817 
    1818  
    1819 
    1820 97.关键字volatile有什么含意 并给出三个不同的例子。
    1821  
    1822 
    1823 一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:
    1824 
    1825 1). 并行设备的硬件寄存器(如:状态寄存器)
    1826 
    1827 2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
    1828 
    1829 3). 多线程应用中被几个任务共享的变量
    1830 
    1831 回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。
    1832 
    1833 假设被面试者正确地回答了这是问题(嗯,怀疑这否会是这样),我将稍微深究一下,看一下这家伙是不是直正懂得volatile完全的重要性。
    1834 
    1835 1). 一个参数既可以是const还可以是volatile吗?解释为什么。
    1836 
    1837 2). 一个指针可以是volatile 吗?解释为什么。
    1838 
    1839 3). 下面的函数有什么错误:
    1840 
    1841 int square(volatile int *ptr)
    1842 
    1843 {
    1844 
    1845 return *ptr * *ptr;
    1846 
    1847 }
    1848 
    1849 下面是答案:
    1850 
    1851 1). 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。
    1852 
    1853 2). 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。
    1854 
    1855 3). 这段代码的有个恶作剧。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:
    1856 
    1857 int square(volatile int *ptr)
    1858 
    1859 {
    1860 
    1861 int a,b;
    1862 
    1863 a = *ptr;
    1864 
    1865 b = *ptr;
    1866 
    1867 return a * b;
    1868 
    1869 }
    1870 
    1871 由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:
    1872 
    1873 long square(volatile int *ptr)
    1874 
    1875 {
    1876 
    1877 int a;
    1878 
    1879 a = *ptr;
    1880 
    1881 return a * a;
    1882 
    1883 }
    1884 
    1885  
    1886 
    1887 位操作(Bit manipulation)
    1888 
    1889  
    1890 
    1891  
    1892 
    1893 98.下面的代码输出是什么,为什么?
    1894  
    1895 
    1896 void foo(void)
    1897 
    1898 {
    1899 
    1900 unsigned int a = 6;
    1901 
    1902 int b = -20;
    1903 
    1904 (a+b > 6) puts("> 6") : puts("<= 6");
    1905 
    1906 }
    1907 
    1908  
    1909 
    1910  
    1911 
    1912 这个问题测试你是否懂得C语言中的整数自动转换原则,我发现有些开发者懂得极少这些东西。不管如何,这无符号整型问题的答案是输出是“>6”。原因是当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型。因此-20变成了一个非常大的正整数,所以该表达式计算出的结果大于6。这一点对于应当频繁用到无符号数据类型的嵌入式系统来说是丰常重要的。如果你答错了这个问题,你也就到了得不到这份工作的边缘。
    1913 
    1914  
    1915 
    1916  
    1917 
    1918 99.C语言同意一些令人震惊的结构,下面的结构是合法的吗,如果是它做些什么?
    1919 int a = 5, b = 7, c;
    1920 
    1921 c = a+++b;
    1922 
    1923  
    1924 
    1925 这个问题将做为这个测验的一个愉快的结尾。不管你相不相信,上面的例子是完全合乎语法的。问题是编译器如何处理它?水平不高的编译作者实际上会争论这个问题,根据最处理原则,编译器应当能处理尽可能所有合法的用法。因此,上面的代码被处理成:
    1926 
    1927 c = a++ + b;
    1928 
    1929 因此, 这段代码持行后a = 6, b = 7, c = 121930 
    1931 如果你知道答案,或猜出正确答案,做得好。如果你不知道答案,我也不把这个当作问题。我发现这个问题的最大好处是:这是一个关于代码编写风格,代码的可读性,代码的可修改性的好的话题
    1932 
    1933 今天早上的面试题9道,比较难,
    1934 
    1935 100.线形表a、b为两个有序升序的线形表,编写一程序,使两个有序线形表合并成一个有序升序线形表h;
    1936  
    1937 
    1938  
    1939 
    1940 答案在 请化大学 严锐敏《数据结构第二版》第二章例题,数据结构当中,这个叫做:两路归并排序
    1941 
    1942 Linklist *unio(Linklist *p,Linklist *q){
    1943 
    1944 linklist *R,*pa,*qa,*ra;
    1945 
    1946 pa=p;
    1947 
    1948 qa=q;
    1949 
    1950 R=ra=p;
    1951 
    1952 while(pa->next!=NULL&&qa->next!=NULL){
    1953 
    1954 if(pa->data>qa->data){
    1955 
    1956 ra->next=qa;
    1957 
    1958 qa=qa->next;
    1959 
    1960 }
    1961 
    1962 else{
    1963 
    1964 ra->next=pa;
    1965 
    1966 pa=pa->next;
    1967 
    1968 }
    1969 
    1970 }
    1971 
    1972 if(pa->next!=NULL)
    1973 
    1974 ra->next=pa;
    1975 
    1976 if(qa->next!=NULL)
    1977 
    1978 ra->next==qa;
    1979 
    1980 return R;
    1981 
    1982 }
    1983 
    1984 101.用递归算法判断数组a[N]是否为一个递增数组。
    1985 递归的方法,记录当前最大的,并且判断当前的是否比这个还大,大则继续,否则返回false结束:
    1986 
    1987 bool fun( int a[], int n )
    1988 
    1989 {
    1990 
    1991 if( n= =1 )
    1992 
    1993 return true;
    1994 
    1995 if( n= =2 )
    1996 
    1997 return a[n-1] >= a[n-2];
    1998 
    1999 return fun( a,n-1) && ( a[n-1] >= a[n-2] );
    2000 
    2001 }
    2002 
    2003 102.编写算法,从10亿个浮点数当中,选出其中最大的10000个。
    2004 用外部排序,在《数据结构》书上有《计算方法导论》在找到第n大的数的算法上加工
    2005 
    2006 103.编写一unix程序,防止僵尸进程的出现.
    2007 同学的4道面试题,应聘的职位是搜索引擎工程师,后两道超级难,(希望大家多给一些算发)
    2008 
    2009 1.给两个数组和他们的大小,还有一动态开辟的内存,求交集,把交集放到动态内存dongtai,并且返回交集个数
    2010 
    2011 long jiaoji(long* a[],long b[],long* alength,long blength,long* dongtai[])
    2012 
    2013 2.单连表的建立,把'a'--'z'26个字母插入到连表中,并且倒叙,还要打印!
    2014 
    2015 方法1:
    2016 
    2017 typedef struct val
    2018 
    2019 {   int date_1;
    2020 
    2021     struct val *next;
    2022 
    2023 }*p;
    2024 
    2025  
    2026 
    2027 void main(void)
    2028 
    2029 {   char c;
    2030 
    2031     
    2032 
    2033     for(c=122;c>=97;c--)
    2034 
    2035        { p.date=c;
    2036 
    2037          p=p->next;
    2038 
    2039         }
    2040 
    2041  
    2042 
    2043     p.next=NULL;
    2044 
    2045 }
    2046 
    2047 }
    2048 
    2049 方法2:
    2050 
    2051 node *p = NULL;
    2052 
    2053 node *q = NULL;
    2054 
    2055  
    2056 
    2057 node *head = (node*)malloc(sizeof(node));
    2058 
    2059 head->data = ' ';head->next=NULL;
    2060 
    2061  
    2062 
    2063 node *first = (node*)malloc(sizeof(node));
    2064 
    2065 first->data = 'a';first->next=NULL;head->next = first;
    2066 
    2067 p = first;
    2068 
    2069  
    2070 
    2071 int longth = 'z' - 'b';
    2072 
    2073 int i=0;
    2074 
    2075 while ( i<=longth )
    2076 
    2077 {
    2078 
    2079 node *temp = (node*)malloc(sizeof(node));
    2080 
    2081 temp->data = 'b'+i;temp->next=NULL;q=temp;
    2082 
    2083  
    2084 
    2085 head->next = temp; temp->next=p;p=q;
    2086 
    2087 i++;
    2088 
    2089 }
    2090 
    2091  
    2092 
    2093 print(head);
    2094 
    2095  
    2096 
    2097 104.可怕的题目终于来了
    2098 象搜索的输入信息是一个字符串,统计300万输入信息中的最热门的前十条,我们每次输入的一个字符串为不超过255byte,内存使用只有1G,
    2099 
    2100 请描述思想,写出算发(c语言),空间和时间复杂度,
    2101 
    2102 7.国内的一些帖吧,如baidu,有几十万个主题,假设每一个主题都有上亿的跟帖子,怎么样设计这个系统速度最好,请描述思想,写出算发(c语言),空间和时间复杂度,
    2103 
    2104  
    2105 
    2106  
    2107 
    2108 #include   string.h
    2109 
    2110 main(void)
    2111 
    2112 {   char   *src="hello,world";
    2113 
    2114     char   *dest=NULL;
    2115 
    2116     dest=(char   *)malloc(strlen(src));
    2117 
    2118     int   len=strlen(str);
    2119 
    2120     char   *d=dest;
    2121 
    2122     char   *s=src[len];
    2123 
    2124     while(len--!=0)
    2125 
    2126       d++=s--;
    2127 
    2128     printf("%s",dest);
    2129 
    2130 }
    2131 
    2132 找出错误!!
    2133 
    2134 #include   "string.h"
    2135 
    2136 #include "stdio.h"
    2137 
    2138 #include "malloc.h"
    2139 
    2140 main(void)
    2141 
    2142 {  
    2143 
    2144 char   *src="hello,world";
    2145 
    2146     char   *dest=NULL;
    2147 
    2148     dest=(char   *)malloc(sizeof(char)*(strlen(src)+1));
    2149 
    2150     int   len=strlen(src);
    2151 
    2152     char   *d=dest;
    2153 
    2154     char   *s=src+len-1;
    2155 
    2156     while(len--!=0)
    2157 
    2158       *d++=*s--;
    2159 
    2160 *d='';
    2161 
    2162     printf("%s",dest);
    2163 
    2164 }
    2165 
    2166 105.判断字符串是否为回文
    2167 bool IsSymmetry(const char* p)
    2168 
    2169      {
    2170 
    2171          assert(p!=NULL);
    2172 
    2173          const char* q=p;      
    2174 
    2175          int len=0;
    2176 
    2177          while(*q++!='')
    2178 
    2179          {
    2180 
    2181               len++;
    2182 
    2183          }       
    2184 
    2185          bool bSign=true;
    2186 
    2187          q=p+len-1;
    2188 
    2189          if (0<len)
    2190 
    2191          {
    2192 
    2193               for (int i=0;i<len/2;i++)
    2194 
    2195               {
    2196 
    2197                    if(*p++!=*q--){ bSign=false;break;};
    2198 
    2199               }
    2200 
    2201          }
    2202 
    2203          if(bSign==true)
    2204 
    2205          {
    2206 
    2207               printf("Yes!
    ");
    2208 
    2209          }
    2210 
    2211          else
    2212 
    2213          {
    2214 
    2215               printf("No!
    ");
    2216 
    2217          }
    2218 
    2219          return bSign;
    2220 
    2221      }
    2222 
    2223 107.ASDL使用的是什么协议?并进行简单描述?
    2224  
    2225 
    2226 108.Static 作用是什么
    2227 首先static的最主要功能是隐藏,其次因为static变量存放在静态存储区,所以它具备持久性和默认值0。
    2228 
    2229 109.什么是预编译,何时需要预编译?
    2230 预编译又称为预处理,是做些代码文本的替换工作。处理#开头的指令,比如拷贝#include包含的文件代码,#define宏定义的替换,条件编译等,就是为编译做的预备工作的阶段,主要处理#开始的预编译指令,预编译指令指示了在程序正式编译前就由编译器进行的操作,可以放在程序中的任何位置。
    2231 
    2232  
    2233 
    2234 c编译系统在对程序进行通常的编译之前,先进行预处理。c提供的预处理功能主要有以下三种:1)宏定义 2)文件包含 3)条件编译
    2235 
    2236  
    2237 
    2238 、总是使用不经常改动的大型代码体。 
    2239 、程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。在这种情况下,可以将所有包含文件预编译为一个预编译头。
    2240 
    2241  
    2242 
    2243 110.进程和线程的区别
    2244 什么是进程(Process):普通的解释就是,进程是程序的一次执行,而什么是线程(Thread),线程可以理解为进程中的执行的一段程序片段。在一个多任务环境中下面的概念可以帮助我们理解两者间的差别:
    2245 
    2246 进程间是独立的,这表现在内存空间,上下文环境;线程运行在进程空间内。 一般来讲(不使用特殊技术)进程是无法突破进程边界存取其他进程内的存储空间;而线程由于处于进程空间内,所以同一进程所产生的线程共享同一内存空间。 同一进程中的两段代码不能够同时执行,除非引入线程。线程是属于进程的,当进程退出时该进程所产生的线程都会被强制退出并清除。线程占用的资源要少于进程所占用的资源。 进程和线程都可以有优先级。在线程系统中进程也是一个线程。可以将进程理解为一个程序的第一个线程。
    2247 
    2248  
    2249 
    2250 线程是指进程内的一个执行单元,也是进程内的可调度实体.与进程的区别:
    2251 (1)地址空间:进程内的一个执行单元;进程至少有一个线程;它们共享进程的地址空间;而进程有自己独立的地址空间;
    2252 (2)进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源
    2253 (3)线程是处理器调度的基本单位,但进程不是.
    2254 (4)二者均可并发执行.
    2255 
    2256 111.插入排序和选择排序
    2257 插入排序基本思想:(假定从大到小排序)依次从后面拿一个数和前面已经排好序的数进行比较,比较的过程是从已经排好序的数中最后一个数开始比较,如果比这个数,继续往前面比较,直到找到比它大的数,然后就放在它的后面,如果一直没有找到,肯定这个数已经比较到了第一个数,那就放到第一个数的前面。那么一般情况下,对于采用插入排序法去排序的一组数,可以先选 取第一个数做为已经排好序的一组数。然后把第二个放到正确位置。
    2258 
    2259  
    2260 
    2261 选择排序(Selection Sort)是一种简单直观的排序算法。它的工作原理如下。首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,然后放到排序序列末尾。以此类推,直到所有元素均排序完毕。
    2262 
    2263 112.运算符优先级问题
    2264 能正确表示a和b同时为正或同时为负的逻辑表达式是(D )。
    2265 
    2266 sssA、(a>=0||b>=0)&&(a<0||b<0) 
    2267 B、(a>=0&&b>=0)&&(a<0&&b<0) 
    2268 C、(a+b>0)&&(a+b<=0) 
    2269 D、a*b>0
    2270 
    2271  
    2272 
    2273 以下关于运算符优先顺序的描述中正确的是(C)。 
    2274 A、关系运算符<算术运算符<赋值运算符<逻辑与运算符 
    2275 B、逻辑与运算符<关系运算符<算术运算符<赋值运算符 
    2276 C、赋值运算符<逻辑与运算符<关系运算符<算术运算符 
    2277 D、算术运算符<关系运算符<赋值运算符<逻辑与运算符
    2278 
    2279  
    2280 
    2281 113.字符串倒序
    2282  
    2283 
    2284 写一个函数将"tom is cat" 倒序打印出来,即 "cat is tom"
    2285 
    2286 //a.ch
    2287 
    2288 #define SPACE ' '
    2289 #define ENDL ''
    2290 
    2291 char* str = "Tom is cat"; // 字符串
    2292 char* p1 = str+strlen(str)-1;
    2293 char* p2 = p1; // 开始时,p1,p2都指向字符串结尾处
    2294 char t=0; // 临时变量,用来保存被临时替换为ENDL的字符
    2295 
    2296 while(str!=p1--)
    2297 {
    2298   if(SPACE!=*p1){
    2299      for(p2=p1+1;SPACE!=*p1; p1--, t=*p2, *p2=ENDL);
    2300 
    2301      // p1+1指向单词的第一个字母,p2指向单词的结尾,此时输出这个单词
    2302                 printf("%s ",p1+1);
    2303                 *p2=t;
    2304                 p2=p1;
    2305          }
    2306 }
    2307 
    2308 Output:
    2309 cat is Tom
    2310 
    2311 ----------------------------------------------------------------------
    2312 1)写一个递归函数将内存中的字符串翻转"abc"->"cba"
    2313 2)写一个函数将"tom is cat" 将内存中的字符串翻转,即 "cat is tomm" 
    2314 
    2315 #include <stdio.h>
    2316 #define SPACE ' '
    2317 #define ENDL ''
    2318 char* s = "The quick brown fox jumps over the lazy dog";
    2319 
    2320 void str_reverse(char* p1,char* p2){
    2321       if(p1==p2)return;
    2322     *p1 = (*p1)+(*p2);
    2323     *p2 = (*p1)-(*p2);
    2324     *p1 = (*p1)-(*p2);
    2325       if(p1==p2-1)return;
    2326       else str_reverse(++p1,--p2);
    2327 }
    2328 
    2329 void str_word_reverse(char* str){
    2330       char *q1=str, *q2=str, *t;
    2331 
    2332       while(*q1==SPACE)q1++;
    2333       if(*q1==ENDL)return; //!
    2334       else q2=q1+1;
    2335 
    2336       while( (*q2!=SPACE) && (*q2!=ENDL) )q2++;
    2337     
    2338      t=q2--; 
    2339     str_reverse(q1,q2);
    2340 
    2341       if(*t==ENDL)return;
    2342       else str_word_reverse(t);
    2343 }
    2344 
    2345 int
    2346 main(int a ,char** b)
    2347 {
    2348     printf("%s
    ",s);
    2349     str_reverse(s,s+strlen(s)-1);
    2350     printf("%s
    ",s);
    2351     str_word_reverse(s);
    2352     printf("%s
    ",s);
    2353            return 0;
    2354 }
    2355 
    2356 Output:
    2357 
    2358 The quick brown fox jumps over the lazy dog
    2359 god yzal eht revo spmuj xof nworb kciuq ehT
    2360 dog lazy the over jumps fox brown quick The
    2361 
    2362 ----------------------------------------------------------------------
    2363 今天同学又问一道题,和上面有些类似,但是要求更严格了一些:
    2364 写一个递归函数将内存中的字符串翻转"abc"->"cba",并且函数原型已确定:void reverse(char* p)
    2365 
    2366 其实,要求越多,思路越确定,我的解如下:
    2367 
    2368 #include <stdio.h>
    2369 #include <string.h>
    2370 char* s = "0123456789";
    2371 #define ENDL ''
    2372 void reverse(char* p){
    2373        //这是这种方法的关键,使用static为的是能用str_reverse的思路,但是不好
    2374        static char* x=0;
    2375        if(x==0)x=p;
    2376        char* q = x+strlen(p)-1; 
    2377        if(p==q)return;
    2378        *q=(*p)^(*q);
    2379        *p=(*p)^(*q);
    2380        *q =(*p)^(*q);
    2381        if(q==p+1)return;
    2382        reverse(++p);
    2383 }
    2384 
    2385 //这种方法就直观多了,但是当字符串很长的时候就很低效
    2386 void reverse2(char* p){
    2387        if(*(p+1)==ENDL)return;
    2388        for(char* o=p+strlen(p)-1,char t=*o;o!=p;o--)
    2389           *o=*(o-1);
    2390        *p=t;
    2391        reverse2(p+1);
    2392 }
    2393 
    2394 int main(int c,char** argv){
    2395        reverse2(s);
    2396        printf("%s
    ",s);
    2397        return 0;
    2398 }
    2399 
    2400  
    2401 
    2402 114.交换两个数的宏定义
    2403  
    2404 
    2405 交换两个参数值的宏定义为:. #define SWAP(a,b) (a)=(a)+(b);(b)=(a)-(b);(a)=(a)-(b);
    2406 
    2407  
    2408 
    2409 115.Itearator各指针的区别
    2410  
    2411 
    2412 游标和指针
    2413 
    2414 我说过游标是指针,但不仅仅是指针。游标和指针很像,功能很像指针,但是实际上,游标是通过重载一元的”*”和”->”来从容器中间接地返回一个值。将这些值存储在容器中并不是一个好主意,因为每当一个新值添加到容器中或者有一个值从容器中删除,这些值就会失效。在某种程度上,游标可以看作是句柄(handle)。通常情况下游标(iterator)的类型可以有所变化,这样容器也会有几种不同方式的转变:
    2415 
    2416 
    2417 iterator——对于除了vector以外的其他任何容器,你可以通过这种游标在一次操作中在容器中朝向前的方向走一步。这意味着对于这种游标你只能使用“++”操作符。而不能使用“--”或“+=”操作符。而对于vector这一种容器,你可以使用“+=”、“—”、“++”、“-=”中的任何一种操作符和“<”、“<=”、“>”、“>=”、“==”、“!=”等比较运算符。
    2418 
    2419  
    2420 
    2421 116. C++中的class和struct的区别
    2422 从语法上,在C++中(只讨论C++中)。class和struct做类型定义时只有两点区别:
    2423 (一)默认继承权限。如果不明确指定,来自class的继承按照private继承处理,来自struct的继承按照public继承处理;
    2424 (二)成员的默认访问权限。class的成员默认是private权限,struct默认是public权限。
    2425 除了这两点,class和struct基本就是一个东西。语法上没有任何其它区别。
    2426 
    2427 不能因为学过C就总觉得连C++中struct和class都区别很大,下面列举的说明可能比较无聊,因为struct和class本来就是基本一样的东西,无需多说。但这些说明可能有助于澄清一些常见的关于struct和class的错误认识:
    24281)都可以有成员函数;包括各类构造函数,析构函数,重载的运算符,友元类,友元结构,友元函数,虚函数,纯虚函数,静态函数;
    24292)都可以有一大堆public/private/protected修饰符在里边;
    24303)虽然这种风格不再被提倡,但语法上二者都可以使用大括号的方式初始化:
    2431 
    2432 A a = {1, 2, 3};不管A是个struct还是个class,前提是这个类/结构足够简单,比如所有的成员都是public的,所有的成员都是简单类型,没有显式声明的构造函数。
    24334)都可以进行复杂的继承甚至多重继承,一个struct可以继承自一个class,反之亦可;一个struct可以同时继承5个class和5个struct,虽然这样做不太好。
    24345)如果说class的设计需要注意OO的原则和风格,那么没任何理由说设计struct就不需要注意。
    24356)再次说明,以上所有说法都是指在C++语言中,至于在C里的情况,C里是根本没有“class”,而C的struct从根本上也只是个包装数据的语法机制。
    2436 ---------------------------------------------------------------
    2437 
    2438 最后,作为语言的两个关键字,除去定义类型时有上述区别之外,另外还有一点点:“class”这个关键字还用于定义模板参数,就像“typename”。但关键字“struct”不用于定义模板参数。
    2439 
    2440  
    2441 
    2442 关于使用大括号初始化
    2443 
    2444   class和struct如果定义了构造函数的话,都不能用大括号进行初始化
    2445 
    2446   如果没有定义构造函数,struct可以用大括号初始化。
    2447 
    2448   如果没有定义构造函数,且所有成员变量全是public的话,可以用大括号初始化。
    2449 
    2450   关于默认访问权限
    2451 
    2452   class中默认的成员访问权限是private的,而struct中则是public的。
    2453 
    2454   关于继承方式
    2455 
    2456   class继承默认是private继承,而struct继承默认是public继承。
    2457 
    2458   关于模版
    2459 
    2460  
    2461 
    2462   在模版中,类型参数前面可以使用class或typename,如果使用struct,则含义不同,struct后面跟的是“non-type template parameter”,而class或typename后面跟的是类型参数。
    2463 
    2464  
    2465 
    2466 class中有个默认的this指针,struct没有
    2467 不同点:构造函数,析构函数 this 指针
    2468 
    2469  
    2470 
    2471 117.有关重载函数
    2472  
    2473 
    2474 返回值类型不同构不成重载 
    2475 参数参数顺序不同能构成重载
    2476 
    2477 c++函数同名不同返回值不算重载!函数重载是忽略返回值类型的。 
    2478 
    2479 --------------------------------------------- 
    2480 成员函数被重载的特征有: 
    2481 1) 相同的范围(在同一个类中); 
    2482 2) 函数名字相同; 
    2483 3) 参数不同; 
    2484 4) virtual关键字可有可无。
    2485 
    2486 5) 成员函数中 有无const (函数后面) 也可判断是否重载
    2487 
    2488  
    2489 
    2490 118.数据库与T-SQL语言
    2491    
    2492 关系数据库是表的集合,它是由一个或多个关系模式定义。SQL语言中的数据定义功能包括对数据库、基本表、视图、索引的定义。
    2493 
    2494  
    2495 
    2496 119.关系模型的基本概念
    2497 
    2498  关系数据库以关系模型为基础,它有以下三部分组成:
    2499     ●数据结构——模型所操作的对象、类型的集合
    2500     ●完整性规则——保证数据有效、正确的约束条件
    2501     ●数据操作——对模型对象所允许执行的操作方式
    2502     关系(Relation)是一个由行和列组成的二维表格,表中的每一行是一条记录(Record),每一列是记录的一个字段(Field)。表中的每一条记录必须是互斥的,字段的值必须具有原子性。
    2503 
    2504 120.SQL语言概述
    2505 
    2506     SQL(结构化查询语言)是关系数据库语言的一种国际标准,它是一种非过程化的语言。通过编写SQL,我们可以实现对关系数据库的全部操作。
    2507     ●数据定义语言(DDL)——建立和管理数据库对象
    2508     ●数据操纵语言(DML)——用来查询与更新数据
    2509     ●数据控制语言(DCL)——控制数据的安全性
    2510 
    2511  
    2512 
    2513 起来是一个很简单的问题,每一个使用过RDBMS的人都会有一个概念。
    2514 
    2515 事务处理系统的典型特点是具备ACID特征。ACID指的是Atomic(原子的)、Consistent(一致的)、Isolated(隔离的)以及Durable(持续的),它们代表着事务处理应该具备的四个特征:
    2516 
    2517 原子性:组成事务处理的语句形成了一个逻辑单元,不能只执行其中的一部分
    2518 
    2519 一致性:在事务处理执行之前和之后,数据是一致的。
    2520 
    2521 隔离性:一个事务处理对另一个事务处理没有影响。
    2522 
    2523 持续性:当事务处理成功执行到结束的时候,其效果在数据库中被永久纪录下来。
    2524 
    2525  
    2526 
    2527 121.C语言中结构化程序设计的三种基本控制结构
    2528  
    2529 
    2530 顺序结构 
    2531 选择结构 
    2532 循环结构
    2533 
    2534  
    2535 
    2536 122.CVS是什么
    2537  
    2538 
    2539 cvs(Concurrent Version System) 是一个版本控制系统。使用它,可以记录下你的源文件的历史。 
    2540 
    2541 例如,修改软件时可能会不知不觉混进一些 bug,而且可能过了很久你才会察觉到它们的存在。有了 cvs,你可以很容易地恢复旧版本,并从中看出到底是哪个修改导致了这个 bug。有时这是很有用的。
    2542 
    2543 CVS服务器端对每个文件维护着一个修订号,每次对文件的更新,都会使得文件的修订号加1。在客户端中也对每个文件维护着一个修订号,CVS通过这两个修订号的关系,来进行Update,Commit和发现冲突等操作操作
    2544 
    2545  
    2546 
    2547 123.三种基本的数据模型
    2548  
    2549 
    2550 按照数据结构类型的不同,将数据模型划分为层次模型、网状模型和关系模型。
    2551 
    2552 124.设计模式:工厂模式 和 单例模式 介绍一下?
    2553 工程模式即将对象创建过程封装即为工厂模式。
    2554 单例模式即整个类只有一个对象,并且不允许显示创建。
    2555 
    2556 125.vector 和 list的区别?
    2557 vector内部使用数组,访问速度快,但是删除数据比较耗性能
    2558 list内部使用链表,访问速度慢,但是删除数据比较快
    2559 
    2560 126.纯虚函数是怎样实现的?在编译原理上讲一下?
    2561 在类内部添加一个虚拟函数表指针,该指针指向一个虚拟函数表,该虚拟函数表包含了所有的虚拟函数的入口地址,每个类的虚拟函数表都不
    2562 
    2563 一样,在运行阶段可以循此脉络找到自己的函数入口。
    2564 
    2565 纯虚函数相当于占位符,先在虚函数表中占一个位置由派生类实现后再把真正的函数指针填进去。除此之外和普通的虚函数没什么区别。
    2566 
    2567 127.抽象类为什么不能实例化?
    2568 抽象类中的纯虚函数没有具体的实现,所以没办法实例化。
    2569 
    2570  128.在函数后面加个const是怎么理解的?
    2571 
    2572 在函数后面加个const一般在类的成员函数中使用,表示这个函数不修改数据成员的值。
    2573 
    2574 另:void set_prt_val(int val)const {*ptr= val}理解:指针ptr指向的内容不是类的数据成员,所以这可这么写:*ptr = val;但这个指针在这个函数中不能修改。如果写成这样:ptr = &i(假设i是另外一个整形变量)就不对了,因为改变了指针的内容。
    2575 
    2576 129.进程间通信类型:
    2577 
    25781)环境变量、文件描述符 一般Unix环境下的父进程执行fork(),生成的子进程拥有了父进程当前设置的环境变量以及文件描述符;由于通信是一个单向的、一次性的通信,随后的父进程以及子进程后续的内容不能再能共享;
    2579 
    25802)命令行参数 大多数用户都使用过ShellExec相关的命令,此API可以打开新的进程,并可以通过接口里的输入参数进行信息共享;同样,他也是一个单项、一次性的通信;
    2581 
    25823)管道 使用文件和写方式访问公用的数据结构;管道分为匿名管道和命名管道,前者是用作关联进程间用,后者为无关联的进程使用;前者通过文件描述符或文件句柄提供对命名管道的访问,后者需要知道管道名称才能读写管道;一般来讲,读写的内容是字节流,需要转换为有意义的结构才有意义;
    2583 
    25844)共享内存 进程需要可以被其他进程访问浏览的进程块;进程间共享内存的关系与函数间共享全局变量的关系类似
    2585 
    25865)DDE 动态数据交互
    2587 
    2588 线程间通信类型:
    2589 
    25901)全局数据;
    2591 
    25922)全局变量;
    2593 
    25943)全局数据结构;
    2595 
    25964)线程间通信的参数:pThread_create这类API接口中的参数
    2597 
    2598  130.关于内存对齐的问题以及sizof()的输出
    2599 答:编译器自动对齐的原因:为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。
    2600 
    2601 131.winsock建立连接的主要实现步骤?
    2602 答:
    2603 
    2604 TCP:服务器端:1.socket()建立套接字,2将套接字绑定到本地地址和端口上,绑定(bind)3.将套接字设为监听模式,准备接收客户端,监听(listen);4.等待客户端请求到来,请求到来后,连接请求,并返回一个新的对应此连接的套接字,accept()5.用返回的套接字和客户端进行通讯(send/recv);6.返回并等待另一客户请求。7.关闭套接字。
    2605 客户端:1.socket()建立套接字2.向服务器发出连接请求,(connect)2。和服务器进行通信,send()和recv(),在套接字上写读数据,直至数据交换完毕;4closesocket()关闭套接字。
    2606 UDP:1服务器端:1.创建套接字(socekt)2.将套接字绑定到本地地址和端口上(bind);3.等待接收数据(recvfrom);4.closesocket()关闭套接字。
    2607 
    2608 客户端:1.创建套接字(socekt)2,向服务器端发送数据(sendto)3.closesocket()关闭套接字。
    2609 
    2610 132.C++中为什么用模板类。
    2611 答:(1)可用来创建动态增长和减小的数据结构
    26122)它是类型无关的,因此具有很高的可复用性。
    26133)它在编译时而不是运行时检查数据类型,保证了类型安全
    26144)它是平台无关的,可移植性
    26155)可用于基本数据类型
    2616 
    2617 133.动态连接库的两种方式?
    2618 答:调用一个DLL中的函数有两种方法:
    2619 1.载入时动态链接(load-time dynamic linking),模块非常明确调用某个导出函数,使得他们就像本地函数一样。这需要链接时链接那些函数所在DLL的导入库,导入库向系统提供了载入DLL时所需的信息及DLL函数定位。
    2620 2.运行时动态链接(run-time dynamic linking),运行时可以通过LoadLibrary或LoadLibraryEx函数载入DLL。DLL载入后,模块可以通过调用GetProcAddress获取DLL函数的出口地址,然后就可以通过返回的函数指针调用DLL函数了。如此即可避免导入库文件了。
    2621 
    2622  134..CSingleLock是干什么的。
    2623 答:同步多个线程对一个数据类的同时访问
    2624 
    2625  135.编写strcat函数(6分)
    2626 已知strcat函数的原型是char *strcat (char *strDest, const char *strSrc);
    2627 其中strDest 是目的字符串,strSrc 是源字符串。
    26281)不调用C++/C 的字符串库函数,请编写函数 strcat
    2629 答:
    2630 VC源码:
    2631 char * __cdecl strcat (char * dst, const char * src)
    2632 {
    2633 char * cp = dst;
    2634 while( *cp )
    2635 cp++; /* find end of dst */
    2636 while( *cp++ = *src++ ) ; /* Copy src to end of dst */
    2637 return( dst ); /* return dst */
    2638 }
    26392)strcat能把strSrc 的内容连接到strDest,为什么还要char * 类型的返回值?
    2640 答:方便赋值给其他变量
    2641 
    2642 136.编写类String 的构造函数、析构函数和赋值函数(25 分)
    2643 已知类String 的原型为:
    2644 class String
    2645 {
    2646 public:
    2647 String(const char *str = NULL); // 普通构造函数
    2648 String(const String &other); // 拷贝构造函数
    2649 ~ String(void); // 析构函数
    2650 String & operate =(const String &other); // 赋值函数
    2651 private:
    2652 char *m_data; // 用于保存字符串
    2653 };
    2654 请编写String 的上述4 个函数。
    2655 标准答案:
    2656 // String 的析构函数
    2657 String::~String(void) // 3 分
    2658 {
    2659 delete [] m_data;
    2660 // 由于m_data 是内部数据类型,也可以写成 delete m_data;
    2661 }
    2662 // String 的普通构造函数
    2663 String::String(const char *str) // 6 分
    2664 {
    2665 if(str==NULL)
    2666 {
    2667 m_data = new char[1]; // 若能加 NULL 判断则更好
    2668 *m_data = ‘0’;
    2669 }
    2670 else
    2671 {
    2672 int length = strlen(str);
    2673 m_data = new char[length+1]; // 若能加 NULL 判断则更好
    2674 strcpy(m_data, str);
    2675 }
    2676 }
    2677 
    2678 // 拷贝构造函数
    2679 String::String(const String &other) // 3 分
    2680 {
    2681 int length = strlen(other.m_data);
    2682 m_data = new char[length+1]; // 若能加 NULL 判断则更好
    2683 strcpy(m_data, other.m_data);
    2684 }
    2685 
    2686 // 赋值函数
    2687 String & String::operate =(const String &other) // 13 分
    2688 {
    2689 // (1) 检查自赋值 // 4 分
    2690 if(this == &other)
    2691 return *this;
    2692 // (2) 释放原有的内存资源 // 3 分
    2693 delete [] m_data;
    2694 // (3)分配新的内存资源,并复制内容 // 3 分
    2695 int length = strlen(other.m_data);
    2696 m_data = new char[length+1]; // 若能加 NULL 判断则更好
    2697 strcpy(m_data, other.m_data);
    2698 // (4)返回本对象的引用 // 3 分
    2699 return *this;
    2700 }
  • 相关阅读:
    SQL查询
    SQL语句
    SQL语句
    查询设计分析
    数据库引擎调整顾问
    详解执行计划
    详解索引连接类型
    查询开销
    利用SQL Profiler处理开销较大的查询
    状压dp的题目列表 (一)
  • 原文地址:https://www.cnblogs.com/herizai/p/3186062.html
Copyright © 2020-2023  润新知