c中,当在printf不是c语句进行算数运算,编译器有创建临时变量操作吗

INTEL C++ COMPILER之常用的编译器选项 | Intel(R) SoftwareC语言基础知识大全_无锡学C语言
重点说明:
1、任何一个c语言程序都必须包括以下格式:
main() { }
这是c语言的基本结构,任何一个程序都必须包含这个结构。括号内可以不写任何内容,那么该程序将不执行任何结果。
2、main()----在c语言中称之为“主函数”,一个c程序有且仅有一个main函数,任何一个c程序总是从main函数开始执行,main函数后面的一对圆括号不能省略。
3、被大括号{ }括起来的内容称为main函数的函数体,这部分内容就是计算机要执行的内容。
4、在{ }里面每一句话后面都有一个分号(;),在c语言中,我们把以一个分号结尾的一句话叫做一个c语言的语句,分号是语句结束的标志。
5、printf(“a=%d,b=%d,sum=%d\n”,a,b,sum); ----通过执行这条c语言系统提供给我们直接使用的屏幕输出函数,用户即可看到运行结果,本程序运行后,将在显示器上显示如下结果:
a=20,b=15,sum=35
6、#include
注意:(1)以#号开头 (2)不以分号结尾 这一行没有分号,所以不是语句,在c语言中称之为命令行,或者叫做“预编译处理命令”。
7、程序中以 /*开头并且以*/结尾的部分表示程序的注释部分,注释可以添加在程序的任何位置,为了提高程序的可读性而添加,但计算机在执行主函数内容时完全忽略注释部分,换而言之就是计算机当做注释部分不存在于主函数中。
C程序的生成过程
C程序是先由源文件经编译生成目标文件,然后经过连接生成可执行文件。
源程序的扩展名为 .c ,目标程序的扩展名为 .obj , 可执行程序的扩展名为 .exe 。
在编写程序时,必须为函数、变量等命名,这个名字称为标识符。C语言中标识符的命名规则如下:
标识符只能由字母、数字、下划线组成;
标识符的第一个字母必须是字母和下划线;
标识符区分大小写字母,如If和if是两个完全不同的标识符。
合法标识符如下: A6, b_3 , _mn 非法的标识符如下: ab#12 , 8m , tr3:4 , yes no
标识符不能与程序中具有特殊意义的关键字相同,不能与用户编制的函数名、C语言库函数相同,在程序中各种标识符尽量不要重复,以便区分。选择变量名和其他标识符时,应注意做到 “见名知义”。
标识符分为如下三类:
关键字是具有特定含义的,专门用来说明c语言特定成分的一类标识符,不能用作用户的标识符。
auto break case char union do double else enum extern goto if int long short signed static sizof struct switch unsigned void for while typedef continue float return typedef default
2、预定义标识符
预定义标识符在c语言中也有特定的含义,但可以用作用户标识符,预定义标识符分为两类:
(1)、库函数名字,比如(printf,scanf,sin,isdigit等) (2)、编译处理命令名,比如(define,include)
3、用户标识符
用户根据需要自己定义的标识符称为用户标识符。无论如何自定义标识符,都必须符合标识符的三条命名规则。
在程序运行中,其值不能被改变的量称为常量。常量有5种类型:整型常量、实型常量、字符常量、字符串常量和符号常量。
(一)数值转换
数字的四种表现形式:
①:二进制:所有数字由0,1构成,逢二进一,二进制数中不会出现2.。 例: ②:八进制:以数字0(注意不是以字母O,o)开头,所有数字由0~7构成,逢八进一,八进制数中不会出现8。 例:7等 ③:十进制:所有数字由0~9构成,逢十进一,十进制数中不会出现10。 例:0,12,-15等 ④:十六进制:以0x或者0X(数字0加字母x)开头,所有数字由0~9,A~F(或者a~f)构成,逢十六进一(其中A、B、C、D、E、F分别代表10、11、12、13、14、15) 例:0x4A、0X14c7等
在计算机内部,数字均以二进制形式表示和存放,用户输入的普通十进制数字都要被计算机转换成二进制才能在计算机内部存储,同样计算机的运算结果也为二进制,一般要将其转换成十进制数再输出给用户阅读,这种转换通常由计算机自动实现。
(1)将十进制转换二进制、八进制和十六进制
除法:将十进制数除以2,记录余数,得到的商继续除以2,直到商为0,然后将各次相处所得的余数从后往前逆序排列,所得余数数字序列就是该十进制数对应的二进制数。八进制和十六进制转换方法同上。
例:十进制数13转换成二进制数的值为1101,转换八进制为015,转换成十六进制为D.
(2)将二进制、八进制和十六进制转换成十进制
乘积求和:将二进制的每一位从低位到高位(右边为低位,左边为高位)分别乘以20,21,22。。。。,然后将这些积求和。
例如:=(13)10 (317)8= (23E)16=
(3)二进制与八进制、十六进制数之间的相互转换
①:二进制转八进制:从右往左每三位一组转换成十进制数,将所得数据组合就是对应的八进制数(注意:高位不足三位补零)。 例:(010 110 111)2=(267)8 ②:二进制转十六进制:从右往左每四位一组转换成十进制数,将所得数据组合就是对应的十六进制数(注意:高位不足四位补零)。 例:()2=(5B)16 ③:八进制转化二进制:每一位数字转换为三位二进制数字 例:(13)8=(001 011)2= (注意:去掉前面的两个00,因为0在高位没有意义) ④:十六进制转化二进制:每一位数字转换为四位二进制数字 例:(E3)16=(
(二)整型常量
整型常量有3种形式:十进制整型常量、八进制整型常量和十六进制整型常量。
(注意:c语言中没有直接表示二进制的整型常量,在c语言源程序中不会出现二进制。)
书写方式如下:
十进制整型常量:123 , 0 ,-24 , 85L(长整型常量) 等 八进制整型常量:051 ,-026 ,0773 等 十六进制整型常量:0x55 , 0x1101 , 0x , 0x5AC0 , -0xFF。 其中L为长整型。
(三)实型常量
实型常量有两种表示形式:小数形式和指数形式。
小数形式:5.4 0.074 -23.0 指数形式:5.4e0 4.3e-3 -3.3e4
(1)小数部分为0的实型常量,可以写为453.0 或453。 (2)用小数表示时,小数点的两边必须有数,不能写成“ .453“和“453.“,而应该写成“0.453“和“453.0“。 (3)用指数写法时,e前必须有数字,e后面的指数必须为整数(注意:整数阶码可以是正数,负数,也可以是八进制数、十六进制数,但必须为整数)。
(四)字符常量
字符常量的标志是一对单引号‘ ’,c语言中的字符常量有两类:
(1)由一对单引号括起来的一个字符,如‘a ’, ‘r’ ,‘#’。注意: ′a′ 和 ′A′ 是两个不同的字符常量。
(2)由一对单引号括起来,以反斜杠\开头,后跟若干数字或者字母,比如‘\n’,其中“\“是转义的意思,后面跟不同的字符表示不同的意思,这类字符常量叫转义字符。具体如图所示 。
转义字符 转义字符的意义 ASCII码
\n 回车换行 10 \t 横向跳到下一制表位置 9 \b 退格 8 \r 回车 13 \f 走纸换页 12 \\ 反斜线符"\" 92 \' 单引号符 39 \” 双引号符 34 \a 鸣铃 7 \ddd 1~3位八进制数所代表的字符 \xhh 1~2位十六进制数所代表的字符
(五)字符串常量
C语言中,以双引号括起来的,由若干个字符组成的序列即为字符串常量。
例:“ni hao” “happy”等等。
(六)符号常量
符号常量是由宏定义“#define“定义的常量,在C程序中可用标识符代表一个常量。
例:计算圆的面积的c程序。
#include #define PI 3. main() { float r,s; r=12.5; S=PI *r*r; printf(“s= %f ”,s); }
#define 是宏定义,此程序中所有出现PI的地方都代表3.,同时PI称为符号常量。习惯上我们用大写字母来表示符号常量,小写字母表示变量,这样比较容易区别。
变量就是其值可以改变的量。变量要有变量名,在内存中占据一定的存储单元,存储单元里存放的是该变量的值。不同类型的变量其存储单元的大小不同,变量在使用前必须定义。
(一)整型变量
整型变量分为4种:基本型(int)、短整型(short int 或short)、长整型(long int 或 long)和无符号型(unsigned int ,unsigned short,unsigned long)。
不同的编译系统对上述四种整型数据所占用的位数和数值范围有不同的规定。
类型说明符
单词signed来说明“有符号”(即有正负数之分),不写signed也隐含说明为有符号,unsigned用来说明“无符号”(只表示正数)。
(二)实型变量
C语言中,实型变量分为单精度类型( float )和双精度类型( double )两种。如:
在vc中,float 型数据在内存中占4个字节(32位),double型数据占8个字节。单精度实数提供7位有效数字,双精度实数提供15~16位有效数字。实型常量不分float型和double型,一个实型常量可以赋给一个float 型或double型变量,但变量根据其类型截取实型常量中相应的有效数字。
注意:实型变量只能存放实型值,不能用整型变量存放实型值,也不能用实型变量存放整型值。
(三)字符变量
字符变量用来存放字符常量,定义形式:
char 变量名;
其中关键字char定义字符型数据类型,占用一个字节的存储单元。
例:char cr1,cr2; cr1= ‘A’ , cr2=‘B’ ;
将一个字符赋给一个字符变量时,并不是将该字符本身存储到内存中,而是将该字符对应的ASCII码存储到内存单元中。例如,字符 ′A′ 的ASCII码为65,在内存中的存放形式如下:0
由于在内存中字符以ASCII码存放,它的存储形式和整数的存储形式类似,所以C语言中字符型数据与整型数据之间可以通用,一个字符能用字符的形式输出,也能用整数的形式输出,字符数据也能进行算术运算,此时相当于对它们的ASCII码进行运算。
类型的自动转换和强制转换
当同一表达式中各数据的类型不同时,编译程序会自动把它们转变成同一类型后再进行计算。转换优先级为:
char & int & float & double
即左边级别“低“的类型向右边转换。具体地说,若在表达式中优先级最高的数据是double型,则此表达式中的其他数据均被转换成double型,且计算结果也是double型;若在表达式中优先级最高的数据是float型,则此表达式中的其他数据均被转换成float型,且计算结果也是float型。
在做赋值运算时,若赋值号左右两边的类型不同,则赋值号右边的类型向左边的类型转换;当右边的类型高于左边的类型时,则在转换时对右边的数据进行截取。
除自动转换外,还有强制转换,表示形式是:
( 类型 )(表达式); 例:(int)(a+b)
讨论:当a值赋值为3.4,b值赋值为2.7,(int)(a+b)和(int)a+b的值分别为多少?
C运算符认识
C语言的运算符范围很广,可分为以下几类:
、算术运算符:用于各类数值运算。包括加(+)、减(-)、乘(*)、除(/)、求余(%)、自增(++)、自减(--)共七种。
、赋值运算符:用于赋值运算,分为简单赋值(=)、复合算术赋值(+=,-=,*=,/=,%=)和复合位运算赋值(&=,|=,^=,&&=,&&=)三类共十一种。 &="" span=""&
、逗号运算符:用于把若干表达式组合成一个表达式(,)。
、关系运算符:用于比较运算。包括大于(&)、小于(&)、等于(==)、 大于等于(=""&=)、小于等于(&=)和不等于(!=)六种。 &="" span=""&
、逻辑运算符:用于逻辑运算。包括与(&&)、或(||)、非(!)三种。
、条件运算符:这是一个三目运算符,用于条件求值(?:)。
、位操作运算符:参与运算的量,按二进制位进行运算。包括位与(&)、位或(|)、位非(~)、位异或(^)、左移(&&)、右移(&&)六种。
8、指针运算符:用于取内容(*)和取地址(&)二种运算。
9、求字节数运算符:用于计算数据类型所占的字节数(sizeof)。
10、特殊运算符:有括号(),下标[],成员(→,.)等几种。
另外,按参与运算的对象个数,C语言运算符可分为:单目运算符 (如 !)、双目运算符 (如+,- )和三目运算符 (如 ? : )。
算术运算符和算术表达式
一、 基本的算术运算符
(1)+(加法运算符或正值运算符,如2+5)。
(2)-(减法运算符或负值运算符,如4-2)。
(3)*(乘法运算符,如3*8)。
(4)/(除法运算符,如11/5)。
/的运算分为两种情况:
a、“除”的左右两边都为整数时,所得结果必然是整数(注意:仅取整数部分,不是四舍五入)
比如:5/2的值为2,不是2.5,1/2的值为0。
b、“除”的左右两边至少有一个是实型数据(即小数)时,所得结果为实型数据。
比如:5/2.0的值为2.5,7.0/2.0的值为3.5.
(5)%(模运算符或称求余运算符,%两侧均应为整型数据,如9%7的值为2)。
需要说明的是:当运算对象为负数时,所得结果随编译器不同而不同,在vc中,结果的符号与被除数相同,比如:13%-2值为1,而-15%2值为-1。
二、 算术表达式和运算符的优先级与结合性
算术表达式是用算术运算符和括号将运算量(也称操作数)连接起来的、符合C语言语法规则的表达式。运算对象包括函数、常量和变量等。
在计算机语言中,算术表达式的求值规律与数学中的四则运算的规律类似,其运算规则和要求如下。
(1)在算术表达式中,可使用多层圆括号,但括号必须配对。运算时从内层圆括号开始,由内向外依次计算各表达式的值。
(2)在算术表达式中,对于不同优先级的运算符,可按运算符的优先级由高到低进行运算,若表达式中运算符的优先级相同,则按运算符的结合方向进行运算。
(3)如果一个运算符两侧的操作数类型不同,则先利用自动转换或强制类型转换,使两者具有相同类型,然后进行运算。
三、 自增自减运算符
作用:使变量的值增1或减1。
如:++i,--i (在使用i之前,先使i的值加1、减1)。 i++,i-- (在使用i之后,使i的值加1、减1)。
(1)只有变量才能用自增运算符 (++)和自减运算符(--),而常量或表达式不能用,如10++或(x+y)++都是不合法的。
(2)++和--的结合方向是“自右向左“,如 -i++ ,i的左边是负号运算符,右边是自增运算符,负号运算和自增运算都是 “自右向左“结合的,相当于 -(i++)。
在循环语句中常用到自增(减)运算符,在指针中也常用到该运算符,考生要弄清楚“i++”和“++i”及“i--”和“--i”的区别,特别弄清楚表达式的值和变量的值。
赋值运算符与赋值表达式
一、赋值运算符与赋值表达式
赋值符号 “=“就是赋值运算符,作用是将一个数据赋给一个变量或将一个变量的值赋给另一个变量,由赋值运算符组成的表达式称为赋值表达式。一般形式为:
变量名 = 表达式
在程序中可以多次给一个变量赋值,每赋一次值,与它相应的存储单元中的数据就被更新一次,内存中当前的数据就是最后一次所赋值的那个数据。
例:a=12; 此表达式读作“将10的值赋值给变量a”。
a、如果赋值号两边的运算对象类型不一致,系统会自动进行类型转换,转换的规则:将赋值号右边表达式的值的类型转换成赋值号左边变量的类型,
例:int y=3.5; 在变量y中最终存储的是整数3。
b、 可以将复制表达式的值再赋值给变量,形成连续赋值。
例如:x=y=25 是一个连续赋值表达式,x=y=25 等价于x=(y=25),所以表达式x=y=25 最终的值为25 。
二、复合的赋值运算符
在赋值运算符之前加上其他运算符可以构成复合赋值运算符。其中与算术运算有关的复合运算符是:+=,-=,*=,/=,%= 。
两个符号之间不可以有空格,复合赋值运算符的优先级与赋值运算符的相同。表达式n+=1等价于n=n+1,作用是取变量n中的值增1再赋给变量n,其他复合的赋值运算符的运算规则依次类推。
如求表达a+=a-=a*a 的值,其中a的初值为12 。
(1)先进行“a-=a*a“运算,相当于a=a-a*a=12-144=-132 。 (2)再进行“a+=-132“运算,相当于 a=a+(-132)==-264 。
逗号运算符和逗号表达式
在c语言中,逗号除了作为分隔符,还可以用作一种运算符----逗号运算符,用逗号运算符将几个表达式连接起来,例如a=b+c,a=b*c等称为逗号表达式。
一般形式为:
表达式1 ,表达式2 ,表达式3 , …,表达式n
例:x=2,y=3,z=4
逗号表达式具有从左至右的结合性,即先求解表达式1,然后依次求解表达式2,直到表达式n的值。表达式n的值就是整个逗号表达式的值。上述的逗号表达式的值就是表达式z=4的值4.需要注意的是,逗号运算符是所有运算符中级别最低的。
例:有如下程序段:
main() { int a=2,b=4,c=6,x,y; y=(x=a+b),(b+c); printf("y=%d,x=%d",y,x); }
程序显示结果为:y=6,x=6
讨论:将y=(x=a+b),(b+c);改为y=((x=a+b),b+c) 的程序结果?
关系运算符和关系表达式
一、 C语言中的逻辑值
C语言中的逻辑值只有两个:真(true)和假(flase)。用非零代表真,用零代表假。因此,对于任意一个表达式,如果它的值为零,就代表一个假值,如果它的值为非零,就代表一个真值。只要值不是零,不管是正数,负数,整数,实数,都代表一个真值。例如-5的逻辑值为真。
二、 逻辑表达式
“&&”和“||”的运算对象有两个,故它们都是双目运算符,而!的运算对象只有一个,因此它是单目运算符。逻辑运算举例如下:
(1)a&&b: 当&&两边都为“真”时,表达式a&&b的值才是真。
值得注意的是:在数学中,关系式0
(2)a||b: 当||两边有一个为“真”时,表达式a||b的值就是真。
(3)!a: 表示取反,如果a为真,则!A为假,反之亦然。例如!-5的值就为0.
在C语言中,由&&或||组成的逻辑表达式,在某些特定情况下会产生“短路“现象。
(1)x && y && z ,只有当x为真(非0)时,才需要判别y的值;只有x和y都为真时,才需要去判别z的值;只要x为假就不必判别y和z,整个表达式的值为0。口诀:“一假必假”。
例:(!5==1)&&(++i==0) (!5==1)表达式的值为0,所以计算机运行中就跳过(++i==0)此表达式,(!5==1)&&(++i==0)表达式的值为0.
(2)x||y||z ,只要x的值为真(非零),就不必判别y和z的值 ,整个表达式的值为1,只有x的值为假,才需要判别y的值,只有x和y的值同时为假才需要判别z的值,口诀:“一真必真”。
一、 位运算符
在计算机中,数据都是以二进制数形式存放的,位运算就是指对存储单元中二进制位的运算。C语言提供6种位运算符。
二、位运算
位运算符 & |~&& && ∧ 按优先级从高到低排列的顺序是:
位运算符中求反运算“~“优先级最高,而左移和右移相同,居于第二,接下来的顺序是按位与 “&“、按位异或 “∧“和按位或 “|“。顺序为~ && && & ∧ | 。
例1:左移运算符“&&”是双目运算符。其功能把“&& ”左边的运算数的各二进位全部左移若干位,由“&&”右边的数指定移动的位数,高位丢弃,低位补0。="" &="" span=""&
例如: a&&4 指把a的各二进位向左移动4位。如a=(十进制3),左移4位后为00(十进制48)。
例2:右移运算符“&&”是双目运算符。其功能是把“&& ”左边的运算数的各二进位全部右移若干位,“&&”右边的数指定移动的位数。
例如: 设 a=15, a&&2 表示把右移为十进制3)。
应该说明的是,对于有符号数,在右移时,符号位将随同移动。当为正数时,最高位补0,而为负数时,符号位为1,最高位是补0或是补1 取决于编译系统的规定。
例3:设二进制数a是00 ,若通过异或运算a∧b 使a的高4位取反,低4位不变,则二进制数b是。
解析:异或运算常用来使特定位翻转,只要使需翻转的位与1进行异或操作就可以了,因为原数中值为1的位与1进行异或运算得0 ,原数中值为0的位与1进行异或运算结果得1。而与0进行异或的位将保持原值。异或运算还可用来交换两个值,不用临时变量。
如 int a=3 , b=4;,想将a与b的值互换,可用如下语句实现: a=a∧b;
所以本题的答案为: 。
C语言作为一门非常适合编程入门的语言,打好基础的重要性不言而喻。
学习地址:无锡市兴源北路401号北创科技园550
责任编辑:
声明:该文观点仅代表作者本人,搜狐号系信息发布平台,搜狐仅提供信息存储空间服务。
今日搜狐热点原文地址:
这些东西有点烦,有点无聊。如果要去C++面试就看看吧。几年前网上搜索的。刚才看到,就整理一下,里面有些被我改了,感觉之前说的不对或不完善。
1.求下面函数的返回值( 微软)
int func(x) {
int countx = 0;
countx ++;
x = x&(x-1);
假定x = 9999。 答案:8
思路:将x转化为2进制,看含有的1的个数。
2.&什么是&引用&?申明和使用&引用&要注意哪些问题?
答:引用就是某个目标变量的&别名&(alias),对应用的操作与对变量直接操作效果完全相同。申明一个引用的时候,切记要对其进行初始化。引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,不能再把该引用名作为其他变量名的别名。声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。不能建立数组的引用。
3.&将&引用&作为函数参数有哪些特点?
(1)传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。
(2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。
(3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。
4.&在什么时候需要使用&常引用&? 
如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。常引用声明方式:const&类型标识符 &引用名=目标变量名;
intconst int &ra = a;ra = 1; // 错误a = 1;
string foo( );void bar(string &s)// 那么下面的表达式将是非法的:bar(foo( ));bar("hello world");
原因在于foo( )和"hello world"串都会产生一个临时对象,而在C++中,这些临时对象都是const类型的。因此上面的表达式就是试图将一个const类型的对象转换为非const类型,这是非法的。
引用型参数应该在能被定义为const的情况下,尽量定义为const 。
5. 将&引用&作为函数返回值类型的格式、好处和需要遵守的规则?
类型标识符 &函数名(形参列表及类型说明){   //函数体}
好处:在内存中不产生被返回值的副本;(注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的。因为随着该局部变量生存期的结束,相应的引用也会失效,产生runtime error!
(1)不能返回局部变量的引用。这条可以参照Effective C++[1]的Item 31。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态。
(2)不能返回函数内部new分配的内存的引用(这个要注意啦,很多人没意识到,哈哈。。。)。 这条可以参照Effective C++[1]的Item 31。虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak。
(3)可以返回类成员的引用,但最好是const。 这条原则可以参照Effective C++[1]的Item 30。主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。
(4)流操作符重载返回值申明为&引用&的作用:
流操作符&&和&&,这两个操作符常常希望被连续使用,例如:cout &&"hello" && 因此这两个操作符的返回值应该是一个仍然支持这两个操作符的流引用。可选的其它方案包括:返回一个流对象和返回一个流对象指针。但是对于返回一个流对象,程序必须重新(拷贝)构造一个新的流对象,也就是说,连续的两个&&操作符实际上是针对不同对象的!这无法让人接受。对于返回一个流指针则不能连续使用&&操作符。 因此,返回一个流对象引用是惟一选择。这个唯一选择很关键,它说明了引用的重要性以及无可替代性,也许这就是C++语言中引入引用这个概念的原因吧。 赋值操作符=。这个操作符象流操作符一样,是可以连续使用的,例如:x = j = 10;或者(x=10)=100;赋值操作符的返回值必须是一个左值,以便可以被继续赋值。因此引用成了这个操作符的惟一返回值选择。
#include &iostream.h&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 && vals[0];  cout && vals[9];}
int &put(int n){  if (n&=0 && n&=9 )&
&    return vals[n];&
    cout && "subscript error";&
&    return
(5)在另外的一些操作符中,却千万不能返回引用:+-*/ 四则运算符。它们不能返回引用,Effective C++[1]的Item23详细的讨论了这个问题。主要原因是这四个操作符没有side effect,因此,它们必须构造一个对象作为返回值,可选的方案包括:返回一个对象、返回一个局部变量的引用,返回一个new分配的对象的引用、返回一 个静态对象引用。根据前面提到的引用作为返回值的三个规则,第2、3两个方案都被否决了。静态对象的引用又因为((a+b) == (c+d))会永远为true而导致错误。所以可选的只剩下返回一个对象了。
6. &引用&与多态的关系?
引用是除指针外另一个可以产生多态效果的手段。这意味着,一个基类的引用可以指向它的派生类实例(见:)。
Class A; Class B : Class A{  // ...};
7. &引用&与指针的区别是什么?
指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;
而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。此外,就是上面提到的对函数传ref和pointer的区别。
8.&什么时候需要&引用&?
流操作符&&和&&、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、其它情况都推荐使用引用。
9.&结构与联合有和区别?1. 结构和联合都是由多个不同的数据类型成员组成, 但在任何同一时刻, 联合中只存放了一个被选中的成员(所有成员共用一块地址空间), 而结构的所有成员都存在(不同成员的存放地址不同)。&2. 对于联合的不同成员赋值, 将会对其它成员重写,&原来成员的值就不存在了, 而对于结构的不同成员赋值是互不影响的。
10.&下面关于&联合&的题目的输出?
#include &stdio.h&union{  int  char x[2];}a;void main(){  a.x[0] = 10;   a.x[1] = 1;  printf("%d",a.i);}
答案:266 (低位低地址,高位高地址,内存占用情况是Ox010A)
/*定义一个联合*/
/*在联合中定义一个结构*/
number.i=0x4241;
/*联合成员赋值*/
printf("%c%c\n", number.half.first, mumber.half.second);
number.half.first='a';
/*联合中结构成员赋值*/
number.half.second='b';
printf("%x\n",number.i);
答案: AB&& (0x41对应'A',是低位;Ox42对应'B',是高位)
&&&&&&&6261 (number.i和number.half共用一块地址空间)
11.&已知strcpy的函数原型:char *strcpy(char *strDest, const char *strSrc)其中strDest 是目的字符串,strSrc 是源字符串。不调用C++/C 的字符串库函数,请编写函数 strcpy。
/*编写strcpy函数(10分)已知strcpy函数的原型是
char *strcpy(char *strDest, const char *strSrc);
其中strDest是目的字符串,strSrc是源字符串。(1)不调用C++/C的字符串库函数,请编写函数 strcpy(2)strcpy能把strSrc的内容复制到strDest,为什么还要char * 类型的返回值?答:为了 实现链式表达式。
// 2分例如
int length = strlen( strcpy( strDest, &hello world&) );*/#include &assert.h&#include &stdio.h&char *strcpy(char *strDest, const char *strSrc){
assert((strDest!=NULL) && (strSrc !=NULL));
char* address = strD
  // 2分
while( (*strDest++ = *strSrc++) != '\0' )       // 2分
   // 2分}
另外strlen函数如下:
#include&stdio.h&#include&assert.h& int strlen( const char *str )
// 输入参数const{
assert( str != NULL );
// 断言字符串地址非0
int len = 0;
while( (*str++) != '\0' )
12. 已知String类定义如下:
class String{public:  String(const char *str = NULL); // 通用构造函数  String(const String &another);
// 拷贝构造函数  ~String(); // 析构函数  String& operater =(const String &rhs); // 赋值函数private:  char* m_ // 用于保存字符串};
尝试写出类的成员函数实现。
String::String(const char *str){
if ( str == NULL ) // strlen在参数为NULL时会抛异常才会有这步判断
m_data = new char[1] ;
m_data[0] = '\0' ;
m_data = new char[strlen(str) + 1];
strcpy(m_data,str);
}} String::String(const String &another){
m_data = new char[strlen(another.m_data) + 1];
strcpy(m_data,other.m_data);}String& String::operator =(const String &rhs){
if ( this == &rhs)
return *this ;
delete []m_ //删除原来的数据,新开一块内存
m_data = new char[strlen(rhs.m_data) + 1];
strcpy(m_data,rhs.m_data);
return *this ;}String::~String(){
delete []m_}
13. .h头文件中的ifndef/define/endif 的作用?
答:防止该头文件被重复引用。
14.&#include&file.h& 与#include "file.h"的区别?
答:前者是从Standard Library的路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h。
15.在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_Hint foo( int x, int y );#endif  
在模块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_Hextern "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函数例子工程中包含的三个文件的源代码如下:
/* c语言头文件:cExample.h */#ifndef C_EXAMPLE_H#define C_EXAMPLE_Hextern int add(int x, int y);#endif
/* c语言实现文件:cExample.c */#include "cExample.h"int add( int x, int y ){  return x +}
// c++实现文件,调用add:cppFile.cppextern"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_Hextern "C" int add( int x, int y );#endif
//C++实现文件 cppExample.cpp#include"cppExample.h"int add( int x, int y ){  return x +}
/* C实现文件 cFile.c/* 这样会编译出错:#i nclude "cExample.h" */extern int add( int x, int y );int main( int argc, char* argv[] ){  add( 2, 3 );   return 0;}
16.&关联、聚合(Aggregation)以及组合(Composition)的区别?
涉及到UML中的一些概念:
关联是表示两个类的一般性联系,比如&学生&和&老师&就是一种关联关系;
聚合表示has-a的关系,是一种相对松散的关系,聚合类不需要对被聚合类负责,如下图所示,用空的菱形表示聚合关系:
从实现的角度讲,聚合可以表示为:
class A {...}& class B { A* .....}
组合表示contains-a的关系,关联性强于聚合:组合类与被组合类有相同的生命周期,组合类要对被组合类负责,采用实心的菱形表示组合关系:
实现的形式是:
class A{...} class B{ A ...}
17.面向对象的三个基本特征,并简单叙述之?
1.&封装:将客观事物抽象成类,每个类对自身的数据和方法实行protection(private, protected,public)
2.&继承:广义的继承有三种实现形式:实现继承(指使用基类的属性和方法而无需额外编码的能力)、可视继承(子窗体使用父窗体的外观和实现代码)、接口继承(仅使用属性和方法,实现滞后到子类实现)。前两种(类继承)和后一种(对象组合=&接口继承以及纯虚函数)构成了功能复用的两种方式。
3.&多态:系统能够在运行时,能够根据其类型确定调用哪个重载的成员函数的能力,称为多态性。(见:)
18.&重载(overload)和重写(overried,有的书也叫做&覆盖&)的区别?
常考的题目。
从定义上来说:
重载:是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。
重写:是指子类重新定义父类虚函数的方法。
从实现原理上来说:
重载:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。如,有两个同名函数:function func(p:integer):和function func(p:string):。那么编译器做过修饰后的函数名称可能是这样的:int_func、str_func。对于这两个函数的调用,在编译器间就已经确定了,是静态的。也就是说,它们的地址在编译期就绑定了(早绑定),因此,重载和多态无关!
重写:和多态真正相关。当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的(晚绑定)。
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&与mallocfree&的联系与区别?答案:都是在堆(heap)上进行动态的内存操作。用malloc函数需要指定内存分配的字节数并且不能初始化对象,new 会自动调用对象的构造函数。delete 会调用对象的destructor,而free 不会调用对象的destructor.
(可以看看:)
22.&#define DOUBLE(x) x+x&,i = 5*DOUBLE(5);&i&是多少?答案:i 为30。(注意直接展开就是了) 5 * 5 + 5&
23.&有哪几种情况只能用intializationlist&而不能用assignment?
答案:当类中含有const、reference 成员变量;基类的构造函数都需要初始化表。
24.&C++是不是类型安全的?答案:不是。两个不同类型的指针之间可以强制转换(用reinterpret cast)。C#是类型安全的。
25.&main&函数执行以前,还会执行什么代码?答案:全局对象的构造函数会在main 函数之前执行,为malloc分配必要的资源,等等。
26.&描述内存分配方式以及它们的区别?1)&从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static&变量。2)&在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集。3)&从堆上分配,亦称动态内存分配。程序在运行的时候用malloc 或new 申请任意多少的内存,程序员自己负责在何时用free 或delete 释放内存。动态内存的生存期由程序员决定,使用非常灵活,但问题也最多。
4) 代码区。
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种类型转换方式?
重点是static_cast, dynamic_cast和reinterpret_cast的区别和应用。(以后再补上吧)
31.分别写出BOOL,int,float,指针类型的变量a&与&零&的比较语句。答案:
 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&常量进行调试,但是不能对宏常量进行调试。
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 =cout&& sizeof(a) && // 12 字节cout&& sizeof(p) && // 4 字节
计算数组和指针的内存容量
void Func(char a[100]){  cout&& sizeof(a) && // 4 字节而不是100 字节}
34.类成员函数的重载、覆盖和隐藏区别?答案:a.成员函数被重载的特征:(1)相同的范围(在同一个类中);(2)函数名字相同;(3)参数不同;(4)virtual 关键字可有可无。b.覆盖是指派生类函数覆盖基类函数,特征是:(1)不同的范围(分别位于派生类与基类);(2)函数名字相同;(3)参数相同;(4)基类函数必须有virtual 关键字。c.&隐藏&是指派生类的函数屏蔽了与其同名的基类函数,规则如下:(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)
35. There are twoint variables: a and b, don&t use &if&, &? :&, &switch&or other judgementstatements, 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 );  _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 whenthe program terminates normally. Successive calls to _onexit create a registerof functions that are executed in LIFO (last-in-first-out) order. The functionspassed to _onexit cannot take parameters.
38.&如何判断一段程序是由C&编译程序还是由C++编译程序编译的?答案:
#ifdef __cplusplus  cout&&"c++";#else  cout&&"c";#endif
注意,后面很多代码啊。代码不看也罢。
39.文件中有一组整数,要求排序后输出到另一个文件中(面试官,超级喜欢考排序的。你要去面试,数据结构的那几个排序一定要非常熟悉,用笔也可以写出代码来,用笔写代码,就是这样变态啊,其实感觉没有必要这样笔试)答案:
#include&iostream&#include&fstream&using namespacevoid Order(vector&int&& data)//bubble sort{int count = data.size() ;int tag = false ; // 设置是否需要继续冒泡的标志位for ( int i = 0 ; i & 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] =}}if ( !tag )break ;}}void main( void ){vector&int&ifstream in("c:\\data.txt");if ( !in){cout&&"file error!";exit(1);}intwhile (!in.eof()){in&&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[i]&&" ";out.close(); //关闭输出文件流}
40. 链表题:一个链表的结点结构
struct Node{intNode *};typedef struct Node N
(1)已知链表的头结点head,写一个函数把这个链表逆序&( Intel)
Node * ReverseList(Node *head) //链表逆序{if ( head == NULL || head-&next == NULL )returnNode *p1 =Node *p2 = p1-&Node *p3 = p2-&p1-&next = NULL ;while ( p3 != NULL ){p2-&next = p1 ;p1 = p2 ;p2 = p3 ;p3 = p3-&}p2-&next = p1 ;head = p2 ;return}
(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-&p2 = head2 ;}else{head = head2 ;p2 = head2-&p1 = head1 ;}Node *pcurrent =while ( p1 != NULL && p2 != NULL){if ( p1-&data &= p2-&data ){pcurrent-&next = p1 ;pcurrent = p1 ;p1 = p1-&}else{pcurrent-&next = p2 ;pcurrent = p2 ;p2 = p2-&}}if ( p1 != NULL )pcurrent-&next = p1 ;if ( p2 != NULL )pcurrent-&next = p2 ;return}
(3)已知两个链表head1&和head2&各自有序,请把它们合并成一个链表依然有序,这次要求用递归方法进行。(Autodesk)答案:
Node * MergeRecursive(Node *head1 , Node *head2){if ( head1 == NULL )return head2 ;if ( head2 == NULL)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}
41.&分析一下这段程序的输出(Autodesk)
class B{public:B(){cout&&"default constructor"&&}~B(){cout&&"destructed"&&}B(int i):data(i)
//B(int) works as a converter ( int -&instance of
B){cout&&"constructed by parameter " && data &&}private:int};B Play( B b) {return}(1)
results:int main(int argc, char* argv[])
constructedby 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[])
constructedby parameter 5{
destructed
B(5)形参析构B t1 = Play(5); B t2 = Play(10);
  constructed by parameter 10return 0;               destructed
B(10)形参析构}
destructed
t2 注意顺序!
destructed
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 & i++){if ( data[i] & maxnumber ){sec_max =maxnumber = data[i] ;}else{if ( data[i] & sec_max )sec_max = data[i] ;}}return sec_}
43.&写一个在一个字符串(n)中寻找一个子串(m)第一个位置的函数。
KMP算法效率最好,时间复杂度是O(n+m)。
44.&多重继承的内存分配问题:&&&比如有class A : public class B, public classC {}&&&那么A的内存结构大致是怎么样的?
这个是compiler-dependent的, 不同的实现其细节可能不同。如果不考虑有虚函数、虚继承的话就相当简单;否则的话,相当复杂。可以参考《深入探索C++对象模型》
45.&如何判断一个单链表是有环的?(注意不能用标志位,最多只能用两个额外指针)
struct node { char node*}
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-&
while(fast!=NULL && fast-&next!=NULL)
fast=fast-&next-&
if(low==fast) return true;
return false;}
阅读(...) 评论()}

我要回帖

更多关于 printf中自增运算符怎么运算 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信