在模块B 中引用该函数: // 模块B 实现文件 moduleB.cpp #include "moduleA.h" foo(2,3); 实际上,在连接阶段,连接器会从模块A 生成的目标文件moduleA.obj 中寻找_foo_int_int 这样的符号! 加extern "C" 声明后的编译和连接方式 加extern "C" 声明后,模块A 的头文件变为: // 模块A 头文件 moduleA.h #ifndef MODULE_A_H #define MODULE_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 )时,需进行下列处理: extern "C" { #include "cExample.h" } 而在C 语言的头文件中,对其外部函数只能指定为extern 类型,C 语言中不支持extern "C" 声明,在.c 文件中包含了extern "C" 时会出现编译语法错误。 C++ 引用C 函数例子工程中包含的三个文件的源代码如下: #ifndef C_EXAMPLE_H #define C_EXAMPLE_H extern int add(int x,int y); #endif #include "cExample.h" int add( int x, int y ) { return x + y; } // c++ 实现文件,调用add :cppFile.cpp extern "C" { #include "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
经典C/C++ 面试题(一)
作者:123.112.125.*
2009-3-31 22:09 回复此发言
9
回复:经典C/C++ 面试题(一)
extern "C" int add( int x, int y ); #endif //C++实现文件 cppExample.cpp #include "cppExample.h" int add( int x, int y ) { return x + y; } extern int add( int x, int y ); int main( int argc, char* argv[] ) { add( 2, 3 ); return 0; } 15 题目的解答请参考《C++ 中extern “C” 含义深层探索》注解: 16. 关联、聚合(Aggregation) 以及组合(Composition) 的区别? 涉及到UML 中的一些概念:关联是表示两个类的一般性联系,比如“ 学生” 和“ 老师” 就是一种关联关系;聚合表示has-a 的关系,是一种相对松散的关系,聚合类不需要对被聚合类负责,如下图所示,用空的菱形表示聚合关系: 从实现的角度讲,聚合可以表示为: class A {...} class B { A* a; .....} 而组合表示contains-a 的关系,关联性强于聚合:组合类与被组合类有相同的生命周期,组合类要对被组合类负责,采用实心的菱形表示组合关系: 实现的形式是: class A{...} class B{ A a; ...} 参考文章:http://blog.csdn.net/wfwd/archive/2006/05/30/763753.aspx http://blog.csdn.net/wfwd/archive/2006/05/30/763760.aspx 17. 面向对象的三个基本特征,并简单叙述之? 1. 封装:将客观事物抽象成类,每个类对自身的数据和方法实行protection(private, protected,public) 2. 继承:广义的继承有三种实现形式:实现继承(指使用基类的属性和方法而无需额外编码的能力)、可视继承(子窗体使用父窗体的外观和实现代码)、接口继承(仅使用属性和方法,实现滞后到子类实现)。前两种(类继承)和后一种(对象组合=> 接口继承以及纯虚函数)构成了功能复用的两种方式。 3. 多态:是将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。 18. 重载(overload) 和重写(overried ,有的书也叫做“ 覆盖” )的区别? 常考的题目。从定义上来说: 重载:是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。 重写:是指子类重新定义复类虚函数的方法。 从实现原理上来说: 重载:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。如,有两个同名函数:function func(p:integer):integer; 和function func(p:string):integer; 。那么编译器做过修饰后的函数名称可能是这样的:int_func 、str_func 。对于这两个函数的调用,在编译器间就已经确定了,是静态的。也就是说,它们的地址在编译期就绑定了(早绑定),因此,重载和多态无关! 重写:和多态真正相关。当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的(晚绑定)。
作者:123.112.125.*
2009-3-31 22:09 回复此发言
11
回复:经典C/C++ 面试题(一)
(六) 1) 什么是预编译,何时需要预编译:总是使用不经常改动的大型代码体。 程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。在这种情况下,可以将所有包含文件预编译为一个预编译头。 2) char * const p; char const * p const char *p 上述三个有什么区别? char * const p; // 常量指针,p 的值不可以修改 char const * p ;// 指向常量的指针,指向的常量值不可以改 const char *p ; // 和char const *p 3) char str1[] = "abc"; char str2[] = "abc"; const char str3[] = "abc"; const char str4[] = "abc"; const char *str5 = "abc"; const char *str6 = "abc"; char *str7 = "abc"; char *str8 = "abc"; cout << ( str1 == str2 ) << endl; cout << ( str3 == str4 ) << endl; cout << ( str5 == str6 ) << endl; cout << ( str7 == str8 ) << endl; 结果是:0 0 1 1 解答:str1,str2,str3,str4 是数组变量,它们有各自的内存空间;而str5,str6,str7,str8 是指针,它们指向相同的常量区域。 4) 以下代码中的两个sizeof 用法有问题吗? void UpperCase( char str[] ) // 将 str 中的小写字母转换成大写字母 { for( size_t i=0; i<sizeof(str)/sizeof(str[0]); ++i ) if( 'a'<=str[i] && str[i]<='z' ) str[i] -= ('a'-'A' ); } char str[] = "aBcDe"; cout << "str 字符长度为: " << sizeof(str)/sizeof(str[0]) << endl; UpperCase( str ); cout << str << endl; 答:函数内的sizeof 有问题。根据语法,sizeof 如用于数组,只能测出静态数组的大小,无法检测动态分配的或外部数组大小。函数外的str 是一个静态定义的数组,因此其大小为6 ,函数内的str 实际只是一个指向字符串的指针,没有任何额外的与数组相关的信息,因此sizeof 作用于上只将其当指针看,一个指针为4 个字节,因此返回4 。 5) 一个32 位的机器, 该机器的指针是多少位? 指针是多少位只要看地址总线的位数就行了。80386 以后的机子都是32 的数据总线。所以指针的位数就是4 个字节了。 6) main() { int a[5]={1,2,3,4,5};
作者:l270378034
2009-4-14 16:31 回复此发言
12
回复:经典C/C++ 面试题(一)
int *ptr=(int *)(&a+1); printf("%d,%d",*(a+1),*(ptr-1)); } 输出:2,5 *(a+1 )就是a[1] ,*(ptr-1) 就是a[4], 执行结果是2 ,5 &a+1 不是首地址+1 ,系统会认为加一个a 数组的偏移,是偏移了一个数组的大小(本例是5 个int ) int *ptr=(int *)(&a+1); 则ptr 实际是&(a[5]), 也就是a+5 原因如下: &a 是数组指针,其类型为 int (*)[5]; 而指针加1 要根据指针类型加上一定的值,不同类型的指针+1 之后增加的大小不同。 a 是长度为5 的int 数组指针,所以要加 5*sizeof(int) 所以ptr 实际是a[5] 但是prt 与(&a+1) 类型是不一样的( 这点很重要) 所以prt-1 只会减去sizeof(int*) a,&a 的地址是一样的,但意思不一样,a 是数组首地址,也就是a[0] 的地址,&a 是对象(数组)首地址,a+1 是数组下一元素的地址,即a[1],&a+1 是下一个对象的地址,即a[5]. 7) 请问以下代码有什么问题: int main() { char a; char *str=&a; strcpy(str,"hello"); printf(str); return 0; } 没有为str 分配内存空间,将会发生异常。问题出在将一个字符串复制进一个字符变量指针所指地址。虽然可以正确输出结果,但因为越界进行内在读写而导致程序崩溃。 8) char* s="AAA"; printf("%s",s); s[0]='B'; printf("%s",s); 有什么错? "AAA" 是字符串常量。s 是指针,指向这个字符串常量,所以声明s 的时候就有问题。 cosnt char* s="AAA"; 然后又因为是常量,所以对是s[0] 的赋值操作是不合法的。 9) 写一个“ 标准” 宏,这个宏输入两个参数并返回较小的一个。 .#define Min(X, Y) ((X)>(Y)?(Y):(X))// 结尾没有; 10) 嵌入式系统中经常要用到无限循环,你怎么用C 编写死循环。 while(1){} 或者for(;;) 软件开发网 www.mscto.cn 11) 关键字static 的作用是什么? 定义静态变量 12) 关键字const 有什么含意? 表示常量不可以修改的变量。 13) 关键字volatile 有什么含意?并举出三个不同的例子? 提示编译器对象的值可能在编译器未监测到的情况下改变。 14) int (*s[10])(int) 表示的是什么? int (*s[10])(int) 函数指针数组,每个指针指向一个int func(int param) 的函数。 15) 有以下表达式: int a=248; b=4; int const c=21; const int *d=&a; int *const e=&b; int const *f const =&a; 请问下列表达式哪些会被编译器禁止?为什么? *c=32;d=&b;*d=43;e=34;e=&a;f=0x321f; *c 这是个什么东东,禁止
作者:l270378034
2009-4-14 16:31 回复此发言
13
回复:经典C/C++ 面试题(一)
*d 说了是const , 禁止 e = &a 说了是const 禁止 const *f const =&a; 禁止 16) 交换两个变量的值,不使用第三个变量。即a=3,b=5, 交换之后a=5,b=3; 有两种解法, 一种用算术算法, 一种用^( 异或) a = a + b; b = a - b; a = a - b; or a = a^b;// 只能对int,char.. b = a^b; a = a^b; or a ^= b ^= a; 17) c 和c++ 中的struct 有什么不同? c 和c++ 中struct 的主要区别是c 中的struct 不可以含有成员函数,而c++ 中的struct 可以。c++ 中struct 和class 的主要区别在于默认的存取权限不同,struct 默认为public ,而class 默认为private 。 18) #include <stdio.h> #include <stdlib.h> void getmemory(char *p) { p=(char *) malloc(100); strcpy(p,"hello world"); } int main( ) { char *str=NULL; getmemory(str); printf("%s/n",str); free(str); return 0; } 程序崩溃,getmemory 中的malloc 不能返回动态内存, free ()对str 操作很危险 19) char szstr[10]; strcpy(szstr,"0123456789"); 产生什么结果?为什么? 长度不一样,会造成非法的OS 20) 列举几种进程的同步机制,并比较其优缺点。 原子操作 信号量机制 自旋锁 管程,会合,分布式系统 21) 进程之间通信的途径 共享存储系统 消息传递系统 管道:以文件系统为基础 22) 进程死锁的原因 资源竞争及进程推进顺序非法 23) 死锁的4 个必要条件 互斥、请求保持、不可剥夺、环路 24) 死锁的处理 鸵鸟策略、预防策略、避免策略、检测与解除死锁 25) 操作系统中进程调度策略有哪几种? FCFS( 先来先服务) ,优先级,时间片轮转,多级反馈 26) 类的静态成员和非静态成员有何区别? 类的静态成员每个类只有一个,非静态成员每个对象一个 27) 纯虚函数如何定义?使用时应注意什么? virtual void f()=0; 是接口,子类必须要实现 28) 数组和链表的区别 数组:数据顺序存储,固定大小 连表:数据可以随机存储,大小可动态改变 29) ISO 的七层模型是什么?tcp/udp 是属于哪一层?tcp/udp 有何优缺点? 应用层 表示层 会话层 运输层 网络层 物理链路层 物理层 tcp /udp 属于运输层 TCP 服务提供了数据流传输、可靠性、有效流控制、全双工操作和多路复用技术等。
作者:l270378034
2009-4-14 16:31 回复此发言
14
回复:经典C/C++ 面试题(一)
与 TCP 不同, UDP 并不提供对 IP 协议的可靠机制、流控制以及错误恢复功能等。由于 UDP 比较简单, UDP 头包含很少的字节,比 TCP 负载消耗少。 tcp: 提供稳定的传输服务,有流量控制,缺点是包头大,冗余性不好 udp: 不提供稳定的服务,包头小,开销小 30) (void *)ptr 和 (*(void**))ptr 的结果是否相同? 其中ptr 为同一个指针(void *)ptr 和 (*(void**))ptr 值是相同的 32) int main() { int x=3; printf("%d",x); return 1; } 问函数既然不会被其它函数调用,为什么要返回1 ? mian 中,c 标准认为0 表示成功,非0 表示错误。具体的值是某中具体出错信息 33) 要对绝对地址0x100000 赋值,我们可以用(unsigned int*)0x100000 = 1234; 那么要是想让程序跳转到绝对地址是0x100000 去执行,应该怎么做? *((void (*)( ))0x100000 ) ( ); 首先要将0x100000 强制转换成函数指针, 即: (void (*)())0x100000 然后再调用它: *((void (*)())0x100000)(); 用typedef 可以看得更直观些: typedef void(*)() voidFuncPtr; *((voidFuncPtr)0x100000)(); 34) 已知一个数组table ,用一个宏定义,求出数据的元素个数 #define NTBL #define NTBL (sizeof(table)/sizeof(table[0])) 35) 线程与进程的区别和联系? 线程是否具有相同的堆栈? dll 是否有独立的堆栈? 进程是死的,只是一些资源的集合,真正的程序执行都是线程来完成的,程序启动的时候操作系统就帮你创建了一个主线程。 每个线程有自己的堆栈。DLL 中有没有独立的堆栈? 这个问题不好回答,或者说这个问题本身是否有问题。因为DLL 中的代码是被某些线程所执行,只有线程拥有堆栈,如果DLL 中的代码是EXE 中的线程所调用,那么这个时候是不是说这个DLL 没有自己独立的堆栈?如果DLL 中的代码是由DLL 自己创建的线程所执行,那么是不是说DLL 有独立的堆栈? 以上讲的是堆栈,如果对于堆来说,每个DLL 有自己的堆,所以如果是从DLL 中动态分配的内存,最好是从DLL 中删除,如果你从DLL 中分配内存,然后在EXE 中,或者另外一个DLL 中删除,很有可能导致程序崩溃。 36) unsigned short A = 10; printf("~A = %u/n", ~A); char c=128; printf("c=%d/n",c); 输出多少?并分析过程 第一题,~A =0xfffffff5,int 值 为-11 ,但输出的是uint 。所以输出4294967285 第二题,c =0x10, 输出的是int ,最高位为1 ,是负数,所以它的值就是0x00 的补码就是128 ,所以输出-128 。 这两道题都是在考察二进制向int 或uint 转换时的最高位处理。 37) 分析下面的程序: void GetMemory(char **p,int num) { *p=(char *)malloc(num); } int main() { char *str=NULL; GetMemory(&str,100); strcpy(str,"hello"); free(str); if(str!=NULL) { strcpy(str,"world"); } printf("/n str is %s",str); 软件开发网 www.mscto.com
作者:l270378034
2009-4-14 16:31 回复此发言
15
回复:经典C/C++ 面试题(一)
getchar(); } 问输出结果是什么? 输出str is world 。 free 只是释放的str 指向的内存空间, 它本身的值还是存在的. 所以free 之后,有一个好的习惯就是将str=NULL. 此时str 指向空间的内存已被回收, 如果输出语句之前还存在分配空间的操作的话, 这段存储空间是可能被重新分配给其他变量的, 尽管这段程序确实是存在大大的问题(上面各位已经说得很清楚了),但是通常会打印出world 来。 这是因为,进程中的内存管理一般不是由操作系统完成的,而是由库函数自己完成的。 当你malloc 一块内存的时候,管理库向操作系统申请一块空间(可能会比你申请的大一些),然后在这块空间中记录一些管理信息(一般是在你申请的内存前面一点),并将可用内存的地址返回。但是释放内存的时候,管理库通常都不会将内存还给操作系统,因此你是可以继续访问这块地址的。 char a[10],strlen(a) 为什么等于15 ?运行的结果 38) #include "stdio.h" #include "string.h" void main() { char aa[10]; printf("%d",strlen(aa)); } sizeof() 和初不初始化,没有关系; strlen() 和初始化有关。 39) char (*str)[20]; char *str[20]; 40) long a=0x801010; a+5=? 0x801010 用二进制表示为:“1000 0000 0001 0000 0001 0000” ,十进制的值为8392720 ,再加上5 就是8392725 罗 41) 给定结构 struct A { char t:4; char k:4; unsigned short i:8; unsigned long m; }; 问sizeof(A) = ? 给定结构 struct A { char t:4; 4 位 char k:4; 4 位 unsigned short i:8; 8 位 unsigned long m; // 偏移2 字节保证4 字节对齐 }; // 共8 字节 42) 下面的函数实现在一个数上加一个数,有什么错误?请改正。 int add_n ( int n ) { static int i = 100; i += n; return i; } 当你第二次调用时得不到正确的结果,难道你写个函数就是为了调用一次?问题就出在 static 上? 43) 分析一下 #include<iostream.h> #include <string.h> #include <malloc.h> #include <stdio.h> #include <stdlib.h> #include <memory.h> typedef struct AA { int b1:5; int b2:2; }AA; void main() { AA aa; char cc[100]; strcpy(cc,"0123456789abcdefghijklmnopqrstuvwxyz");
作者:l270378034
2009-4-14 16:31 回复此发言
16
回复:经典C/C++ 面试题(一)
memcpy(&aa,cc,sizeof(AA)); cout << aa.b1 <<endl; cout << aa.b2 <<endl; } 答案是 -16 和1 首先sizeof(AA) 的大小为4,b1 和b2 分别占5bit 和2bit. 经过strcpy 和memcpy 后,aa 的4 个字节所存放的值是: 0,1,2,3 的ASC 码,即00110000,00110001,00110010,00110011 所以,最后一步:显示的是这4个字节的前5位,和之后的2位分别为:10000, 和01 ,因为int 是有正负之分 所以:答案是-16 和1 44) 求函数返回值,输入x=9999; int func ( x ) { int countx = 0; while ( x ) { countx ++; x = x&(x-1); } return countx; } 结果呢? 知道了这是统计9999 的二进制数值中有多少个1 的函数,且有9999 =9×1024 +512 +256 +15 9×1024 中含有1 的个数为2 ; 512 中含有1 的个数为1 ; 256 中含有1 的个数为1 ; 15 中含有1 的个数为4 ; 软件开发网 www.mscto.com 故共有1 的个数为8 ,结果为8 。 1000 - 1 = 0111 ,正好是原数取反。这就是原理。 用这种方法来求1 的个数是很效率很高的。 不必去一个一个地移位。循环次数最少。 int a,b,c 请写函数实现C=a+b , 不可以改变数据类型, 如将c 改为long int, 关键是如何处理溢出问题 bool add (int a, int b,int *c) { *c=a+b; return (a>0 && b>0 &&(*c<a || *c<b) || (a<0 && b<0 &&(*c>a || *c>b))); } 45) 分析: struct bit { int a:3; int b:2; int c:3; }; int main() { bit s; char *c=(char*)&s; cout<<sizeof(bit)<<endl; *c=0x99; cout << s.a <<endl <<s.b<<endl<<s.c<<endl; int a=-1; printf("%x",a); return 0; } 输出为什么是 4 1 -1 -4 ffffffff 因为0x99 在内存中表示为 100 11 001 , a = 001, b = 11, c = 100 。当c 为有符合数时, c = 100, 最高1 为表示c 为负数,负数在计算机用补码表示,所以c = -4; 同理 b = -1; 当c 为有符合数时, c = 100, 即 c = 4, 同理 b = 3 。 46) 位域 : 有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0 和1 两种状态,用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“ 位域” 或“ 位段” 。所谓“ 位域” 是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。一、位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:
作者:l270378034
2009-4-14 16:31 回复此发言
17
回复:经典C/C++ 面试题(一)
struct 位域结构名 { 位域列表 }; 其中位域列表的形式为:类型说明符位域名:位域长度 例如: struct bs { int a:8; int b:2; int c:6; }; 位域变量的说明与结构变量说明的方式相同。可采用先定义后说明,同时定义说明或者直接说明这三种方式。例如: struct bs { int a:8; int b:2; int c:6; }data; 说明data 为bs 变量,共占两个字节。其中位域a 占8 位,位域b 占2 位,位域c 占6 位。对于位域的定义尚有以下几点说明: 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如: struct bs { unsigned a:4 unsigned :0 unsigned b:4 unsigned c:4 } 在这个位域定义中,a 占第一字节的4 位,后4 位填0 表示不使用,b 从第二字节开始,占用4 位,c 占用4 位。 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8 位二进位。 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如: struct k { int a:1 int :2 int b:3 int c:2 }; 从以上分析可以看出,位域在本质上就是一种结构类型,不过其成员是按二进位分配的。 位域的使用位域的使用和结构成员的使用相同,其一般形式为:位域变量名? 位域名位域允许用各种格式输出。 main() { struct bs { unsigned a:1; unsigned b:3; unsigned c:4; } bit,*pbit; bit.a=1; bit.b=7; bit.c=15; pri 47) 改错: #include <stdio.h> int main(void) { int **p; int arr[100]; p = &arr; return 0; } 解答:搞错了, 是指针类型不同,int **p; // 二级指针&arr; // 得到的是指向第一维为100 的数组的指针 #include <stdio.h> int main(void) { int **p, *q; int arr[100]; q = arr; p = &q; return 0; }
作者:l270378034
2009-4-14 16:31 回复此发言
18
回复:经典C/C++ 面试题(一)
48) 下面这个程序执行后会有什么错误或者效果: #define MAX 255 int main() { unsigned char A[MAX],i;//i 被定义为unsigned char for (i=0;i<=MAX;i++) A[i]=i; return 0; } 解答:死循环加数组越界访问(C/C++ 不进行数组越界检查)MAX=255 数组A 的下标范围为:0..MAX-1, 这是其一.. 其二. 当i 循环到255 时, 循环内执行:A[255]=255; 这句本身没有问题.. 但是返回for (i=0;i<=MAX;i++) 语句时, 由于unsigned char 的取值范围在(0..255),i++ 以后i 又为0 了.. 无限循环下去。 49) struct name1 { char str; short x; int num; } struct name2 { char str; int num; short x; } sizeof(struct name1)=8,sizeof(struct name2)=12 在第二个结构中,为保证num 按四个字节对齐,char 后必须留出3 字节的空间;同时为保证整个结构的自然对齐(这里是4 字节对齐),在x 后还要补齐2 个字节,这样就是12 字节。 50) intel : A.c 和B.c 两个c 文件中使用了两个相同名字的static 变量, 编译的时候会不会有问题? 这两个static 变量会保存到哪里(栈还是堆或者其他的)? static 的全局变量,表明这个变量仅在本模块中有意义,不会影响其他模块。他们都放在数据区,但是编译器对他们的命名是不同的。如果要使变量在其他模块也有意义的话,需要使用extern 关键字。 51) struct s1 { int i: 8; int j: 4; int a: 3; double b; }; struct s2 { int i: 8; int j: 4; double b; int a:3; }; printf("sizeof(s1)= %d/n", sizeof(s1)); printf("sizeof(s2)= %d/n", sizeof(s2)); result: 16, 24 第一个struct s1 { int i: 8; int j: 4; int a: 3; double b; }; 理论上是这样的,首先是i 在相对0 的位置,占8 位一个字节,然后,j 就在相对一个字节的位置,由于一个位置的字节数是4 位的倍数,因此不用对齐,就放在那里了,然后是a ,要在3 位的倍数关系的位置上,因此要移一位,在15 位的位置上放下,目前总共是18 位,折算过来是2 字节2 位的样子,由于double 是8 字节的,因此要在相对0 要是8 个字节的位置上放下,因此从18 位开始到8 个字节之间的位置被忽略,直接放在8 字节的位置了,因此,总共是16 字节。 第二个最后会对照是不是结构体内最大数据的倍数,不是的话,会补成是最大数据的倍数。
作者:l270378034
2009-4-14 16:31 回复此发言
19
回复:经典C/C++ 面试题(一)
(五) 40. 链表题:一个链表的结点结构 struct Node { int data ; Node *next ; }; typedef struct Node Node ; (1) 已知链表的头结点head, 写一个函数把这个链表逆序 ( Intel) Node * ReverseList(Node *head) // 链表逆序 { if ( head == NULL || head->next == NULL ) return head; Node *p1 = head ; Node *p2 = p1->next ; Node *p3 = p2->next ; p1->next = NULL ; while ( p3 != NULL ) { p2->next = p1 ; p1 = p2 ; p2 = p3 ; p3 = p3->next ; } p2->next = p1 ; head = p2 ; return head ; } (2) 已知两个链表head1 和head2 各自有序,请把它们合并成一个链表依然有序。( 保留所有结点,即便大小相同) Node * Merge(Node *head1 , Node *head2) { if ( head1 == NULL) return head2 ; if ( head2 == NULL) return head1 ; Node *head = NULL ; Node *p1 = NULL; Node *p2 = NULL; if ( head1->data < head2->data ) { head = head1 ; p1 = head1->next; p2 = head2 ; } else { head = head2 ; p2 = head2->next ; p1 = head1 ; } Node *pcurrent = head ; while ( p1 != NULL && p2 != NULL) { if ( p1->data <= p2->data ) { pcurrent->next = p1 ; pcurrent = p1 ; p1 = p1->next ; } else { pcurrent->next = p2 ; pcurrent = p2 ; p2 = p2->next ; } } if ( p1 != NULL ) pcurrent->next = p1 ; if ( p2 != NULL ) pcurrent->next = p2 ; return head ; } (3) 已知两个链表head1 和head2 各自有序,请把它们合并成一个链表依然有序,这次要求用递归方法进行。 (Autodesk) 答案: Node * MergeRecursive(Node *head1 , Node *head2) { if ( head1 == NULL ) return head2 ; if ( head2 == NULL)
作者:221.221.165.*
2009-4-14 16:31 回复此发言
20
回复:经典C/C++ 面试题(一)
return head1 ; Node *head = NULL ; if ( head1->data < head2->data ) { head = head1 ; head->next = MergeRecursive(head1->next,head2); } else { head = head2 ; head->next = MergeRecursive(head1,head2->next); } return head ; } 41. 分析一下这段程序的输出 (Autodesk) class B { public: B() { cout<<"default constructor"<<endl; } ~B() { cout<<"destructed"<<endl; } B(int i):data(i) //B(int) works as a converter ( int -> instance of B) { cout<<"constructed by parameter " << data <<endl; } private: int data; }; B Play( B b) { return b ; } (1) results: int main(int argc, char* argv[]) constructed by parameter 5 { destructed B(5) 形参析构 B t1 = Play(5); B t2 = Play(t1); destructed t1 形参析构 return 0; destructed t2 注意顺序! } destructed t1 (2) results: int main(int argc, char* argv[]) constructed by parameter 5 { destructed B(5) 形参析构 B t1 = Play(5); B t2 = Play(10); constructed by parameter 10 return 0; destructed B(10) 形参析构 } destructed t2 注意顺序! destructed t1 42. 写一个函数找出一个整数数组中,第二大的数 (Microsoft ) 答案: const int MINNUMBER = -32767 ; int find_sec_max( int data[] , int count) { int maxnumber = data[0] ; int sec_max = MINNUMBER ; for ( int i = 1 ; i < count ; i++) { if ( data > maxnumber ) { sec_max = maxnumber ; maxnumber = data ; } else { if ( data > sec_max ) sec_max = data ; } } return sec_max ; } 43. 写一个在一个字符串(n) 中寻找一个子串(m) 第一个位置的函数。 KMP 算法效率最好,时间复杂度是O(n+m) 。 44. 多重继承的内存分配问题: 比如有class A : public class B, public class C {} 那么A 的内存结构大致是怎么样的? 这个是compiler-dependent 的, 不同的实现其细节可能不同。 如果不考虑有虚函数、虚继承的话就相当简单;否则的话,相当复杂。 可以参考《深入探索C++ 对象模型》,或者:http://blog.csdn.net/wfwd/archive/2006/05/30/763797.aspx
作者:221.221.165.*
2009-4-14 16:31 回复此发言
21
回复:经典C/C++ 面试题(一)
45. 如何判断一个单链表是有环的?(注意不能用标志位,最多只能用两个额外指针) struct node { char val; node* next;} bool check(const node* head) {} //return false : 无环;true: 有环 一种O (n )的办法就是(搞两个指针,一个每次递增一步,一个每次递增两步,如果有环的话两者必然重合,反之亦然): bool check(const node* head) { if(head==NULL) return false; node *low=head, *fast=head->next; while(fast!=NULL && fast->next!=NULL) { low=low->next; fast=fast->next->next; if(low==fast) return true; } return false; } 1. C++ 的类和C 里面的struct 有什么区别? struct 成员默认访问权限为public ,而class 成员默认访问权限为private 2. 析构函数和虚函数的用法和作用 析构函数是在对象生存期结束时自动调用的函数,用来释放在构造函数分配的内存。 虚函数是指被关键字virtual 说明的函数,作用是使用C++ 语言的多态特性 3. 全局变量和局部变量有什么区别?是怎么实现的?操作系统和编译器是怎么知道的? 1) 全局变量的作用用这个程序块, 而局部变量作用于当前函数 2) 前者在内存中分配在全局数据区, 后者分配在栈区 3) 生命周期不同:全局变量随主程序创建和创建,随主程序销毁而销毁,局部变量在局部函数内部,甚至局部循环体等内部存在,退出就不存在 4) 使用方式不同:通过声明后全局变量程序的各个部分都可以用到,局部变量只能在局部使用 4. 有N 个大小不等的自然数(1--N ),请将它们由小到大排序. 要求程序算法:时间复杂度为O(n) ,空间复杂度为O(1) 。 void sort(int e[], int n) { int i; int t; for (i=1; i<n+1; i++) { t = e[e[i]]; e[e[i]] = e[i]; e[i] = t; } } 5. 堆与栈的去区别 A. 申请方式不同 Stack 由系统自动分配,而heap 需要程序员自己申请,并指明大小。 B. 申请后系统的响应不同 Stack :只要栈的剩余空间大于申请空间,系统就为程序提供内存,否则将抛出栈溢出异常 Heap :当系统收到程序申请时,先遍历操作系统中记录空闲内存地址的链表,寻找第一个大于所申请空间的堆结点,然后将该结点从空间结点链表中删除,并将该结点的空间分配给程序。另外,大多数系统还会在这块内存空间中的首地址处记录本次分配的大小,以便于delete 语句正确释放空间。而且,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动将多余的那部分重新放入空闲链表。 C. 申请大小限制的不同 Stack :在windows 下,栈的大小是2M (也可能是1M 它是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow 。因此,能从栈获得的空间较小。 Heap :堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
作者:221.221.165.*
2009-4-14 16:31 回复此发言
22
回复:经典C/C++ 面试题(一)
D. 申请效率的比较: 栈由系统自动分配,速度较快。但程序员是无法控制的。 堆是由new 分配的内存,一般速度比较慢,而且容易产生内存碎片, 不过用起来最方便。 另外,在WINDOWS 下,最好的方式是用VirtualAlloc 分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。 E. 堆和栈中的存储内容 栈:在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C 编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。 堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。 6. 含参数的宏与函数的优缺点 宏: 优点:在预处理阶段完成,不占用编译时间,同时,省去了函数调用的开销,运行效率高 缺点:不进行类型检查,多次宏替换会导致代码体积变大,而且由于宏本质上是字符串替换,故可能会由于一些参数的副作用导致得出错误的结果。 函数: 优点:没有带参数宏可能导致的副作用,进行类型检查,计算的正确性更有保证。 缺点:函数调用需要参数、返回地址等的入栈、出栈开销,效率没有带参数宏高 PS :宏与内联函数的区别 内联函数和宏都是在程序出现的地方展开,内联函数不是通过函数调用实现的,是在调用该函数的程序处将它展开(在编译期间完成的);宏同样是; 不同的是:内联函数可以在编译期间完成诸如类型检测,语句是否正确等编译功能;宏就不具有这样的功能,而且宏展开的时间和内联函数也是不同的(在运行期间展开) 7. Windows 程序的入口是哪里?写出Windows 消息机制的流程 Windows 程序的入口是WinMain() 函数。 Windows 应用程序消息处理机制: A. 操作系统接收应用程序的窗口消息,将消息投递到该应用程序的消息队列中 B. 应用程序在消息循环中调用GetMessage 函数从消息队列中取出一条一条的消息,取出消息后,应用程序可以对消息进行一些预处理。 C. 应用程序调用DispatchMessage ,将消息回传给操作系统。 D. 系统利用WNDCLASS 结构体的lpfnWndProc 成员保存的窗口过程函数的指针调用窗口过程,对消息进行处理。 8. 如何定义和实现一个类的成员函数为回调函数 A. 什么是回调函数? 简而言之,回调函数就是被调用者回头调用调用者的函数。 使用回调函数实际上就是在调用某个函数(通常是API 函数)时,将自己的一个函数(这个函数为回调函数)的地址作为参数传递给那个被调用函数。而该被调用函数在需要的时候,利用传递的地址调用回调函数。 回调函数,就是由你自己写的,你需要调用另外一个函数,而这个函数的其中一个参数,就是你的这个回调函数名。这样,系统在必要的时候,就会调用你写的回调函数,这样你就可以在回调函数里完成你要做的事。 B. 如何定义和实现一个类的成员函数为回调函数 要定义和实现一个类的成员函数为回调函数需要做三件事: a .声明; b .定义; c .设置触发条件,就是在你的函数中把你的回调函数名作为一个参数,以便系统调用 如: 一、声明回调函数类型 typedef void (*FunPtr)(void); 二、定义回调函数 class A { public: A(); static void callBackFun(void) // 回调函数,必须声明为static { cout<<"callBackFun"<<endl; } virtual ~A(); }; 三、设置触发条件 void Funtype(FunPtr p) { p(); } void main(void) { Funtype(A::callBackFun); } C. 回调函数与API 函数 回调和API 非常接近,他们的共性都是跨层调用的函数。但区别是API 是低层提供给高层的调用,一般这个函数对高层都是已知的;而回调正好相反,他是高层提供给底层的调用,对于低层他是未知的,必须由高层进行安装,这个安装函数其实就是一个低层提供的API ,安装后低层不知道这个回调的名字,但它通过一个函数指针来保存这个回调函数,在需要调用时,只需引用这个函数指针和相关的参数指针。 其实:回调就是该函数写在高层,低层通过一个函数指针保存这个函数,在某个事件的触发下,低层通过该函数指针调用高层那个函数。
作者:221.221.165.*
2009-4-14 16:31 回复此发言
23
回复:经典C/C++ 面试题(一)
1 、局部变量能否和全局变量重名? 能,局部会屏蔽全局。要用全局变量,需要使用"::" 局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内。 2 、如何引用一个已经定义过的全局变量? extern 可以用引用头文件的方式,也可以用extern 关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变理,假定你将那个变写错了,那么在编译期间会报错,如果你用extern 方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。 3 、全局变量可不可以定义在可被多个.C 文件包含的头文件中?为什么? 可以,在不同的C 文件中以static 形式来声明同名全局变量。 可以在不同的C 文件中声明同名的全局变量,前提是其中只能有一个C 文件中对此变量赋初值,此时连接不会出错。 4 、语句for( ;1 ;) 有什么问题?它是什么意思? 无限循环,和while(1) 相同。 5 、do……while 和while……do 有什么区别? 前一个循环一遍再判断,后一个判断以后再循环。 6 、请写出下列代码的输出内容 #include<stdio.h> 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; } 答:10 ,12 ,120 7 、请找出下面代码中的所以错误 说明:以下代码是把一个字符串倒序,如“abcd” 倒序后变为“dcba” #include "string.h" main() { char*src="hello,world"; char* dest=NULL; int len=strlen(src); dest=(char*)malloc(len); char* d=dest; char* s=src[len]; while(len--!=0) d++=s--; printf("%s",dest); return 0; } 答: 方法1 : int main() { char* src = "hello,world"; int len = strlen(src); char* dest = (char*)malloc(len+1);// 要为/0 分配一个空间 char* d = dest; char* s = &src[len-1];// 指向最后一个字符 while( len-- != 0 ) *d++=*s--; *d = 0;// 尾部要加/0 printf("%s/n",dest); free(dest);// 使用完,应当释放空间,以免造成内存汇泄露 return 0; } 方法2 : #include <stdio.h> #include <string.h> main() { char str[]="hello,world"; int len=strlen(str); char t; for(int i=0; i<len/2; i++) { t=str[i]; str[i]=str[len-i-1]; str[len-i-1]=t; } printf("%s",str); return 0; } 8 、-1,2,7,28,,126 请问28 和126 中间那个数是什么?为什么?
作者:221.221.165.*
2009-4-14 16:32 回复此发言
24
回复:经典C/C++ 面试题(一)
答案应该是4^3-1=63 规律是n^3-1( 当n 为偶数0 ,2 ,4) n^3+1( 当n 为奇数1 ,3 ,5) 答案:63 9 、用两个栈实现一个队列的功能?要求给出算法和思路! 设2 个栈为A,B, 一开始均为空. 入队: 将新元素push 入栈A; 出队: (1) 判断栈B 是否为空; (2) 如果不为空,则将栈A 中所有元素依次pop 出并push 到栈B ; (3) 将栈B 的栈顶元素pop 出;这样实现的队列入队和出队的平摊复杂度都还是O(1), 比上面的几种方法要好。 10 、在c 语言库函数中将一个字符转换成整型的函数是atool() 吗,这个函数的原型是什么? 函数名: atol 功 能: 把字符串转换成长整型数 用 法: long atol(const char *nptr); 程序例: #include <stdlib.h> #include <stdio.h> int main(void) { long l; char *str = "98765432"; l = atol(lstr); printf("string = %s integer = %ld/n", str, l); return(0); } 11 、对于一个频繁使用的短小函数, 在C 语言中应用什么实现, 在C++ 中应用什么实现? c 用宏定义,c++ 用inline 12 、直接链接两个信令点的一组链路称作什么? PPP 点到点连接 13 、接入网用的是什么接口? 14 、voip 都用了那些协议? 15 、软件测试都有那些种类? 黑盒:针对系统功能的测试 白合:测试函数功能,各函数接口 16 、确定模块的功能和模块的接口是在软件设计的那个队段完成的? 概要设计阶段 17 、enum string { x1, x2, x3=10, x4, x5, }x; 问x= 0x801005 ,0x8010f4; 18 、unsigned char *p1; unsigned long *p2; p1=(unsigned char *)0x801000; p2=(unsigned long *)0x810000; 请问p1+5= 0x801005; p2+5= 0x801014; 19. 多态的作用? 主要是两个:1. 隐藏实现细节,使得代码能够模块化;扩展代码模块,实现代码重用;2. 接口重用:为了类在继承和派生的时候,保证使用家族中任一类的实例的某一属性时的正确调用。 20. Ado 与Ado.net 的相同与不同? 除了“ 能够让应用程序处理存储于DBMS 中的数据“ 这一基本相似点外,两者没有太多共同之处。但是Ado 使用OLE DB 接口并基于微软的COM 技术,而ADO.NET 拥有自己的ADO.NET 接口并且基于微软的.NET 体系架构。众所周知.NET 体系不同于COM 体系,ADO.NET 接口也就完全不同于ADO 和OLE DB 接口,这也就是说ADO.NET 和ADO 是两种数据访问方式。ADO.net 提供对XML 的支持。 21. New delete 与malloc free 的联系与区别? 都是在堆(heap) 上进行动态的内存操作。用malloc 函数需要指定内存分配的字节数并且不能初始化对象,new 会自动调用对象的构造函数。delete 会调用对象的destructor ,而free 不会调用对象的destructor. 22. #define DOUBLE(x) x+x ,i = 5*DOUBLE(5) ; i 是多少? 答案:i 为30 。
作者:221.221.165.*
2009-4-14 16:32 回复此发言
25
回复:经典C/C++ 面试题(一)
23. 有哪几种情况只能用intialization list 而不能用assignment? 答案:当类中含有const 、reference 成员变量;基类的构造函数都需要初始化表。 24. C++ 是不是类型安全的? 答案:不是。两个不同类型的指针之间可以强制转换(用reinterpret cast) 。C# 是类型安全的。 25. main 函数执行以前,还会执行什么代码? 答案:全局对象的构造函数会在main 函数之前执行。 26. 描述内存分配方式以及它们的区别? 1 )从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static 变量。 2 )在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集。 3 )从堆上分配,亦称动态内存分配。程序在运行的时候用malloc 或new 申请任意多少的内存,程序员自己负责在何时用free 或delete 释放内存。动态内存的生存期由程序员决定,使用非常灵活,但问题也最多。 27.struct 和 class 的区别 struct 的成员默认是公有的,而类的成员默认是私有的。struct 和 class 在其他方面是功能相当的。 从感情上讲,大多数的开发者感到类和结构有很大的差别。感觉上结构仅仅象一堆缺乏封装和功能的开放的内存位,而类就象活的并且可靠的社会成员,它有智能服务,有牢固的封装屏障和一个良好定义的接口。既然大多数人都这么认为,那么只有在你的类有很少的方法并且有公有数据(这种事情在良好设计的系统中是存在的! )时,你也许应该使用 struct 关键字,否则,你应该使用 class 关键字。 28. 当一个类A 中没有生命任何成员变量与成员函数, 这时sizeof(A) 的值是多少,如果不是零,请解释一下编译器为什么没有让它为零。(Autodesk ) 肯定不是零。举个反例,如果是零的话,声明一个class A[10] 对象数组,而每一个对象占用的空间是零,这时就没办法区分A[0],A[1]… 了。 29. 在8086 汇编下,逻辑地址和物理地址是怎样转换的?(Intel ) 通用寄存器给出的地址,是段内偏移地址,相应段寄存器地址*10H+ 通用寄存器内地址,就得到了真正要访问的地址。 30. 比较C++ 中的4 种类型转换方式? 请参考:http://blog.csdn.net/wfwd/archive/2006/05/30/763785.aspx ,重点是static_cast, dynamic_cast 和reinterpret_cast 的区别和应用。 31. 分别写出BOOL,int,float, 指针类型的变量a 与“ 零” 的比较语句。 答案: BOOL : if ( !a ) or if(a) int : if ( a == 0) float : const EXPRESSION EXP = 0.000001 if ( a < EXP && a >-EXP) pointer : if ( a != NULL) or if(a == NULL) 32. 请说出const 与#define 相比,有何优点? 答案: 1 ) const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。 2 )有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。
26
回复:经典C/C++ 面试题(一)
33.简述数组与指针的区别? 数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。指针可以随时指向任意类型的内存块。 (1) 修改内容上的差别 char a[] = “hello”; a[0] = ‘X’; char *p = “world”; // 注意p 指向常量字符串 p[0] = ‘X’; // 编译器不能发现该错误,运行时错误 (2) 用运算符sizeof 可以计算出数组的容量(字节数)。sizeof(p),p 为指针得到的是一个指针变量的字节数,而不是p 所指的内存容量。C++/C 语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。 char a[] = "hello world"; char *p = a; cout<< sizeof(a) << endl; // 12 字节 cout<< sizeof(p) << endl; // 4 字节 计算数组和指针的内存容量 void Func(char a[100]) { cout<< sizeof(a) << endl; // 4 字节而不是100 字节 } 34. 类成员函数的重载、覆盖和隐藏区别? 答案: a. 成员函数被重载的特征: (1 )相同的范围(在同一个类中); (2 )函数名字相同; (3 )参数不同; (4 )virtual 关键字可有可无。 b. 覆盖是指派生类函数覆盖基类函数,特征是: (1 )不同的范围(分别位于派生类与基类); (2 )函数名字相同; (3 )参数相同; (4 )基类函数必须有virtual 关键字。 c.“ 隐藏” 是指派生类的函数屏蔽了与其同名的基类函数,规则如下: (1 )如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual 关键字,基类的函数将被隐藏(注意别与重载混淆)。 (2 )如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆) 35. 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. 答案: ( ( a + b ) + abs( a - b ) ) / 2 36. 如何打印出当前源文件的文件名以及源文件的当前行号? 答案: cout << __FILE__ ; cout<<__LINE__ ; __FILE__ 和__LINE__ 是系统预定义宏,这种宏并不是在某个文件中定义的,而是由编译器定义的。 37. main 主函数执行完毕后,是否可能会再执行一段代码,给出说明? 答案: 可以,可以用_onexit 注册一个函数,它会在main 之后执行int fn1(void), fn2(void), fn3(void), fn4 (void); void main( void ) { String str("zhanglin"); _onexit( fn1 ); _onexit( fn2 );
27
_onexit( fn3 ); _onexit( fn4 ); printf( "This is executed first./n" ); } int fn1() { printf( "next./n" ); return 0; } int fn2() { printf( "executed " ); return 0; } int fn3() { printf( "is " ); return 0; } int fn4() { printf( "This " ); return 0; } 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. 38. 如何判断一段程序是由C 编译程序还是由C++ 编译程序编译的? 答案: #ifdef __cplusplus cout<<"c++"; #else cout<<"c"; #endif 39. 文件中有一组整数,要求排序后输出到另一个文件中 答案: #include<iostream> #include<fstream> using namespace std; void Order(vector<int>& data) //bubble sort { int count = data.size() ; int tag = false ; // 设置是否需要继续冒泡的标志位 for ( int i = 0 ; i < count ; i++) { for ( int j = 0 ; j < count - i - 1 ; j++) { if ( data[j] > data[j+1]) { tag = true ; int temp = data[j] ; data[j] = data[j+1] ; data[j+1] = temp ; } } if ( !tag ) break ; } } void main( void ) { vector<int>data; ifstream in("c://data.txt"); if ( !in) { cout<<"file error!"; exit(1); } int temp; while (!in.eof()) { in>>temp; data.push_back(temp); } in.close(); // 关闭输入文件流 Order(data); ofstream out("c://result.txt"); if ( !out) { cout<<"file error!"; exit(1); } for ( i = 0 ; i < data.size() ; i++) out<<data<<" "; out.close(); // 关闭输出文件流 }