程序员面试宝典2008-10-05 22:27 第一部份 C/C++
一、i++
1. x=x+1 , x+=1 ,x++ 那种效率最高 为什么?
解析:
x=x+1 效率最低
因为它的执行过程如下:
1.读取右边x的地址.
2.x+1.
3.读取左x的地址.
4.将右值传给左边的X(编译器并不认为左右的X地址相同)
其次 x+=1.
1.读取右x的地址
2.x+1
3.将得到值传给x(因为x的地址已经读出)
x++效率最高
1.读取右x的址址
2.x自增1
2. What will be the output of the following C code?
#define product(x)(x*x)
int main()
{
int i=3,j,k;
j=product(i++);
k=product(++i);
printf("j=%d,k=%d",j,k);
return 0;
}
解析:
product(i__)=i++*i++;i=3,所以j等到于9,此时i已经累加到5了.
product(++i) 要求先累加i,累加后i等于7,所以product(++i)结果49;
答案:9,49
3.if there are "int a=5,b=3;",the values of a and b are ____ and ____ after execute "!a && b++;",
解析:
这是表达式运算问题.因为"!a"运算结束后,整个表达式的值已经为假,所以不必再去计算后面的式子.
答案:5,3
二、编程风格
1.we have two pieces of code,which one do you prefer ,and tell why?
A .
// a is a variable
写法1:
if('A'==a)
{
a++;
}
写法2:
if(a=='A')
{
a++;
}
B .
写法1:
for(i=0;i<9;i++){
X=i+Y+J*7;
printf("%d",X);
}
写法2:
S=Y+J*7;
for(i=0;i<9;i++){
printf("%d",i+S);
}
解析:
A:第一种写法('A'==a)比较好,如果把"=="误写成了"="号,编译器会检查到此错误!
因为编译器不允许给常量赋值;
B:第二种写法好一些,将部份加法运算放到循环体外面,提高了效率.但代码不够简洁
三、类型转换
1.char foo(void)
{
unsigned int a=6;
int b=-20;
char c;
(a+b>6)?(c=1):(c=0);
return c;
}
解析:unsigned int 类型的数据与int 类型的数据相运算后,自动转化为unsigned int类型
所以a+b的值不为-14,而是一个unsigned int类型的大数4294967382
因此返回值为1,与我们实际想要的结果不符,
可以定义一个int 类型的变量来接收这个值,或者强制类型转换,才能达到我们想要的结果。
四、a,b交换
1.There are two int variable:a and b,don't use "if" ," ? : ",switch,or other judgement statementes,
find biggest one of the two numbers?
答案
方案1: int max=((a+b)+abs(a-b))/2;
方案2: int c=a-b;
char *strs[2]={"a大","b大"};
c=unsigned(c) >> {sizeof(int)*8-1};
五、C++与C的关系?
1.在C++程序中调用被C编译后的函数,为什么要加 extern "C" ?
答案:C++中允许函数重载,而在C中不能,函数在C++中编译后和C中不同,所以
C++提供了C连接交换指定符号 extern "c" 是为了解决名字匹配问题.
2.头文件中ifndef/define/endif是干什么用的?
答案:防止该头文件被重复使用.
3. #include<stdio.h>与#include "stdio.h" 有什么区别?
答案:前者是从标准库路径下寻找头文件,而后者是从用户工作路径下寻找头文件
4.如何判断一个程序是由C还是C++编译的?
答案: C++编译时定义了_cplusplus
C编译时定义了_stdc_;
第六章 预处理、const与sizeof
1. 预处理当中的宏定义
注意:有时候宏展开以后会出现二意性问题。所以要注意使用括号。
2. sizeof的总结
sizeof是运算符,它的作用是返回一个类型或变量的长度,长度的单位是字节。
(1)基本数据类型sizeof的结果
平台:Windows XP,32位cpu;
* VC++6.0.
使用.c和.cpp作为文件后缀得到的结果是同样的.(有的程序同样是在VC++6.0下,后缀名不同,用的编译器不同,结果也不同。谭浩强的C语言第二版
上的有个union类型的例题就是这样,用.c就可以编译通过,用.cpp作为后缀,就有错误。)
* Turbo C下的结果是不相同的。int类型是2,long double是10.
(2)结构体的sizeof问题(数据对齐问题)
为了方便对结构体内元素的访问和管理,以结构体里面最长的数据元素的长度为对齐单位,也就是说,结构体的长度一定是最长元素的整数倍。(不
管结构体内的元素是大于还是小于处理器的位数)。这点跟书上的不同。书上的经过VC++验证,反正在VC++下是错的。并且最大的单位就是8个字节,
即使结构体中有其他结构体的变量,也最大是以8个字节为单位对齐的。8字节是基本数据类型中占空间最大的单位。
结构体内小于最长元素的元素,如果是单独的,则占用一个最长单位;如果有几个连续的放在一起的,可以按最长单位顺序存放。知道满了或者剩下
的不够超出为止,即换到下一个最长长度单位。
例1:
struct tagD
{
short d1;
double d2;
short d3;
};
结果为:。以8个字节为单位,不足8的补齐。第一个short占2个,但是后面紧跟着是double占8个字节,所以让第一个short占8个字节,接下来double
再占8个字节。最后一个short一样处理,不足8补成8个字节。
例2
struct tagD
{
double d2;
short d1;
short d3;
};
结果为: 。以8为单位,后面的两个short加起来只占4个,不够8个单位,所以一共是2个8字节,一共是16.
对于结构体中的位运算中的位段,是以4字节,即int所占字节的大小为单位对齐的。如果位段结构体中还有其他类型,那么同样是以最大字节数为对
齐单位。
(3)对类sizeof
1. 空类占1个字节;
2. 类中的成员函数不计算在内,只计算成员变量占多少个字节;
3. 静态成员变量不计算在内,因为静态成员变量存放在全局数据区,而sizeof是计算栈中分配的大小。
4. 如果有虚函数或者纯虚函数的话,不管有多少个,只增加4个字节,这四个字节是虚函数表的指针所占的空间。
5. 多重继承的话也不会增加所占字节数;
6. 虚继承,会增加4个字节。
7. 虚继承有虚函数的类,那么新类增加4+4个字节。如果自己还有虚函数,则再增加4个字节。
8. 但非虚继承有虚函数的类,新类增加4个字节,而且即使自己还有虚函数,也不再增加额外的4个字节。说明它们用的是同一个虚函数表。
(注)以上提及的增加,对于空类来说,只是由1个字节变为,而不是在1上增加。
例:
class A
{
};
class A2
{
};
class B
{
void virtual funB();
};
class B2
{
void virtual funB2()=0;
};
class C: public A
{
};
class D: public virtual A
{
};
class E: public A,public A2
{
};
class F1: public virtual B
{
};
class F2: public virtual B
{
void virtual funf(void); //自己有虚函数,还会再增加4个字节。
};
class G1: public B
{
};
class G2: public B
{
void virtual funH(void); //自己有虚函数,但不增加4个字节。
};
void main(void)
{
cout<<"class A: "< cout<<"class B(have virtual func): "< cout<<"class C(derived from A): "< cout<<"class D(virtual derived from A):
"< cout<<"class E(multiple derived from A and A2): "< cout<<"class F1(virtual derived from B,B have virtual func,F1 don't have
virtual func): "< cout<<"class F2(virtual derived from B,B have virtual func,F2 also have virtual func): "< cout<<"class G1(derived
from B,B have virtual func,G1 don't have virtual func): "< cout<<"class G2(derived from B,B have virtual func,G2 also have virtual
func): "< }
(4)对数组名sizeof(退化为指针的问题)
等于将其元素类型做sizeof的结果×数组元素的个数。
而当数组名作为函数参数时,有个退化的问题。即在函数内部用sizeof(数组名),则得到是一个指针的大小,即4字节,非上面数据类型×数组元素
的个数。
例:
char var[10];
int test(char var[])
{
return sizeof(var);
}
cout<<br /> cout<<br /> 返回的是4,而非10. 运行结果为:
第五章 程序设计基本概念
1.++运算符的顺序问题
#define product(X) (X*X)
void main()
{
int i=3,j,k;
j=product(i++);
k=product(++i);
printf("j=%d,k=%d",j,k);
return
}
结果为j=9;k=49;已经在VC++6.0上验证;
注意:在一个表达式中,同时有1个以上的同一个变量的++运算符,进行+-*/运算的i的值是相同的。如果有++i,则i的值在运算前+1,如果有i++则在
做完运算后才去+1.
2. 类型转换char foo(void){ unsigned int a=6; int b=-20; char c; (a+b>6)?(c=1):(c=0); return c;}结果:返回
值为1.注意:1. 有符号整形与无符号型做运算的时候,有符号整形会自动转换成无符号的。2. 调用函数,实参形参类型不同,自动转换为形参类型
;3. 函数返回值类型与函数类型不同时,转换为函数类型;4. Doulbe ßfloat (ß表示左边类型任何时候都会自动转换成右边的来进行运算)↑
(↑表示混合类型数据进行运算时,数据会自动向上面的类型转换)Long↑Unsigned int↑Int ßchar, short3. a和b求最大值的技巧算法
int max=((a+b)+abs(a-b))/2;注释:a+b再加上它们的差,即为max的两倍,处于2后就是最大的值;4. a和b交换的技巧算法a=a^b; b=a^b; a=a^b;注
释:无须 担心超界的问题。5. 如何判断一段程序是由C编译程序还是有C++编译程序编译的?答案:C++编译时在目标文件中定义了_cplusplus宏; C
编译时定义了_STDC_宏.6. main主函数执行完毕后,再执行一段代码的问题int main(void){ void fn1(void),fn2(void),fn3(void),fn4
(void);atexit(fn1); atexit(fn2); atexit(fn3); atexit(fn4); printf("The main function is running!/n");} void
fn1(void){ printf("next !/n ");}void fn2(void){ printf("executed ");}void fn3(void){ printf("is ");}void fn4(void){
printf("This ");}注释:如果需要加入一段在main退出后执行的代码,可以使用atexit()函数注册一个函数。且先注册的后执行。7. C++程序中
调用被C编译器编译后的函数,要加extern “C”,用来解决名字匹配问题。注释: C++支持函数重载,C不支持。函数被C++和C编译后在库中的名字
不同。