C++复试笔记(二)
数组,sizeof计算
对于给定的数组定义 int a[3][4];
,我们来计算表达式 sizeof(a)/sizeof(int [3])
。
首先明确几个概念:
- 数组
a
是一个 3x4 的二维数组,即它有 3 行 4 列,总共包含 12 个int
类型的元素。 sizeof(a)
给出的是整个数组a
所占的总字节大小。因为有 12 个int
,假设在你的环境中int
占用 4 字节,那么sizeof(a)
就是12 * 4 = 48
字节。sizeof(int [3])
给出的是一个包含 3 个int
元素的一维数组所占用的字节大小。因此,如果每个int
占用 4 字节,则sizeof(int [3])
为3 * 4 = 12
字节。
现在,我们可以计算表达式 sizeof(a)/sizeof(int [3])
:
sizeof(a)
是整个数组的大小,如上所述为 48 字节(基于上述假设)。sizeof(int [3])
是 12 字节(同样基于上述假设)。
将这两个值相除:48 / 12 = 4
。
字符串中的 \0
若有定义:char *str="abc\0def";,则语句cout<<str;的输出为()。
当你使用 cout << st;
输出这个字符串时(假设 str
是 st
的笔误),输出将从字符串的起始位置开始,直到遇到第一个空字符 \0
为止。因此,尽管 "abc\0def"
包含更多的字符,但实际输出只会是 "abc"
,因为 \0
标记了输出的终止位置。
所以,语句
C++常量
下面非法的 C++常量是(C)。 A.0xAf B.015 C.e-3 D.'\x41'
A. 0xAf
:这是一个十六进制整型常量。在C++中,十六进制常量以 0x
或 0X
开头,后面跟随的是十六进制数字(0-9, a-f, A-F)。因此,0xAf
是合法的。
B. 015
:这是一个八进制整型常量。在C++中,八进制常量以 0
开头,后面跟随的是0到7之间的数字。因此,015
也是合法的。
C. e-3
:这个看起来像是一个浮点数的科学记数法表示形式的一部分,但是它缺少了必要的基础数值部分。正确的科学记数法应该包括一个基数和一个指数,例如 1.2e-3
。单独的 e-3
无法被解释为一个有效的数值常量,所以它是非法的。
D. '\x41'
:这是一个字符常量,其中 \x
后跟两位十六进制数表示一个字符的ASCII码值。这里的 '\x41'
表示的是字符 'A'(其ASCII码为65,即十六进制的41),因此这也是合法的。
析构函数,继承
7.下面说法错误的是(B)。
A.类的静态成员为所有类的对象所共享
B.构造函数可以重载,析构函数也可以重载
C.类的友元函数可以访问类的私有成员
D.私有继承派生类的成员函数可以访问其基类的保护成员
解析:
A. 类的静态成员为所有类的对象所共享:这是正确的。静态成员属于类本身而不是类的某个特定对象,因此它们由所有对象共享。
B. 构造函数可以重载,析构函数也可以重载:这是不正确的。构造函数确实可以重载,这意味着一个类可以有多个不同参数列表的构造函数。然而,析构函数不能重载。每个类只能有一个析构函数,且其名称与类名相同但前面加上波浪号(~),并且不接受任何参数,也不返回任何值。
C. 类的友元函数可以访问类的私有成员:这是正确的。通过将函数声明为类的友元(使用 friend
关键字),该函数可以访问这个类的所有私有和保护成员。
D. 私有继承派生类的成员函数可以访问其基类的保护成员:这是正确的。即使继承是私有的,派生类仍然可以访问基类中的保护成员。私有继承影响的是从派生类外部对基类成员的访问级别,而不是派生类对其基类成员的访问权限。
运算符重载
下面关于运算符重载的说法中正确的是( )
A.通过运算符重载可以定义新的运算符 B.只能通过成员函数重载运算符"[]
C.如果重载运算符"+",则函数的名字是+ D.当重载二元运算法时,必须声明两个参数
详细解释:
A. 通过运算符重载可以定义新的运算符
-
错误。运算符重载只能重载 C++ 中已经存在的运算符,不能创建全新的运算符。例如,你不能定义一个全新的运算符
**
来表示幂运算。
B. 只能通过成员函数重载运算符 []
-
错误。运算符
[]
可以通过成员函数重载,但也可以通过非成员函数(全局函数)重载。不过,通常情况下,[]
是通过成员函数重载的,因为它需要访问类的私有成员。
C. 如果重载运算符 +
,则函数的名字是 +
-
错误。运算符重载的函数名并不是运算符本身,而是一个特殊的函数名。例如,重载
+
运算符的函数名是operator+
,而不是+
。 -
D. 当重载二元运算符时,必须声明两个参数
-
正确。二元运算符需要两个操作数,因此重载时需要声明两个参数。例如,重载
+
运算符时,函数签名通常是:MyClass operator+(const MyClass& lhs, const MyClass& rhs);
其中
lhs
和rhs
分别表示左操作数和右操作数。当然左操作数可能隐藏为this指针
插入排序
使用插入排序对 table指针数组中size 个指针所指向的字符串进行升序排序
void sort(char *table[], int size) {
int i, j;
for (i = 1; i < size; i++) { // ①:遍历数组
char *p = table[i]; // 保存当前需要插入的元素
for (j = i - 1; j >= 0; j--) { // 从后往前比较
if (strcmp(p, table[j]) < 0) { // 如果 p 比 table[j] 小
table[j + 1] = table[j]; // ②:将 table[j] 后移
} else {
break; // 如果找到合适的位置,退出内层循环
}
}
table[j + 1] = p; // ③:将 p 插入到正确的位置
}
}
有关e
C++中,下列变量声明中合法的是(A)
A.short a=1-0.1e-1 B.double b=1+5e2.5
C.long do=0xfdaL D.float 2_and=1-e-3
A. short a=1-0.1e-1
-
short
是合法的数据类型。 -
1-0.1e-1
是一个合法的表达式,计算结果为0.9
。 -
但是,
short
类型通常用于存储整数,而0.9
是一个浮点数。虽然C++允许隐式类型转换,但这种用法可能会导致精度丢失。
B. double b=1+5e2.5
-
double
是合法的数据类型。 -
5e2.5
是一个不合法的浮点数表示法,因为指数部分必须是整数。
C. long do=0xfdaL
-
long
是合法的数据类型。 -
do
是C++中的关键字(用于循环),不能用作变量名。
D. float 2_and=1-e-3
-
float
是合法的数据类型。 -
2_and
是一个不合法的变量名,因为变量名不能以数字开头。
总结 在科学计数法中,基数(e前面)可以是任意浮点数,而指数(e后面)部分必须是整数。
运算符优先级表
初级运算符( )、[ ]、->、. 高于 单目运算符 高于 算数运算符(先乘除后加减) 高于 关系运算符 高于 逻辑运算符(不包括!) 高于 条件运算符 高于 赋值运算符 高于 逗号运算符。
位运算符的优先级比较分散。
除了赋值运算符、条件运算符、单目运算符三类的平级运算符之间的结合顺序是从右至左,其他都是从左至右。
C语言运算符优先级
优先级 | 运算符 | 名称或含义 | 使用形式 | 结合方向 | 说明 |
1 | [] | 数组下标 | 数组名[常量表达式] | 左到右 | -- |
() | 圆括号 | (表达式)/函数名(形参表) | -- | ||
. | 成员选择(对象) | 对象.成员名 | -- | ||
-> | 成员选择(指针) | 对象指针->成员名 | -- | ||
2 | - | 负号运算符 | -表达式 | 右到左 | 单目运算符 |
~ | 按位取反运算符 | ~表达式 | |||
++ | 自增运算符 | ++变量名/变量名++ | |||
-- | 自减运算符 | --变量名/变量名-- | |||
* | 取值运算符 | *指针变量 | |||
& | 取地址运算符 | &变量名 | |||
! | 逻辑非运算符 | !表达式 | |||
(类型) | 强制类型转换 | (数据类型)表达式 | -- | ||
sizeof | 长度运算符 | sizeof(表达式) | -- | ||
3 | / | 除 | 表达式/表达式 | 左到右 | 双目运算符 |
* | 乘 | 表达式*表达式 | |||
% | 余数(取模) | 整型表达式%整型表达式 | |||
4 | + | 加 | 表达式+表达式 | 左到右 | 双目运算符 |
- | 减 | 表达式-表达式 | |||
5 | << | 左移 | 变量<<表达式 | 左到右 | 双目运算符 |
>> | 右移 | 变量>>表达式 | |||
6 | > | 大于 | 表达式>表达式 | 左到右 | 双目运算符 |
>= | 大于等于 | 表达式>=表达式 | |||
< | 小于 | 表达式<表达式 | |||
<= | 小于等于 | 表达式<=表达式 | |||
7 | == | 等于 | 表达式==表达式 | 左到右 | 双目运算符 |
!= | 不等于 | 表达式!= 表达式 | |||
8 | & | 按位与 | 表达式&表达式 | 左到右 | 双目运算符 |
9 | ^ | 按位异或 | 表达式^表达式 | 左到右 | 双目运算符 |
10 | | | 按位或 | 表达式|表达式 | 左到右 | 双目运算符 |
11 | && | 逻辑与 | 表达式&&表达式 | 左到右 | 双目运算符 |
12 | || | 逻辑或 | 表达式||表达式 | 左到右 | 双目运算符 |
13 | ?: | 条件运算符 | 表达式1? 表达式2: 表达式3 | 右到左 | 三目运算符 |
14 | = | 赋值运算符 | 变量=表达式 | 右到左 | -- |
/= | 除后赋值 | 变量/=表达式 | -- | ||
*= | 乘后赋值 | 变量*=表达式 | -- | ||
%= | 取模后赋值 | 变量%=表达式 | -- | ||
+= | 加后赋值 | 变量+=表达式 | -- | ||
-= | 减后赋值 | 变量-=表达式 | -- | ||
<<= | 左移后赋值 | 变量<<=表达式 | -- | ||
>>= | 右移后赋值 | 变量>>=表达式 | -- | ||
&= | 按位与后赋值 | 变量&=表达式 | -- | ||
^= | 按位异或后赋值 | 变量^=表达式 | -- | ||
|= | 按位或后赋值 | 变量|=表达式 | -- | ||
15 | , | 逗号运算符 | 表达式,表达式,… | 左到右 | -- |
说明:
同一优先级的运算符,运算次序由结合方向所决定。
简单记就是:! > 算术运算符 > 关系运算符 > && > || > 赋值运算符
字符串字面量赋值给一个字符数组
char s[10];s="dad"为什么错
-
数组名是指针常量:在C++中,数组名本质上是一个指向数组第一个元素的常量指针。你不能改变这个指针指向的位置,即不能通过赋值操作改变数组名指向的地址。
-
初始化 vs 赋值:字符数组可以通过初始化列表在其声明时被初始化为特定的字符串,例如
char s[10] = "dad";
。这里,编译器会自动将字符串"dad"
复制到数组s
中。然而,一旦数组被定义之后,就不能再通过简单的赋值操作符=
来改变它的内容。