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;
}
|