admin 管理员组文章数量: 1086019
2024年12月29日发(作者:linuxecho)
w、delete、malloc、free关系
delete会调用对象的析构函数,和new对应free只会释放内存,new调用结构函数。malloc与free是C++/C语言的标
准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。对于非内部数据类型的对象而言,光用
maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行结构函数,对象在消亡之前要自动执行析构函数。因
为malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行结构函数和析构函数的任务强加于
malloc/free。因此C++语言需要一个能完成动态内存分派和初始化工作的运算符new,以及一个能完成清理与释放内存工作
的运算符delete。注意new/delete不是库函数。
te与 delete []区分?delete只会调用一次析构函数,而delete[]会调用每一个组员的析构函数。在More
Effective C++中有更为详细的解释:“当delete操作符用于数组时,它为每个数组元素调用析构函数,然后调用opera
tordelete来释放内存。”delete与New配套,delete []与new []配套
MemTest*mTest1=newMemTest[10];MemTest*mTest2=newMemTest;int*pInt1=newint[10];
int*pInt2=new int; delete[]pInt1; //-1- delete[]pInt2; //-2- delete[]mTest1;//-3- delete[]mT
est2;//-4-
在-4-处报错。这就阐明:对于内建简单数据类型,delete和delete[]功效是相同的。对于自定义的复杂数据类型,de
lete和delete[]不能互用。delete[]删除一个数组,delete删除一个指针简单来说,用new分派的内存用delete删除用n
ew[]分派的内存用delete[]删除delete[]会调用数组元素的析构函数。内部数据类型没有析构函数,因此问题不大。假如你
在用delete时没用括号,delete就会以为指向的是单个对象,否则,它就会以为指向的是一个数组。
3.C C++ JAVA共同点,不一样之处?
4.继承优缺陷。类继承是在编译时刻静态定义的,且可直接使用,类继承能够较以便地变化父类的实现。不过类继承也有某
些不足之处。首先,因为继承在编译时刻就定义了,因此无法在运行时刻变化从父类继承的实现。更糟的是,父类一般最少定
义了子类的部分行为,父类的任何变化都也许影响子类的行为。假如继承下来的实现不适合处理新的问题,则父类必须重写或
被其他更适合的类替代。这种依赖关系限制了灵活性并最后限制了复用性。(待补充)
5.C++有哪些性质(面对对象特点)?封装,继承和多态。在面对对象程序设计语言中,封装是利用可重用成份结构软件系
统的特性,它不但支持系统的可重用性,并且尚有利于提升系统的可扩充性;消息传递能够实现发送一个通用的消息而调用
不一样的措施;封装是实现信息隐蔽的一个技术,其目标是使类的定义和实现分离。
6.子类析构时要调用父类的析构函数吗?析构函数调用的次序是先派生类的析构后基类的析构,也就是说在基类的的析构调
用的时候,派生类的信息已经所有销毁了。定义一个对象时先调用基类的结构函数、然后调用派生类的结构函数;析构的时候
恰好相反:先调用派生类的析构函数、然后调用基类的析构函数JAVA无析构函数深拷贝和浅拷贝
7.多态,虚函数,纯虚函数
8.求下面函数的返回值(微软)
int func(x) ﻫ{ ﻫ int countx = 0;
while(x)
{
countx ++;
x = x&(x-1); ﻫ } ﻫ return countx;
}
假定x = 9999。 答案:8。思绪:将x转化为2进制,看含有的1的个数。
9.什么是“引用”?申明和使用“引用”要注意哪些问题?
答:引用就是某个目标变量的“别名”(alias),对引用的操作与对变量直接操作效果完全相同。申明一个引用的时候,切记要对
其进行初始化。引用申明完成后,相称于目标变量名有两个名称,即该目标原名称和引用名,不能再把该引用名作为其他变量名
的别名。申明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它自身不是一个数据类型,因此
引用自身不占存储单元,系统也不给引用分派存储单元。不能建立数组的引用。
10.将“引用”作为函数参数有哪些特点?
(1)传递引用给函数与传递指针的效果是同样的。这时,被调函数的形参就成为本来主调函数中的实参变量或对象的一个别
名来使用,因此在被调函数中对形参变量的操作就是对其对应的目标对象(在主调函数中)的操作。
(2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,
当发生函数调用时,需要给形参分派存储单元,形参变量是实参变量的副本;假如传递的是对象,还将调用拷贝结构函数。
因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。
(3)使用指针作为函数的参数虽然也能达成与使用引用的效果,不过,在被调函数中同样要给形参分派存储单元,且需要
重复使用"*指针变量名"的形式进行运算,这很轻易产生错误且程序的阅读性较差;另首先,在主调函数的调用点处,必须
用变量的地址作为实参。而引用更轻易使用,更清楚。
11.在什么时候需要使用“常引用”?假如既要利用引用提升程序的效率,又要保护传递给函数的数据不在函数中被变化,就
应使用常引用。常引用申明方式:const 类型标识符 &引用名=目标变量名;
例1 int a ; const int &ra=a; ra=1; //错误 a=1; //正确
例2 string foo( ); void bar(string & s);
那么下面的体现式将是非法的: bar(foo( )); bar("hello world");
原因在于foo( )和"hello world"串都会产生一个暂时对象,而在C++中,这些暂时对象都是const类型的。因此上面的体
现式就是试图将一个const类型的对象转换为非const类型,这是非法的。引用型参数应当在能被定义为const的情况
下,尽也许定义为const 。
12.将“引用”作为函数返回值类型的格式、好处和需要遵守的规则?
格式:类型标识符 &函数名(形参列表及类型阐明){ //函数体 }
好处:在内存中不产生被返回值的副本;(注意:正是因为这点原因,因此返回一个局部变量的引用是不可取的。因为伴
随该局部变量生存期的结束,对应的引用也会失效,产生runtime error! 注意事项:
(1)不能返回局部变量的引用。这条能够参考Effective C++[1]的Item 31。重要原因是局部变量会在函数返回后被销
毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态。
(2)不能返回函数内部new分派的内存的引用。这条能够参考Effective C++[1]的Item 31。虽然不存在局部变量的
被动销毁问题,可对于这种情况(返回函数内部new分派内存的引用),又面临其他尴尬局面。例如,被函数返回的引用只是作
为一个暂时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分派)就无法释放,导致memo
ry leak。
(3)能够返回类组员的引用,但最佳是const。这条标准能够参考Effective C++[1]的Item 30。重要原因是当对象的属
性是与某种业务规则(business rule)有关联的时候,其赋值常常与某些其他属性或者对象的状态有关,因此有必要将赋值操
作封装在一个业务规则当中。假如其他对象能够取得该属性的非常量引用(或指针),那么对该属性的单纯赋值就会破坏业
务规则的完整性。
(4)流操作符重载返回值申明为“引用”的作用:流操作符<<和>>,这两个操作符常常希望被连续使用,例如:cout << "hell
o" << endl; 因此这两个操作符的返回值应当是一个仍然支持这两个操作符的流引用。可选的其他方案包括:返回一
个流对象和返回一个流对象指针。不过对于返回一个流对象,程序必须重新(拷贝)结构一个新的流对象,也就是说,连续的
两个<<操作符实际上是针对不一样对象的!这无法让人接收。对于返回一个流指针则不能连续使用<<操作符。因此,返回
一个流对象引用是惟一选择。这个唯一选择很核心,它阐明了引用的重要性以及无可替代性,也许这就是C++语言中引入引
用这个概念的原因吧。 赋值操作符=。这个操作符象流操作符同样,是能够连续使用的,例如:x = j = 10;或者
(x=10)=100;赋值操作符的返回值必须是一个左值,以便能够被继续赋值。因此引用成了这个操作符的惟一返回值选择。
例3
#i nclude
int &put(int n);
int vals[10];ﻫint error=-1;ﻫvoid main()ﻫ{ﻫput(0)=10; //以put(0)函数值作为左值,等价于vals[0]=10; ﻫput(9)=
20; //以put(9)函数值作为左值,等价于vals[9]=20;
cout< cout<<vals[9]; } ﻫint &put(int n) { if (n>=0 && n<=9 ) return vals[n]; ﻫelse { cout<<"subscript error"; return error; } } (5)在另外的某些操作符中,却千万不能返回引用:+-*/ 四则运算符。它们不能返回引用,Effective C++[1]的Item2 3详细的讨论了这个问题。重要原因是这四个操作符没有side effect,因此,它们必须结构一个对象作为返回值,可选的方案包 括:返回一个对象、返回一个局部变量的引用,返回一个new分派的对象的引用、返回一个静态对象引用。依照前面提到的引 用作为返回值的三个规则,第2、3两个方案都被否决了。静态对象的引用又因为((a+b) == (c+d))会永远为true而导 致错误。因此可选的只剩余返回一个对象了。 13.“引用”与多态的关系?引用是除指针外另一个能够产生多态效果的伎俩。这意味着,一个基类的引用能够指向它的派生类 实例。例4 Class A; Class B : Class A{...}; B b; A & ref = b; 14.“引用”与指针的区分是什么? 1) 引用必须被初始化,指针无须。 2) 引用初始化以后不能被变化,指针能够变化所指的对象。 2) 不存在指向空值 的引用,不过存在指向空值的指针。 指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的 可读性差;而引用自身就是目标变量的别名,对引用的操作就是对目标变量的操作。另外,就是上面提到的对函数传ref和 pointer的区分。 15.什么时候需要“引用”?流操作符<<和>>、赋值操作符=的返回值、拷贝结构函数的参数、赋值操作符=的参数、其他情况 都推荐使用引用。以上 2-8 参考: 16.结构与联合有和区分? (1). 结构和联合都是由多个不一样的数据类型组员组成, 但在任何同一时刻, 联合中只存储 了一个被选中的组员(所有组员共用一块地址空间), 而结构的所有组员都存在(不一样组员的存储地址不一样)。 (2). 对于联合的不一样组员赋值, 将会对其他组员重写, 本来组员的值就不存在了, 而对于结构的不一样组员赋值是互 不影响的。 17.面有关“联合”的题目标输出? a)#i nclude union { int i; char x[2];ﻫ}a; void main()ﻫ{ a.x[0] = 10; ﻫa.x[1] = 1;ﻫprintf("%d",a.i);ﻫ} 答案:266 (低位低地址,高位高地址,内存占用情况是Ox010A) b) main() { ﻫ union{ /*定义一个联合*/ int i; struct{ /*在联合中定义一个结构*/ char first; ﻫ char second; }half; ﻫ }number; ﻫ number.i=0x4241; /*联合组员赋值*/ printf("%c%cn", number.half.first, mumber.hand); ﻫ num='a'; /*联合中 结构组员赋值*/ ﻫ number.half.second='b'; printf("%xn", number.i); ﻫ getch(); ﻫ } ﻫ答案: AB (0x41对应'A',是低位;Ox42对应'B', 是高位) 6261 (number.i和number.half共用一块地址空间) 18.关联、聚合(Aggregation)以及组合(Composition)的区分? 包括到UML中的某些概念:关联是表示两个类的一般性联系,例如“学生”和“老师”就是一个关联关系;聚合表示has-a的 关系,是一个相对涣散的关系,聚合类不需要对被聚合类负责,如下图所示,用空的菱形表示聚合关系:从实现的角度讲,聚合 能够表示为: class A {...} class B { A* a; .....} 而组合表示contains-a的关系,关联性强于聚合:组合类与被组合类有相同的生命周期,组合类要对被组合类负责,采取实 心的菱形表示组合关系:实现的形式是: class A{...} class B{ A a; ...} 27. main 函数执行此前,还会执行什么代码?答案:全局对象的结构函数会在main 函数之前执行。 28. 描述内存分派方式以及它们的区分? 1)从静态存储区域分派。内存在程序编译时就已经分派好,这块内存在程序的整个运行期间都存在。例如全局变量,static 变量。 2)在栈上创建。在执行函数时,函数内局部变量的存储单元都能够在栈上创建,函数执行结束时这些存储单元自动被释 放。栈内存分派运算内置于处理器的指令集。ﻫ3)从堆上分派,亦称动态内存分派。程序在运行时用malloc 或new 申请任意多少的内存,程序员自己负责在何时用free 或delete 释放内存。动态内存的生存期由程序员决定,使用非常灵 活,但问题也最多。 29.struct 和 class 的区分 答案:struct 的组员默认是公有的,而类的组员默认是私有的。struct 和 class 在其他方面是功效相称的。从感情上讲, 大多数的开发者感到类和结构有很大的差异。感觉上结构仅仅象一堆缺乏封装和功效的开放的内存位,而类就象活的并且可 靠的社会组员,它有智能服务,有牢靠的封装屏障和一个良好定义的接口。既然大多数人都这么以为,那么只有在你的类有 极少的措施并且有公有数据(这种事情在良好设计的系统中是存在的!)时,你也许应当使用 struct 核心字,否则,你应当 使用 class 核心字。 30.当一个类A 中没有任何组员变量与组员函数,这时sizeof(A)的值是多少? 答案:假如不是零,请解释一下编译器为何没有让它为零。(Autodesk)肯定不是零。举个反例,假如是零的话,申明一个c lass A[10]对象数组,而每一个对象占用的空间是零,这时就没措施辨别A[0],A[1]…了。值 为1. 32. 比较C++中的4种类型转换方式? 请参考:,重点是static_cast, dynamic_cast和reinterpret_cast的区分和应用。 dynamic_casts在协助你浏览继承层次上是有限制的。它不能被用于缺乏虚函数的类型上,它被用于安全地沿着类的继承 关系向下进行类型转换。如你想在没有继承关系的类型中进行转换,你也许想到static_cast 44.写一个在一个字符串(n)中寻找一个子串(m)第一个位置的函数。 KMP算法效率最佳,时间复杂度是O(n+m),详见: 48.指针找错题ﻩ 分析这些面试题,自身包括很强的趣味性;而作为一名研发人员,通过对这些面试题的深入剖析则可深入增强自身的内功。 ﻫ2.找错题 试题1: 如下是引用片段:ﻫvoid test1() //数组越界ﻫ{ char string[10];ﻫ char* str1 = ""; strcpy( string, str1 );} 试题2: ﻫ如下是引用片段:ﻫvoid test2()ﻫ{ char string[10], str1[10]; ﻫ int i; for(i=0; i<10; i++)ﻫ { str1= 'a'; }ﻫ strcpy( string, str1 );ﻫ } 试题3: 如下是引用片段:ﻫvoid test3(char* str1)ﻫ { char string[10];ﻫ if( strlen( str1 ) <= 10 )ﻫ { strcpy( string, str1 ); } } 解答:试题1字符串str1需要11个字节才能存储下(包括末尾的’0’),而string只有10个字节的空间,strcpy会导致数组 越界;试题2,假如面试者指出字符数组str1不能在数组内结束能够给3分;假如面试者指出strcpy(string,str1)调用使得从 str1内存起复制到string内存起所复制的字节数具备不确定性能够给7分,在此基础上指出库函数strcpy工作方式的给 10分;ﻫ对试题3,if(strlen(str1) <= 10)应改为if(strlen(str1) <10),因为strlen的成果未统计’0’所占用的1个字 节。剖析:考查对基本功的掌握 (1)字符串以’0’结尾; (2)对数组越界把握的敏感度; (3)库函数strcpy的工作 方式, 49.假如编写一个标准strcpy函数?总分值为10,下面给出几个不一样得分的答案:2分 如下是引用片段:ﻫvoid strcpy( char *strDest, char *strSrc )ﻫ {ﻫ while( (*strDest++ = * strSrc++) != ‘0’ ); } 4分 如下是引用片段:ﻫ void strcpy( char *strDest, const char *strSrc ) //将源字符串加const,表白其为输入参数,加2分ﻫ { while( (*strDest++ = * strSrc++) != ‘\0’ ); } 7分 如下是引用片段:ﻫvoid strcpy(char *strDest, const char *strSrc) { //对源地址和目标地址加非0断言,加3分 assert( (strDest != NULL) &&(strSrc != NULL) ); while( (*strDest++ = * strSrc++) != ‘\0’ ); } 10分 如下是引用片段: //为了实现链式操作,将目标地址返回,加3分! char * strcpy( char *strDest, const char *strSrc ) { assert( (strDest != NULL) &&(strSrc != NULL) ); //对源地址和目标地址加非0断言ﻫ char *address = strDest; while( (*strDest++ = * strSrc++) != ‘0’ );ﻫ return address; //为了实现链式操作,将目标地址返回 } 从2分到10分的几个答案我们能够清楚的看到,小小的strcpy竟然暗藏着这么多玄机,真不是盖的!需要多么扎实的基本功 才能写一个完美的strcpy啊! (4)对strlen的掌握,它没有包括字符串末尾的'0'。读者看了不一样分值的strcpy版本,应当也能够写出一个10分的 strlen函数了, int strlen( const char *str ) //输入参数const 如下是引用片段:ﻫ { assert( strt != NULL ); //断言字符串地址非0 int len=0; //注,一定要初始化。 while( (*str++) != '\0' )ﻫ { len++; }ﻫ return len; } 试题4:如下是引用片段: void GetMemory( char *p )//内存分派 { p = (char *) malloc( 100 ); }ﻫ void Test( void )ﻫ { char *str = NULL;ﻫ GetMemory( str );ﻫ strcpy( str, "hello world" );ﻫ printf( str ); } 试题5:如下是引用片段:ﻫ char *GetMemory( void )ﻫ { char p[] = "hello world";ﻫ return p; } void Test( void )ﻫ { char *str = NULL;ﻫ str = GetMemory(); printf( str ); }ﻫ 试题6:如下是引用片段: void GetMemory( char **p, int num ) { *p = (char *) malloc( num ); }ﻫ void Test( void )ﻫ { char *str = NULL; GetMemory( &str, 100 ); strcpy( str, "hello" );ﻫ printf( str ); } 试题7:如下是引用片段:ﻫ void Test( void ) { char *str = (char *) malloc( 100 );ﻫ strcpy( str, "hello" );ﻫ free( str );ﻫ ... //省略的其他语 句 } 解答:试题4传入中GetMemory( char *p )函数的形参为字符串指针,在函数内部修改形参并不能真正的变化传入形 参的值,执行完char *str = NULL; GetMemory( str ); 后的str仍然为NULL;试题5中char p[] = "hello wo rld"; return p;的p[]数组为函数内的局部自动变量,在函数返回后,内存已经被释放。这是许多程序员常犯的错误,其 根源在于不了解变量的生存期。试题6的GetMemory防止了试题4的问题,传入GetMemory的参数为字符串指针的指 针,不过在GetMemory中执行申请内存及赋值语句 *p = (char *) malloc( num );后未判断内存是否申请成功,应加 上: if ( *p == NULL ) {...//进行申请内存失败处理} 试题7存在与试题6同样的问题,在执行char *str = (char *) malloc(100);后未进行内存是否申请成功的判断;另外, 在free(str)后未置str为空,导致也许变成一个“野”指针,应加上: str = NULL;试题6的Test函数中也未对mal loc的内存进行释放。ﻫ 剖析:试题4~7考查面试者对内存操作的了解程度,基本功扎实的面试者一般都能正确的回答其 中50~60的错误。不过要完全解答正确,却也绝非易事。 对内存操作的考查重要集中在: (1)指针的了解; (2)变量的生存期及作用范围; (3)良好的动态内存申请和释放习惯。ﻫ 再看看下面的一段程序有什么错误: ﻫ如下是引用片段:ﻫswap( int* p1,int* p2 )ﻫ{ int *p;ﻫ *p = *p1; *p1 = *p2; *p2 = *p; }ﻫ 在swap函数中,p是一个“野”指针,有也许指向系统区,导致程序运行的瓦解。在VC++中DEBUG 运行时提示错误“Access Violation”。该程序应当改为ﻫ如下是引用片段: swap( int* p1,int* p2 ) { int p; p = *p1;ﻫ *p1 = *p2;ﻫ *p2 = p; } 51.h头文献中的ifndef/define/endif 的作用?答:预防该头文献被重复引用。 52.#i nclude<file.h> 与 #i nclude "file.h"的区分? 答:前者是从Standard Library的途径寻找和引用file.h,而后者是从目前工作途径搜寻并引用file.h。 53.在C++ 程序中调用被C 编译器编译后的函数,为何要加extern “C”? C++语言支持函数重载,C语言不支持函数重载。C++提供了C连接互换指定符号extern “C”处理名字匹配问题。 首先,作为extern是C/C++语言中表白函数和全局变量作用范围(可见性)的核心字,该核心字告诉编译器,其申明的函数 和变量能够在本模块或其他模块中使用。一般,在模块的头文献中对本模块提供应其他模块引用的函数和全局变量以核心 字extern申明。例如,假如模块B欲引用该模块A中定义的全局变量和函数时只需包括模块A的头文献即可。这么,模块B 中调用模块A中的函数时,在编译阶段,模块B虽然找不到该函数,不过并不会报错;它会在连接阶段中从模块A编译生成 的目标代码中找到此函数。extern "C"是连接申明(linkage declaration),被extern "C"修饰的变量和函数 是按照C语言方式编译和连接的,来看看C++中对类似C的函数是怎样编译的:作为一个面对对象的语言,C++支持函数 重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不一样。例如,假设某个函数的原型为: void foo( int x, int y );该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像 _foo_int_int之类的名字(不一样的编译器也许生成的名字不一样,不过都采取了相同的机制,生成的新名字称为 “mangled name”)。_foo_int_int 这么的名字包括了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函 数重载的。例如,在C++中,函数void foo( int x, int y )与void foo( int x, float y )编译生成的符号是不相 同的,后者为_foo_int_float。同样地,C++中的变量除支持局部变量外,还支持类组员变量和全局变量。用户所编写 程序的类组员变量也许与全局变量同名,我们以"."来辨别。而本质上,编译器在进行编译时,与函数的处理相同,也为类 中的变量取了一个独一无二的名字,这个名字与用户程序中同名的全局变量名字不一样。未加extern "C"申明时的连接 方式 假设在C++中,模块A的头文献如下: // 模块A头文献 moduleA.h #ifndef MODULE_A_H #define MODULE_A_Hﻫint foo( int x, int y ); #endif 在模块B中引用该函数:ﻫ// 模块B实现文献 mod #i nclude "moduleA.h"ﻫfoo(2,3); 加extern "C"申明后的编译和连接方式 加extern "C"申明后,模块A的头文献变为:ﻫ// 模块A头文献 moduleA.hﻫ#ifndef MODULE_A_Hﻫ#define MOD ULE_A_Hﻫextern "C" int foo( int x, int y );ﻫ#endif 在模块B的实现文献中仍然调用foo( 2,3 ),其成果是:ﻫ(1)模块A编译生成foo的目标代码时,没有对其名字进行特 殊处理,采取了C语言的方式;(2)连接器在为模块B的目标代码寻找foo(2,3)调用时,寻找的是未经修改的符号名_ foo。假如在模块A中函数申明了foo为extern "C"类型,而模块B中包括的是extern int foo( int x, int y ) ,则模块B找不到模块A中的函数;反之亦然。因此,能够用一句话概括extern “C”这个申明的真实目标(任何语言中 的任何语法特性的诞生都不是随意而为的,起源于真实世界的需求驱动。我们在思考问题时,不能只停留在这个语言是怎么 做的,还要问一问它为何要这么做,动机是什么,这么我们能够更深入地了解许多问题):实现C++与C及其他语言的混合编 程。 明白了C++中extern "C"的设置动机,我们下面来详细分析extern "C"一般的使用技巧:ﻫextern "C"的常使 用方法1)在C++中引用C语言中的函数和变量,在包括C语言头文献(假设为cExample.h)时,需进行下列处理: ext ern "C"ﻫ{ #i nclude "cExample.h"ﻫ}而在C语言的头文献中,对其外部函数只能指定为extern类型,C语言中不支持extern "C"申明,在.c文献中包括了extern "C"时会出现编译语法错误。ﻫC++引用C函数例子工程中包括的三个文献的源代码如 下: /* c语言头文献:cExample.h */ﻫ#ifndef C_EXAMPLE_H #define C_EXAMPLE_Hﻫextern int add(int x,int y); #endifﻫ/* c语言实现文献:cExample.c */ﻫ#i nclude "cExample.h" int add( int x, int y ) {ﻫreturn x + y;ﻫ}ﻫ// c++实现文献,调用add:cppFile.cppﻫextern "C" {#i nclude "cExample.h"ﻫ} int main(int argc, char* argv[]) {add(2,3);ﻫreturn 0;ﻫ}假如C++调用一个C语言编写的.DLL时,当包括.DLL的头文献或申明接口函数时,应加 extern "C" { }。 (2)在C中引用C++语言中的函数和变量时,C++的头文献需添加extern "C",不过在C语言中不能直接引用申明了 extern "C"的该头文献,应当仅将C文献中将C++中定义的extern "C"函数申明为extern类型。 C引用C++函数例子工程中包括的三个文献的源代码如下:ﻫ//C++头文献 cppExample.h #ifndef CPP_EXAMPLE_H #define CPP_EXAMPLE_Hﻫextern "C" int add( int x, int y ); #endifﻫ//C++实现文献 cppExample.cppﻫ#i nclude "cppExample.h"ﻫint add( int x, int y ) { return x + y; } /* C实现文献 cFile.cﻫ/* 这么会编译犯错:#i nclude "cExample.h" */ int main( int argc, char* argv[] ) { add( 2, 3 );ﻫreturn 0;ﻫ}15题目标解答请参考《C++中extern “C”含义深层探索》注解: 几道c笔试题(含参考答案) 1. What is displayed when f() is called given the code:ﻫclass Number {ﻫpublic:ﻫstring type; ﻫN umber(): type(“void”) { }ﻫexplicit Number(short) : type(“short”) { } ﻫNumber(int) : type(“int”) { }ﻫ};ﻫvoid Show(const Number& n) { cout << e; } void f()ﻫ{ short s = 42;ﻫShow(s); }ﻫa) void b) short c) int d) None of the above选C; 虽然传入的是short类型,不过short类型的结构函数被生命被explicit,也就是只能显示类型转换,不能使用隐式类型转换 ﻫ2. Which is the correct output for the following code double dArray[2] = {4, 8}, *p, *q;ﻫp = &dArray[0]; q = p + 1; cout << q – p << endl; cout << (int)q - (int)p << endl;ﻫa) 1 and 8 b) 8 and 4 c) 4 and 8 d) 8 and 1。第二个选A; 第一个是指针加减,按照的是指向地址类型的加减,只跟类型位置有关,q和p指向的数据类型以实际数据类型来算差一个位 置,因此是1。而第二个加减是实际指针值得加减,在内存中一个double类型占据8个字节,因此是8 54.Sony笔试题 1.完成下列程序 * .*.* ﻫ *..*..*.. ..*..*.*.....*.. ﻫ ...**.....*...*......*... *.*.....*.........*.....*.....*..... ﻫ ..*......*.*......*.........*.....*...*.......... ﻫ *.......*.......*.......*.......*.......*.......*.......*....... #include<iostream> using namespace std; #define N 8 int main() { ﻩint i,j,k; for(i=0;i<N;i++) ﻩ{ for(j=0;j<=i;j++) ﻩ{ ﻩﻩ cout"*"<<; ﻩ for(k=0;k<i;k++) cout<<"."; ﻩﻩ} ﻩcout< } return 0; } 2.完成程序,实现对数组的降序排序 ﻫ #include ﻫ void sort( ); ﻫ int main() { ﻫ int array[]={45,56,76,234,1,34,23,2,3}; //数字任//意给出 sort( ); ﻫ return 0; } void sort( ) { ____________________________________ | | | | ﻫ |---------------------------------------------------|-- ﻫ } ﻫ 3,5……编写程序求第十项。能够用递归,也能够用其 ﻫ他措施,但要阐明你选择的理由。 #include<iostream> using namespace std; 3.费波那其数列,1,1,2, int Pheponatch(int); int main() { ﻩcout<<"The 10th is "< return 0; } int Pheponatch(int i) {if(i==1||i==2) ﻩreturn 1; ﻩelse ﻩreturn Pheponatch(i-1)+Pheponatch(i-2); } 4.下列程序运行时会瓦解,请找犯错误并更正,并且阐明原因。 ﻫ #include<iostream> ﻫ > typedef struct{ ﻫ TNode* left; ﻫ TNode* right; int value; ﻫ } TNode; TNode* root=NULL; ﻫ void append(int N); int main() ﻫ { append(63); append(45); ﻫ append(32); ﻫ append(77); ﻫ append(96); append(21); ﻫ append(17); // Again, 数字任意给出 ﻫ } ﻫ void append(int TNode* NewNode=(TNode *)malloc(sizeof(TNode)); NewNode->value=N; ﻫ if(root==NULL) #include N) ﻫ { { root=NewNode; return; ﻫ } else { ﻫ TNode* temp; temp=root; ﻫ while((N>=temp.value && temp.left!=NULL) || (N !=NULL)) ﻫ { ﻫ while (N>=temp.value && temp.left!=NULL) ﻫ temp=temp.left; while(N temp=temp.right; ﻫ } ﻫ if(N>=temp.value) ﻫ temp.left=NewNode; else temp.right=NewNode; ﻫ return; } } 55请你分别画出OSI的七层网络结构图和TCP/IP的五层结构图。 应用层:为应用程序提供服务 表示层:处理在两个通信系统中互换信息的表示方式 会话层:负责维护两个结点间会话连接的建立、管理和终止,以及数据互换 传输层:向用户提供可靠的端到端服务。UDP TCP协议。 网络层:通过路由选择算法为分组通过通信子网选择最适当的途径,以及实现拥塞控制、网络互联等功效。数据传输单元是 分组。IP地址,路由器,IP协议。 数据链路层:在物理层提供的服务基础上,数据链路层在通信的实体间建立数据链路连接,传输一帧为单位的数据包(,并采取 差错控制与流量控制措施,使有差错的物理线路变成无差错的数据链路。) 物理层:传输比特流。传输单元是比特。调制解调器。 56请你详细地解释一下IP协议的定义,在哪个层上面?重要有什么作用?TCP与UDP呢 ? 网络层。 57.请问互换机和路由器各自的实现原理是什么?分别在哪个层次上面实现的? 互换机:数据链路层。路由器:网络层。 58.全局变量和局部变量有什么区分?是怎么实现的?操作系统和编译器是怎么懂得的 ? 59.8086是多少位的系统?在数据总线上是怎么实现的? 8086微处理器共有4个16位的段存储器,在寻址内存单元时,用它们直接或间接地存储段地址。 代码段存储器CS:存储目前执行的程序的段地址。 数据段存储器DS:存储目前执行的程序所用操作数的段地址。 堆栈段存储器SS:存储目前执行的程序所用堆栈的段地址。 附加段存储器ES:存储目前执行程序中一个辅助数据段的段地址。 由cs:ip组成指令地址,ss:sp组成堆栈的栈顶地址指针。DS和ES用作数据段和附加段的段地址(段起始地址或段值) 8086/8088微处理器的存储器管理 1.地址线(码)与寻址范围:N条地址线 寻址范围=2N 2.8086有20地址线 寻址范围为1MB 由 00000H~FFFFFH 3. 8086微处理器是一个16位结构,用户可用的存储器均为16位:寻址64KB 4. 8086/8088采取分段的措施对存储器进行管理。详细做法是:把1MB的存储器空间提成若干段,每段容量为64KB, 每段存储器的起始地址必须是一个能被16整除的地址码,即在20位的二进制地址码中最低4位必须是“0”。每个段首地址 的高16位二进制代码就是该段的段号(称段基地址)或简称段地址,段号保存在段存储器中。我们可对段存储器设置不一样 的值来使微处理器的存储器访问指向不一样的段。 5.段内的某个存储单元相对于该段段首地址的差值,称为段内偏移地址(也叫偏移量)用16位二进制代码表示。 6.物理地址是由8086/8088芯片地址引线送出的20位地址码,它用来参加存储器的地址译码,最后读/写所访问的一个 特定的存储单元。 7.逻辑地址由某段的段地址和段内偏移地址(也叫偏移量)两部分所组成。写成: 段地址:偏移地址(例如,1234H:0088H)。 8.在硬件上起作用的是物理地址,物理地址=段基地址×10H十偏移地址 联想笔试题 ﻫ 1.设计函数 int atoi(char *s)。 int atoi(const char *s)ﻫ{ if(!str) return INF; char c; int i = 0; bool isMinus = false; c=*s; if(c = '-') { isMinus = true;s++;} while(c=*p++)ﻫ { if(c>='0' && c<='9')ﻫ i = i*10 + (c-'0'); else return INF; //Invalid stringﻫ } if(isMinus) i = -i;ﻫ return i; } 2.int i=(j=4,k=8,l=16,m=32); printf(“%d”, i); 输出是多少?32 ﻫ走人(重要考business 式)。 letter格 大唐面试试题 1.什么是中断?中断发生时CPU做什么工作? 2.CPU在上电后,进入操作系统的main()之前必须做 什么工作? 3.简述ISO OSI的物理层Layer1,链路层Layer2,网络层Layer3的任务。 4.有线电话和无线电话有何区分? 无线电话尤其需要注意的是什么? 5软件开发五个重要step是什么? 6.你在开发软件的时候,这5个step分别占用的时 间百分比是多少? 7.makefile文献的作用是什么? 8.UNIX显示文献夹中,文献名的命令是什么?能使文献内容显示在屏幕 的命令是什么 ? 9.(选做)手机用户在从一个基站漫游到另一个基站的过程中,都会发生什么? 简答题(每题10分) 1.简述一般电话与IP电话的区分。 2.简述随路信令与公路信令的根本区分。 3.阐明掩 码的重要作用。 4.ss7协议中,有三大要素决定其详细定位,哪三大要素? 5.描述ss7的基本通话过程。 6.简述通信 网的组成结构。 7.面对连接与面对非连接各有何利弊? 8.写出爱尔兰的基本计算公式。 9.数据网重要有哪些设备? 10. 中国一号协议是怎样在被叫号码中插入主叫号码的? ﻫ东信笔试:30分钟。 1.压控振荡器的英文缩写。 2.动态随机 存储器的英文缩写。 3.选择电阻时要考虑什么? 4.单片机上电后没有运转,首先要检查什么? 5.计算机的基本组成部分及 其各自的作用。 6.怎样用D触发器、与或非门组成二分频电路? tic有什么用途?(请最少阐明两种) 答 、1.限制变量的作用域(文献级的)。2.设置变量的存储域(全局数据区)。 66.描述实时系统的基本特性?答:在特定期间内完成特定的任务,实时性与可靠性。 67.全局变量和局部变量在内存中是否有区分?假如有,是什么区分?答 、全局变量储存在静态数据区,局部变量在堆栈 中。 68.什么是平衡二叉树?答 、左右子树都是平衡二叉树 且左右子树的深度差值的绝对值小于1。 69.堆栈溢出一般是由什么原因导致的?答:1.没有回收垃圾资源 2.层次太深的递归调用 70.什么函数不能申明为虚函数?答 :constructorDeconstructor 能够申明为虚函数。 ﻩ系统为一个空类创建的组员函数有那些。 默认结构函数 析构函数 拷贝结构函数 赋值运算符(operator=) 取址运算符(operator&)(一对,一个非const的,一 个const的) 当然,所有这些只有当被需要才会产生。例如你定义了一个类,但从来定义过该类的对象,也没使用过该类型的函 数参数,那么基本啥也不会产生。在例如你从来没有进行过该类型对象之间的赋值,那么operator=不会被产生。 71.冒泡排序算法的时间复杂度是什么?答 :O(n^2) 72.写出float x 与“零值”比较的if语句。答 、if(x>0.000001&&x<-0.000001) ternet采取哪种网络协议?该协议的重要层次结构?答:tcp/ip 应用层/传输层/网络层/数据链路层/物理层 7rnet物理地址和IP地址转换采取什么协议?答 、ARP (Address Resolution Protocol)(地址解析协议) 75.IP地址的编码分为哪俩部分? 答 、IP地址由两部分组成,网络号和主机号。不过是要和“子网掩码”按位与之后才能辨别哪些是网络位哪些是主机位。 76.用户输入M,N值,从1至N开始次序循环数数,每数到M输出该数值,直至所有输出。写出C程序。 答:循环链表,用取余操作做 77.不能做switch()的参数类型是:答:switch的参数不能为实型。 78.局部变量能否和全局变量重名?答:能,局部会屏蔽全局。要用全局变量,需要使用"::" 局部变量能够与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器 而言,在同一个函数内能够定义多个同名的局部变量,例如在两个循环体内都定义一个同名的局部变量,而那个局部变量的 作用域就在那个循环体内 79.怎样引用一个已经定义过的全局变量?答:能够用引用头文献的方式,也能够用extern核心字,假如用引用头文献方式来引 用某个在头文献中申明的全局变理,假定你将那个变量写错了,那么在编译期间会报错,假如你用extern方式引用时,假定 你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错 80.全局变量可不能够定义在可被多个.C文献包括的头文献中?为何?答:能够,在不一样的C文献中以static形式来申明 同名全局变量。能够在不一样的C文献中申明同名的全局变量,前提是其中只能有一个C文献中对此变量赋初值,此时连接 不会犯错 81.语句for( ;1 ;)有什么问题?它是什么意思?答:和while(1)相同。 82.do……while和while……do有什么区分?答:前一个循环一遍再判断,后一个判断以后再循环 83.请写出下列代码的输出内容 答:10,12,120 #i nclude int main() {int a,b,c,d; a=10; b=a++; c=++a; d=10*a++; printf("b,c,d:%d,%d,%d",b,c,d); return 0; } tac 全局变量、局部变量、函数与一般全局变量、局部变量、函数:static全局变量与一般的全局变量有什么区 分?static局部变量和一般局部变量有什么区分?static函数与一般函数有什么区分? 答 、全局变量(外部变量)的阐明之前再冠以static 就组成了静态的全局变量。全局变量自身就是静态存储方式, 静态全局 变量当然也是静态存储方式。 这二者在存储方式上并无不一样。这二者的区分虽在于非静态全局变量的作用域是整个源程 序, 当一个源程序由多个源文献组成时,非静态的全局变量在各个源文献中都是有效的。 而静态全局变量则限制了其作用 域, 即只在定义该变量的源文献内有效, 在同一源程序的其他源文献中不能使用它。因为静态全局变量的作用域局限于一 个源文献内,只能为该源文献内的函数公用, 因此能够防止在其他源文献中引起错误。 从以上分析能够看出, 把局部变量变化为静态变量后是变化了它的存储方式即变化了它的生存期。把全局变量变化为静态变 量后是变化了它的作用域, 限制了它的使用范围。 static函数与一般函数作用域不一样。仅在本文献。只在目前源文献中使用的函数应当阐明为内部函数(static),内部函数应 当在目前源文献中阐明和定义。对于可在目前源文献以外使用的函数,应当在一个头文献中阐明,要使用这些函数的源文献要 包括这个头文献 static全局变量与一般的全局变量有什么区分:static全局变量只初使化一次,预防在其他文献单元中被引用; static局部变量和一般局部变量有什么区分:static局部变量只被初始化一次,下一次依据上一次成果值; static函数与一般函数有什么区分:static函数在内存中只有一份,一般函数在每个被调用中维持一份拷贝 程序的局部变量存在于(堆栈)中,全局变量存在于(静态区 )中,动态申请数据存在于( 堆)中。 85.设有如下阐明和定义: typedef union {long i; int k[5]; char c;} DATE; struct data { int cat; DATE cow; double dog;} too; DATE max; 则语句 printf("%d",sizeof(struct date)+sizeof(max));的执行成果是? 答 、成果是:___52____。DATE是一个union, 变量公用空间. 里面最大的变量类型是int[5], 占用20个字节. 因此 它的大小是20。data是一个struct, 每个变量分开占用空间. 依次为int4 + DATE20 + double8 = 32. 因此成果是 20 + 32 = 52. 当然...在某些16位编辑器下, int也许是2字节,那么成果是 int2 + DATE10 + double8 = 20 86.-1,2,7,28,,126请问28和126中间那个数是什么?为何?答 、应当是4^3-1=63规律是n^3-1(当n为偶数0, 2,4) n^3+1(当n为奇数1,3,5) 87.用两个栈实现一个队列的功效?要求给出算法和思绪! 答 、设2个栈为A,B, 一开始均为空. 入队:将新元素push入栈A; 出队: (1)判断栈B是否为空; (2)假如不为空,则将栈A中所有元素依次pop出并push到栈B; (3)将栈B的栈顶元素pop出; 这么实现的队列入队和出队的平摊复杂度都还是O(1), 比上面的几个措施要好。 88.在c语言库函数中将一个字符转换成整型的函数是atool()吗,这个函数的原型是什么? 答:函数名: atol 功 能: 把字符串转换成长整型数 用 法: long atol(const char *nptr); 程序例: #include #include int main(void) { long l; char *str = "98765432"; l = atol(lstr); printf("string = %s integer = %ld\n", str, l); } 89.对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现?答 、c用宏定义,c++用inline 90.用预处理指令#define 申明一个常数,用以表白1年中有多少秒(忽视闰年问题) #define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL 我在这想看到几件事情: 1). #define 语法的基本知识(例如:不能以分号结束,括号的使用,等等) 2). 懂得预处理器将为你计算常数体现式的值,因此,直接写出你是怎样计算一年中有多少秒而不是计算出实际的值,是更清 楚而没有代价的。 3). 意识到这个体现式将使一个16位机的整型数溢出-因此要用到长整型符号L,告诉编译器这个常数是的长整型数。 4). 假如你在你的体现式中用到UL(表示无符号长整型),那么你有了一个好的起点。记住,第一印象很重要。 91.写一个“标准”宏MIN,这个宏输入两个参数并返回较小的一个。 #define MIN(A,B) ((A) <= (B) (A) : (B)) 这个测试是为下面的目标而设的: return(0); 1). 标识#define在宏中应用的基本知识。这是很重要的,因为直到嵌入(inline)操作符变为标准C的一部分,宏是以便 产生嵌入代码的唯一措施,对于嵌入式系统来说,为了能达成要求的性能,嵌入代码常常是必须的措施。 2). 三重条件操作符的知识。这个操作符存在C语言中的原因是它使得编译器能产生比if-then-else更优化的代码,了解这 个使用方法是很重要的。 3). 懂得在宏中小心地把参数用括号括起来 4). 我也用这个问题开始讨论宏的副作用,例如:当你写下面的代码时会发生什么事? least = MIN(*p++, b); 92.预处理器标识#error的目标是什么? 假如你不懂得答案,请看参考文献1。这问题对辨别一个正常的伙计和一个书呆子是很有用的。只有书呆子才会读C语言课 本的附录去找出象这种问题的答案。当然假如你不是在找一个书呆子,那么应试者最佳希望自己不要懂得答案。 死循环(Infinite loops) 93.嵌入式系统中常常要用到无限循环,你怎么样用C编写死循环呢? 这个问题用几个处理方案。我首选的方案是: while(1) { } 某些程序员更喜欢如下方案: for(;1;) { } 这个实现方式让我为难,因为这个语法没有确切体现到底怎么回事。假如一个应试者给出这个作为方案,我将用这个作为一个 机会去探究他们这么做的 基本原理。假如他们的基本答案是:“我被教着这么做,但从没有想到过为何。”这会给我留下一个坏印象。 第三个方案是用 goto Loop: ... goto Loop; 应试者如给出上面的方案,这阐明或者他是一个汇编语言程序员(这也许是好事)或者他是一个想进入新领域的BASIC/ FORTRAN程序员。 数据申明(Data declarations) 94.用变量a给出下面的定义 a) 一个整型数(An integer) b) 一个指向整型数的指针(A pointer to an integer) c) 一个指向指针的的指针,它指向的指针是指向一个整型数(A pointer to a pointer to an integer) d) 一个有10个整型数的数组(An array of 10 integers) e) 一个有10个指针的数组,该指针是指向一个整型数的(An array of 10 pointers to integers) f) 一个指向有10个整型数数组的指针(A pointer to an array of 10 integers) g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a function that takes an int eger as an argument and returns an integer) h) 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数( An array of ten po inters to functions that take an integer argument and return an integer ) 答案是: a) int a; // An integer b) int *a; // A pointer to an integer c) int **a; // A pointer to a pointer to an integer d) int a[10]; // An array of 10 integers e) int *a[10]; // An array of 10 pointers to integers f) int (*a)[10]; // A pointer to an array of 10 integers g) int (*a)(int); // A pointer to a function a that takes an integer argument and re turns an integer h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer Static95.核心字static的作用是什么? 在C语言中,核心字static有三个明显的作用: 1). 在函数体,一个被申明为静态的变量在这一函数被调用过程中维持其值不变。 2). 在模块内(但在函数体外),一个被申明为静态的变量能够被模块内所用函数访问,但不能被模块外其他函数访问。它 是一个本地的全局变量。 3). 在模块内,一个被申明为静态的函数只可被这一模块内的其他函数调用。那就是,这个函数被限制在申明它的模块的 本地范围内使用。 Const96.核心字const是什么含意? 我只要一听到被面试者说:“const意味着常数”,我就懂得我正在和一个业余者打交道。去年Dan Saks已经在他的文章里 完全概括了const的所有使用方法,因此ESP(译者:Embedded Systems Programming)的每一位读者应当非常熟悉c onst能做什么和不能做什么.假如你从没有读到那篇文章,只要能说出const意味着“只读”就能够了。尽管这个答案不是 完全的答案,但我接收它作为一个正确的答案。(假如你想懂得更详细的答案,仔细读一下Saks的文章吧。)假如应试者能 正确回答这个问题,我将问他一个附加的问题:下面的申明都是什么意思? const int a; int const a; const int *a; int * const a; int const * a const; 前两个的作用是同样,a是一个常整型数。第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但 指针能够)。第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是能够修改的,但指针是不可修改 的)。最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改 的)。假如应试者能正确回答这些问题,那么他就给我留下了一个好印象。顺带提一句,也许你也许会问,虽然不用核心字 const,也还是能很轻易写出功效正确的程序,那么我为何还要如此看重核心字const呢?我也如下的几下理由: 1). 核心字const的作用是为给读你代码的人传达非常有用的信息,实际上,申明一个参数为常量是为了告诉了用户这个参 数的应用目标。假如你曾花诸多时间清理其他人留下的垃圾,你就会很快学会感激这点多出的信息。(当然,懂得用const的 程序员极少会留下的垃圾让他人来清理的。) 2). 通过给优化器某些附加的信息,使用核心字const也许能产生更紧凑的代码。 3). 合理地使用核心字const能够使编译器很自然地保护那些不希望被变化的参数,预防其被无意的代码修改。简而言 之,这么能够减少bug的出现。 Volatile97.核心字volatile有什么含意 并给出三个不一样的例子。 一个定义为volatile的变量是说这变量也许会被意想不到地变化,这么,编译器就不会去假设这个变量的值了。精准地说就是, 优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在存储器里的备份。下面是volatile变 量的几个例子: 1). 并行设备的硬件存储器(如:状态存储器) 2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables) 3). 多线程应用中被几个任务共享的变量 回答不出这个问题的人是不会被雇佣的。我以为这是辨别C程序员和嵌入式系统程序员的最基本的问题。嵌入式系统程序员 常常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。 假设被面试者正确地回答了这是问题(嗯,怀疑这否会是这么),我将稍微深究一下,看一下这家伙是不是直正懂得volatil e完全的重要性。 1). 一个参数既能够是const还能够是volatile吗?解释为何。 2). 一个指针能够是volatile 吗?解释为何。 3). 下面的函数有什么错误: int square(volatile int *ptr) { return *ptr * *ptr; } 下面是答案: 1). 是的。一个例子是只读的状态存储器。它是volatile因为它也许被意想不到地变化。它是const因为程序不应当试 图去修改它。 2). 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。 3). 这段代码的有个恶作剧。这段代码的目标是用来返指针*ptr指向值的平方,不过,因为*ptr指向一个volatile型参 数,编译器将产生类似下面的代码: int square(volatile int *ptr) { int a,b; a = *ptr; b = *ptr; return a * b; } 因为*ptr的值也许被意想不到地该变,因此a和b也许是不一样的。成果,这段代码也许返不是你所期望的平方值!正确的 代码如下: long square(volatile int *ptr) { int a; a = *ptr; return a * a; } 位操作(Bit manipulation)98.下面的代码输出是什么,为何? void foo(void) { unsigned int a = 6; int b = -20; (a+b > 6) puts("> 6") : puts("<= 6"); } 这个问题测试你是否懂得C语言中的整数自动转换标准,我发觉有些开发者懂得极少这些东西。无论怎样,这无符号整型问题 的答案是输出是“>6”。原因是当体现式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型。因此- 20变成了一个非常大的正整数,因此该体现式计算出的成果不小于6。这一点对于应当频繁用到无符号数据类型的嵌入式 系统来说是丰常重要的。假如你答错了这个问题,你也就到了得不到这份工作的边缘。 99.C语言同意某些令人震惊的结构,下面的结构是合法的吗,假如是它做些什么? int a = 5, b = 7, c; c = a+++b; 这个问题将做为这个测验的一个愉快的结尾。无论你相不相信,上面的例子是完全合乎语法的。问题是编译器怎样处理它? 水平不高的编译作者实际上会争论这个问题,依照最处理标准,编译器应当能处理尽也许所有合法的使用方法。因此,上面 的代码被处理成: c = a++ + b; 因此, 这段代码持行后a = 6, b = 7, c = 12。 假如你懂得答案,或猜出正确答案,做得好。假如你不懂得答案,我也不把这个当作问题。我发觉这个问题的最大好处是:这是 一个有关代码编写格调,代码的可读性,代码的可修改性的好的话题, 100.线形表a、b为两个有序升序的线形表,编写一程序,使两个有序线形表合并成一个有序升序线形表h; 答案在 请化大学 严锐敏《数据结构第二版》第二章例题,数据结构当中,这个叫做:两路归并排序 Linklist *unio(Linklist *p,Linklist *q){ linklist *R,*pa,*qa,*ra; pa=p; qa=q; R=ra=p; while(pa->next!=NULL&&qa->next!=NULL){ if(pa->data>qa->data){ ra->next=qa; qa=qa->next; } else{ ra->next=pa; pa=pa->next; } } if(pa->next!=NULL) ra->next=pa; if(qa->next!=NULL) ra->next==qa; return R; } 101.用递归算法判断数组a[N]是否为一个递增数组。 递归的措施,统计目前最大的,并且判断目前的是否比这个还大,大则继续,否则返回false结束: bool fun( int a[], int n ) { if( n= =1 ) return true; if( n= =2 ) return a[n-1] >= a[n-2]; return fun( a,n-1) && ( a[n-1] >= a[n-2] ); } 102.编写算法,从10亿个浮点数当中,选出其中最大的10000个。 用外部排序,在《数据结构》书上有《计算措施导论》在找到第n大的数的算法上加工 103.编写一unix程序,预防僵尸进程的出现. 同学的4道面试题,应聘的职位是搜索引擎工程师,后两道超级难,(希望大家多给某些算发) 1.给两个数组和他们的大小,尚有一动态开辟的内存,求交集,把交集放到动态内存dongtai,并且返回交集个数 long jiaoji(long* a[],long b[],long* alength,long blength,long* dongtai[]) 2.单连表的建立,把'a'--'z'26个字母插入到连表中,并且倒叙,还要打印! 措施1: typedef struct val { int date_1; struct val *next; }*p; void main(void) { char c; for(c=122;c>=97;c--) { p.date=c; p=p->next; } p.next=NULL; } } 措施2: node *p = NULL; node *q = NULL; node *head = (node*)malloc(sizeof(node)); head->data = ' ';head->next=NULL; node *first = (node*)malloc(sizeof(node)); first->data = 'a';first->next=NULL;head->next p = first; int longth = 'z' - 'b'; int i=0; while ( i<=longth ) = first; { node *temp = (node*)malloc(sizeof(node)); temp->data = 'b'+i;temp->next=NULL;q=temp; head->next = temp; temp->next=p;p=q; i++; } print(head); 104.可怕的题目终于来了 象搜索的输入信息是一个字符串,统计300万输入信息中的最热门的前十条,我们每次输入的一个字符串为不超出255by te,内存使用只有1G, 请描述思想,写出算发(c语言),空间和时间复杂度, 7.国内的某些帖吧,如百度,有几十万个主题,假设每一个主题都有上亿的跟帖子,怎么样设计这个系统速度最佳,请描述思 想,写出算发(c语言),空间和时间复杂度, #include string.h main(void) { char *src="hello,world"; char *dest=NULL; dest=(char *)malloc(strlen(src)); int len=strlen(str); char *d=dest; char *s=src[len]; while(len--!=0) d++=s--; printf("%s",dest); } 找犯错误!! #include "string.h" #include "stdio.h" #include "malloc.h" main(void) { char *src="hello,world"; char *dest=NULL; dest=(char *)malloc(sizeof(char)*(strlen(src)+1)); int len=strlen(src); char *d=dest; char *s=src+len-1; while(len--!=0) *d++=*s--; *d='0'; printf("%s",dest); } 105.判断字符串是否为回文 bool IsSymmetry(const char* p) ﻩ{ ﻩﻩassert(p!=NULL;) ﻩconst char* q=p;ﻩﻩ int len=0; ﻩwhile(*q++!='0') ﻩ{ ﻩlen++; } ﻩﻩbool bSign=true; q=p+len-1; ﻩ ﻩ if (0<len) { ﻩfor (int i=0;i ﻩ{ ﻩﻩ ﻩ ﻩﻩ} ﻩif(bSign==true) { ﻩ ﻩ} ﻩﻩelse { ﻩprintf("No!n"); ﻩ} printf("Yes!n"); ﻩ} if(*p++!=*q--){ bSign=false;break;}; ﻩﻩreturn bSign; } 107.ASDL使用的是什么协议?并进行简单描述? 109.什么是预编译,何时需要预编译? 预编译又称为预处理,是做些代码文本的替代工作。处理#开头的指令,例如拷贝#include包括的文献代码,#define宏定 义的替代,条件编译等,就是为编译做的预备工作的阶段,重要处理#开始的预编译指令,预编译指令指示了在程序正式编译前 就由编译器进行的操作,能够放在程序中的任何位置。 c编译系统在对程序进行一般的编译之前,先进行预处理。c提供的预处理功效重要有如下三种:1)宏定义 2)文献包括 3)条件编译 1、总是使用不常常改动的大型代码体。 ﻫ2、程序由多个模块组成,所有模块都使用一组标准的包括文献和相同的编译选 项。在这种情况下,能够将所有包括文献预编译为一个预编译头。 110.进程和线程的区分 什么是进程(Process):一般的解释就是,进程是程序的一次执行,而什么是线程(Thread),线程能够了解为进程中的执行的 一段程序片段。在一个多任务环境中下面的概念能够协助我们了解二者间的差异: ﻫ进程间是独立的,这表目前内存空间,上 下文环境;线程运行在进程空间内。 一般来讲(不使用特殊技术)进程是无法突破进程边界存取其他进程内的存储空间;而 线程因为处在进程空间内,因此同一进程所产生的线程共享同一内存空间。 同一进程中的两段代码不能够同时执行,除非 引入线程。线程是属于进程的,当进程退出时该进程所产生的线程都会被强制退出并清除。线程占用的资源要少于进程所占 用的资源。 进程和线程都能够有优先级。在线程系统中进程也是一个线程。能够将进程了解为一个程序的第一个线程。 线程是指进程内的一个执行单元,也是进程内的可调度实体.与进程的区分: (1)地址空间:进程内的一个执行单元;进程最少有一个线程;它们共享进程的地址空间;而进程有自己独立的地址空间;ﻫ(2)进 程是资源分派和拥有的单位,同一个进程内的线程共享进程的资源ﻫ(3)线程是处理器调度的基本单位,但进程不是.ﻫ(4)二者均 可并发执行. 111.插入排序和选择排序 插入排序基本思想:(假定从大到小排序)依次从背面拿一个数和前面已经排好序的数进行比较,比较的过程是从已经排好序的 数中最后一个数开始比较,假如比这个数大,继续往前面比较,直到找到比它大的数,然后就放在它的背面,假如一直没有 找到,肯定这个数已经比较到了第一个数,那就放到第一个数的前面。那么一般情况下,对于采取插入排序法去排序的一组 数,能够先选 取第一个数做为已经排好序的一组数。然后把第二个放到正确位置。 选择排序(Selection Sort)是一个简单直观的排序算法。它的工作原理如下。首先在未排序序列中找到最小元素,存储到 排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,然后放到排序序列末尾。以此类推,直到所有元素均排 序完成。 112.运算符优先级问题 能正确表示a和b同时为正或同时为负的逻辑体现式是(D )。 A、(a>=0||b>=0)&&(a<0||b<0) B、(a>=0&&b>=0)&&(a<0&&b<0) C、(a+b>0)&&(a+b<=0) D、a*b>0 如下有关运算符优先次序的描述中正确的是(C)。 A、关系运算符<算术运算符<赋值运算符<逻辑与运算符 ﻫB、逻辑与运算符<关系运算符<算术运算符<赋值运算符 ﻫC、 赋值运算符<逻辑与运算符<关系运算符<算术运算符 D、算术运算符<关系运算符<赋值运算符<逻辑与运算符 113.字符串倒序 写一个函数将"tom is cat" 倒序打印出来,即 "cat is tom" //a.ch #define SPACE ' 'ﻫ#define ENDL '0'ﻫchar* str = "Tom is cat"; // 字符串ﻫchar* p1 = str+strle n(str)-1; char* p2 = p1; // 开始时,p1,p2都指向字符串结尾处ﻫchar t=0; // 暂时变量,用来保存被暂时替代为ENDL的 字符 while(str!=p1--) {ﻫ if(SPACE!=*p1){ﻫ for(p2=p1+1;SPACE!=*p1; p1--, t=*p2, *p2=ENDL;) // p1+1指向单词的第一个字母,p2指向单词的结尾,此时输出这个单词ﻫ printf("%s ",p1+1);ﻫ * p2=t; p2=p1;ﻫ } } Output: cat is Tom 1)写一个递归函数将内存中的字符串翻转"abc"->"cba"ﻫ2)写一个函数将"tom is cat" 将内存中的字符串翻转,即 "c at is tomm" #include <stdio.h> #define SPACE ' ' #define ENDL '0'ﻫchar* s = "The quick brown fox jumps over the lazy dog"; void str_reverse(char* p1,char* p2){ if(p1==p2)return;ﻫ *p1 = (*p1)+(*p2);ﻫ *p2 = (*p1)-(*p2);ﻫ *p1 = (*p1)-(*p2); if(p1==p2-1)return;ﻫ else str_reverse(++p1,--p2); } void str_word_reverse(char* str){ char *q1=str, *q2=str, *t; while(*q1==SPACE)q1++; if(*q1==ENDL)return; //! else q2=q1+1; while( (*q2!=SPACE) && (*q2!=ENDL) )q2++; ﻫ t=q2--; str_reverse(q1,q2); if(*t==ENDL)return;ﻫ else str_word_reverse(t); } int main(int a ,char** b) {ﻫ printf("%s\n",s);ﻫ str_reverse(s,s+strlen(s)-1;)ﻫ printf("%s\n",s;)ﻫ str_word_reverse(s); printf("%sn",s);ﻫ return 0; } Output: The quick brown fox jumps over the lazy dog god yzal eht revo spmuj xof nworb kciuq ehTﻫdog lazy the over jumps fox brown quick The 写一个递归函数将内存中的字符串翻转"abc"->"cba",并且函数原型已确定:void reverse(char* p)其实,要求越多, 思绪越确定,我的解如下: #include char* s = "";ﻫ#define ENDL '0' void reverse(char* p){ﻫ //这是这种措施的核心,使用static为的是能用str_reverse的思绪,不过不好ﻫ s tatic char* x=0; if(x==0)x=p;ﻫ char* q = x+strlen(p)-1; ﻫ if(p==q)return;ﻫ *q=(*p)^(*q); *p=(*p)^(*q);ﻫ *q =(*p)^(*q); if(q==p+1)return; reverse(++p);ﻫ} //这种措施就直观多了,不过当字符串很长的时候就很低效 void reverse2(char* p){ if(*(p+1)==ENDL)return;ﻫ for(char* o=p+strlen(p)-1,char t=*o;o!=p;o--)ﻫ *o=* (o-1);ﻫ *p=t;ﻫ reverse2(p+1); } int main(int c,char** argv){ reverse2(s);ﻫ printf("%s\n",s);ﻫ return 0;ﻫ} 114.互换两个数的宏定义 互换两个参数值的宏定义为:. #define SWAP(a,b) (a)=(a)+(b);(b)=(a)-(b);(a)=(a)-(b); 115.Itearator和指针的区分 游标和指针 我说过游标是指针,但不但仅是指针。游标和指针很像,功效很像指针,不过实际上,游标是通过重载一元的”*”和”->”来从容 器中间接地返回一个值。将这些值存储在容器中并不是一个好主意,因为每当一个新值添加到容器中或者有一个值从容器中 删除,这些值就会失效。在某种程度上,游标能够看作是句柄(handle)。一般情况下游标(iterator)的类型能够有所变化, 这么容器也会有几个不一样方式的转变: iterator——对于除了vector以外的其他任何容器,你能够通过这种游标在一次操作中在容器中朝向前的方向走一步。这 意味着对于这种游标你只能使用“++”操作符。而不能使用“--”或“+=”操作符。而对于vector这一个容器,你能够使用 “+=”、“—”、“++”、“-=”中的任何一个操作符和“<”、“<=”、“>”、“>=”、“==”、“!=”等比较运算符。 116. C++中的class和struct的区分 从语法上,在C++中(只讨论C++中)。class和struct做类型定义时只有两点区分:ﻫ(一)默认继承权限。假如不明确指 定,来自class的继承按照private继承处理,来自struct的继承按照public继承处理; (二)组员的默认访问权限。class的组员默认是private权限,struct默认是public权限。 除了这两点,class和struct基本就是一个东西。语法上没有任何其他区分。 不能因为学过C就总以为连C++中struct和class都区分很大,下面列举的阐明也许比较无聊,因为struct和class本来就是 基本同样的东西,无需多说。但这些阐明也许有利于澄清某些常见的有关struct和class的错误认识: (1)都能够有组员函数;包括各类结构函数,析构函数,重载的运算符,友元类,友元结构,友元函数,虚函数,纯虚函数,静态 函数;(2)都能够有一大堆public/private/protected修饰符在里边;(3)虽然这种格调不再被倡导,但语法上二者都 能够使用大括号的方式初始化:A a = {1, 2, 3};无论A是个struct还是个class,前提是这个类/结构足够简单,例如所 有的组员都是public的,所有的组员都是简单类型,没有显式申明的结构函数。(4)都能够进行复杂的继承甚至多重继承,一 个struct能够继承自一个class,反之亦可;一个struct能够同时继承5个class和5个struct,虽然这么做不太好。(5)假 如说class的设计需要注意OO的标准和格调,那么没任何理由说设计struct就不需要注意。(6)再次阐明,以上所有说 法都是指在C++语言中,至于在C里的情况,C里是根本没有“class”,而C的struct从根本上也只是个包装数据的语法机 制。 最后,作为语言的两个核心字,除去定义类型时有上述区分之外,另外尚有一点点:“class”这个核心字还用于定义模板参 数,就像“typename”。但核心字“struct”不用于定义模板参数。 有关使用大括号初始化 class和struct假如定义了结构函数的话,都不能用大括号进行初始化 假如没有定义结构函数,struct能够用大括号初始化。 假如没有定义结构函数,且所有组员变量全是public的话,能够用大括号初始化。 有关默认访问权限 class中默认的组员访问权限是private的,而struct中则是public的。 有关继承方式 class继承默认是private继承,而struct继承默认是public继承。 有关模版 在模版中,类型参数前面能够使用class或typename,假如使用struct,则含义不一样,struct背面跟的是 “non-type template parameter”,而class或typename背面跟的是类型参数。 class中有个默认的this指针,struct没有ﻫ不一样点:结构函数,析构函数 this 指针 117.有关重载函数 返回值类型不一样构不成重载 ﻫ参数参数次序不一样能组成重载 c++函数同名不一样返回值不算重载!函数重载是忽视返回值类型的。 组员函数被重载的特性有:1) 相同的范围(在同一个类中);2) 函数名字相同;3) 参数列表不一样;4) virtual核心字可 有可无。 5) 组员函数中 有无const (函数背面) 也可判断是否重载 118.数据库与T-SQL语言?关系数据库是表的集合,它是由一个或多个关系模式定义。SQL语言中的数据定义功效包括 对数据库、基本表、视图、索引的定义。 119.关系模型的基本概念ﻫ关系数据库以关系模型为基础,它有如下三部分组成: ●数据结构——模型所操作的对象、类型的集合 ●完整性规则——确保数据有效、正确的约束条件ﻫ ●数据操作——对模型对象所允许执行的操作方式ﻫ 关系(Re lation)是一个由行和列组成的二维表格,表中的每一行是一条统计(Record),每一列是统计的一个字段(Field)。表 中的每一条统计必须是互斥的,字段的值必须具备原子性。 120.SQL语言概述 SQL(结构化查询语言)是关系数据库语言的一个国际标准,它是一个非过程化的语言。通过编写SQL,我们能够实现对关系 数据库的所有操作。 ●数据定义语言(DDL)——建立和管理数据库对象 ●数据操纵语言(DML)——用来查询与更新数据ﻫ ●数据控制语言(DCL)——控制数据的安全性 事务处理系统的经典特点是具备ACID特性。ACID指的是Atomic(原子的)、Consistent(一致的)、Isolated(隔离 的)以及Durable(连续的),它们代表着事务处理应当具备的四个特性: 原子性:组成事务处理的语句形成了一个逻辑单元,不能只执行其中的一部分 一致性:在事务处理执行之前和之后,数据是一致的。 隔离性:一个事务处理对另一个事务处理没有影响。 连续性:当事务处理成功执行到结束的时候,其效果在数据库中被永久纪录下来。 121.C语言中结构化程序设计的三种基本控制结构 次序结构 选择结构 循环结构 是什么 cvs(Concurrent Version System) 是一个版本控制系统。使用它,能够统计下你的源文献的历史。 例如,修改软件时也许会不知不觉混进某些 bug,并且也许过了很久你才会察觉到它们的存在。有了 cvs,你能够很轻易地恢 复旧版本,并从中看出到底是哪个修改导致了这个 bug。有时这是很有用的。 CVS服务器端对每个文献维护着一个修订号,每次对文献的更新,都会使得文献的修订号加1。在客户端中也对每个文献维 护着一个修订号,CVS通过这两个修订号的关系,来进行Update,Commit和发觉冲突等操作操作 123.三种基本的数据模型 按照数据结构类型的不一样,将数据模型划分为层次模型、网状模型和关系模型。
版权声明:本文标题:2024年大学英语四级高频词汇总结 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://roclinux.cn/p/1735525907a1673895.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论