1、
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#include <iostream>
using
namespace
std;
struct
SimpleType
{
double
db;
char
sz;
int
n;
};
void
main()
{
SimpleType a;
int
nSize =
sizeof
(a);
cout<<nSize<<endl;
}
//输出:nSize = 16
|
解析:这里nSize的值并非13,而是16。这设计结构体的字节对齐问题。编译器在为结构体变量分配空间时,保证下一个成员的偏移量应为该成员数据类型长度的整数倍。首先为db 成员分配空间,假设起始偏移位置从0开始,db 成员将占用0,1,2,3,4,5,6,7共8字节。接下来为成员变量sz 分配空间,由于char 类型占用1字节,sz 将占据8的位置,因为当前位置8与1是整除的。最后为n 成员分配空间,该成员为int 类型,占用4字节。当前偏移位置为9,并不是4的整数倍,因此需要空出3字节(9、10、11),n 从12的位置开始分配4字节的空间。这样就导致了实际分配的大小与“理论上”的大小不一致。
2、
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#include <iostream>
using
namespace
std;
void
OutputString(
char
data[])
{
int
iSize =
sizeof
(data);
cout<<
"iSize = "
<<iSize<<endl;
}
void
main()
{
int
iLen =
sizeof
(
"家园"
);
cout<<
"'家园'的大小为:"
<<iLen<<endl;
OutputString(
"家园"
);
}
//输出:
//'家园'的大小为:5
//iSize = 4
|
解析:作为参数传递的数组其实是以指针的形式传递的,所以在使用sizeof获得数组参数的长度时是4,而不是数字长度。
3、
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#include <iostream>
using
namespace
std;
void
main()
{
int
i = 2;
cout<<(i = 3 * 5, 2 * 4)<<endl;
cout<<i<<endl;
int
x = 9, y = 7;
int
n = x > y ? (x-y):(x+y);
//三目元表达式
cout<<n<<endl;
}
//输出:
//8
//15
//2
|
解析:因为赋值运算符的优先级比逗号运算符的优先级高,所以在上面的代码中,会先计算赋值表达式的值,也就是i=3*5,然后再计算逗号表达式的值,所以 i 的值为15,而逗号表达式的值却是8.
又因为条件运算符的优先级高于赋值运算符,所以会先计算 x>y 的值,然后执行符合条件的表达式(x-y),最后将结果赋值给n。
4、x=x+1、x+=1、++ x 、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)y = x;
(2)x += 1;
(3)return y;
++ x 的效率最高,其执行过程为:
(1)读取右x的地址;
(2)x自增1。
5、
1
2
3
4
5
6
7
8
|
int
i=1, j=2, k=3, d=4;
cout<<i+++j<<endl;
//输出:3,先(i++),再(+j),++比+优先级高
cout<<(++k)*(++k)<<endl;
//输出:20,先k自加1等于4,再k自加1等于5,然后4*5=20
(d++)*(d++);
cout<<d<<endl;
//输出:6
!i && j++;
cout<<i<<endl<<j<<endl;
//输出:2 3,因为!i运算结束后,整个表达式已肯定为假,所以不必再去计算后面的式子
|
6、if("A" == a) 比 if(a == "A") 更好,因为如果把”==“误写成”=“,编译器就能检查到错误,因为编译器不允许对常量进行赋值。
7、自动转换遵循以下规则:
1)若参与运算量的类型不同,则先转换成同一类型,然后进行运算。
2)转换按数据长度增加的方向进行,以保证精度不降低。如int型和long型运算时,先把int量转成long型后再进行运算。
a.若两种类型的字节数不同,转换成字节数高的类型
b.若两种类型的字节数相同,且一种有符号,一种无符号,则转换成无符号类型
3)所有的浮点运算都是以双精度进行的,即使仅含float单精度量运算的表达式,也要先转换成double型,再作运算。
4)char型和short型参与运算时,必须先转换成int型。
5)在赋值运算中,赋值号两边量的数据类型不同时,赋值号右边量的类型将转换为左边量的类型。如果右边量的数据类型长度左边长时,将丢失一部分数据,这样会降低精度,丢失的部分按四舍五入向前舍入。
扩展:
(1). 在表达式中,char 和 short 类型的值,无论有符号还是无符号,都会自动转换成 int 或者 unsigned int(如果 short 的大小和 int 一样,unsigned short 的表示范围就大于 int,在这种情况下,unsigned short 被转换成 unsigned int)。因为它们被转换成表示范围更大的类型,故而把这种转换称为“升级(promotion)”。
(2). 按照从高到低的顺序给各种数据类型分等级,依次为:long double, double, float, unsigned long long, long long, unsigned long, long, unsigned int 和 int。这里有一个小小的例外,如果 long 和 int 大小相同,则 unsigned int 的等级应位于 long 之上。char 和 short 并没有出现于这个等级列表,是因为它们应该已经被升级成了 int 或者 unsigned int。
(3). 在任何涉及两种数据类型的操作中,它们之间等级较低的类型会被转换成等级较高的类型。
(4). 在赋值语句中,= 右边的值在赋予 = 左边的变量之前,首先要将右边的值的数据类型转换成左边变量的类型。也就是说,左边变量是什么数据类型,右边的值就要转换成什么数据类型的值。这个过程可能导致右边的值的类型升级,也可能导致其类型降级(demotion)。所谓“降级”,是指等级较高的类型被转换成等级较低的类型。
5. 作为参数传递给函数时,char 和 short 会被转换成 int,float 会被转换成 double。使用函数原型可以避免这种自动升级。
8、交换两个数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
//方法一:
temp = a;
a = b;
b = temp;
//方式二:
a = a + b;
b = a - b;
a = a - b;
//方式三:(推荐)
a = a ^ b;
b = a ^ b;
a = a ^ b;
|
9、在C++中调用被C编译器编译后的函数,为什么要加 extern "c"?
答:C++语言支持函数重载,C语言不支持函数重载,函数被C++编译后在库中的名字与C语言的不同。假设某个函数的名称为:void fun(int x, int y),该函数被C编译器编译后在库中的名字为_fun,而C++编译器则会产生像_fun_int_int之类的名字。C++提供了C连接交换指定符号extern ”C“解决名字匹配问题。
10、
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
#include <iostream>
#include <cstring>
using
namespace
std;
class
A
{
};
class
B
{
char
a, b;
B();
~B();
};
struct
C
{
};
struct
D
{
int
a;
char
b;
};
struct
E
{
long
a1;
short
a2;
};
struct
F
{
int
a;
static
int
b;
};
int
main()
{
A *p1=
new
A();
A p2;
A *p3;
char
*ss1 =
"0123456789"
;
char
ss2[] =
"0123456789"
;
char
ss3[100] =
"0123456789"
;
int
ss4[100];
char
q1[] =
"ABCDEF"
;
char
q2[] =
"a\n"
;
char
*q3 =
"a\n"
;
string x[] = {
"aaa"
,
"bbb"
,
"ccc"
};
void
*i;
char
*str1 = (
char
*)
malloc
(100);
void
*str2 = (
void
*)
malloc
(100);
cout<<
"sizeof(p1): "
<<
sizeof
(p1)<<endl;
cout<<
"sizeof(p2): "
<<
sizeof
(p2)<<endl;
cout<<
"sizeof(p3): "
<<
sizeof
(p3)<<endl;
cout<<
"sizeof(ss1): "
<<
sizeof
(ss1)<<endl;
cout<<
"sizeof(*ss1): "
<<
sizeof
(*ss1)<<endl;
cout<<
"sizeof(ss2): "
<<
sizeof
(ss2)<<endl;
cout<<
"sizeof(ss3): "
<<
sizeof
(ss3)<<endl;
cout<<
"sizeof(ss4): "
<<
sizeof
(ss4)<<endl;
cout<<
"sizeof(q1): "
<<
sizeof
(q1)<<endl;
cout<<
"sizeof(q2): "
<<
sizeof
(q2)<<endl;
cout<<
"sizeof(q3): "
<<
sizeof
(q3)<<endl;
cout<<
"sizeof(x): "
<<
sizeof
(x)<<endl;
cout<<
"sizeof(A): "
<<
sizeof
(A)<<endl;
cout<<
"sizeof(B): "
<<
sizeof
(B)<<endl;
cout<<
"sizeof(C): "
<<
sizeof
(C)<<endl;
cout<<
"sizeof(D): "
<<
sizeof
(D)<<endl;
cout<<
"sizeof(E): "
<<
sizeof
(E)<<endl;
cout<<
"sizeof(F): "
<<
sizeof
(F)<<endl;
cout<<
"sizeof(str1): "
<<
sizeof
(str1)<<endl;
cout<<
"sizeof(str2): "
<<
sizeof
(str2)<<endl;
cout<<
"sizeof("
"): "
<<
sizeof
(
""
)<<endl;
cout<<
"sizeof(\"明\"): "
<<
sizeof
(
"明"
)<<endl;
cout<<
"sizeof(i): "
<<
sizeof
(i)<<endl;
}
/*输出:
sizeof(p1): 4
sizeof(p2): 1
sizeof(p3): 4
sizeof(ss1): 4
sizeof(*ss1): 1
sizeof(ss2): 11
sizeof(ss3): 100
sizeof(ss4): 400
sizeof(q1): 7
sizeof(q2): 3
sizeof(q3): 4
sizeof(x): 48
sizeof(A): 1
sizeof(B): 2
sizeof(C): 1
sizeof(D): 8
sizeof(E): 8
sizeof(F): 4
sizeof(str1): 4
sizeof(str2): 4
sizeof(): 1
sizeof("明"): 3
sizeof(i): 4
*/
|
解析:
空类所占空间为1,单一继承的空类也为1,多继承的空类还是1,但虚继承涉及到虚表(虚指针),其所占空间为4.
11、类中的this指针有以下特点:
(1)this只能在成员函数中使用,在全局函数、静态函数中都不能使用this;
(2)this在成员函数的开始前构造,在成员函数结束后清除;
12、C++中有了malloc/free,为什么还要new/delete?
答:malloc和free是C++/C语言的标准库函数,new和delete是C++的运算符。对于非内部数据类型的对象而言,光用malloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于new/delete。因此C++需要一个能够完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的delete。
13、
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
#include <iostream>
using
namespace
std;
class
A
{
public
:
virtual
f()
{
cout<<
"A"
<<endl;
}
};
class
B :
public
A
{
public
:
virtual
f()
{
cout<<
"B"
<<endl;
}
};
void
main()
{
A* pa =
new
A();
pa->f();
B* pb = (B *)pa;
pb->f();
delete
pa, pb;
pa =
new
B();
pa->f();
pb = (B *)pa;
pb->f();
}
/*输出:
A
A
B
B
*/
|
14、
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
#include<iostream>
using
namespace
std;
class
A
{
char
a[3];
virtual
void
aa() {};
};
class
B :
virtual
public
A
{
char
b[3];
virtual
void
bb() {};
};
class
C :
public
A
{
char
c[3];
virtual
void
cc() {};
};
int
main()
{
A a;
B b;
C c;
cout<<
sizeof
(a)<<endl;
cout<<
sizeof
(b)<<endl;
cout<<
sizeof
(c)<<endl;
return
0;
}
|