(1.3)基础知识类
(1.1)库函数类
引用标准库时,下面的说法你认为哪个是正确的:
#include “stdlib.h”是正确的,而且程序编译速度比#include <stdlib.h>要快
语句#include <stdlib.h>是正确的,而且程序编译速度比#include “stdlib.h”要快
语句#include <stdlib.h>和#include “stdlib.h”都是正确的,程序编译速度没有区别
语句#include “stdlib.h”是错误的
#inlcude <> 首先 只搜索系统目录,不会搜索本地目录.比如你自己写一个头文件,你用#include <>会出错.
#inlude ""首先搜索本地目录,如果本地目录没有才会搜索系统目录.
可以把系统的文件 放到当前目录下 改成 "" 可以优先使用
你认为可以完成编写一个C语言编译器的语言是()
- 汇编
- C语言
- :VB
- 以上全可以
下面哪些调用转换支持可变长度参数
- cdecl
- stdcall
- pascal
- fastcal
以下哪个函数可以在源地址和目的地址的位置任意的情况下,在源地址和目的地址的空间大小任意的情况下实现二进制代码块的复制?
- memcpy()
- memmove()
- memset()
- strcpy()
定义网络传输数据包为
1
2
3
4
class
packet{
int
size;
void
data[
0
];
}
其中data的作用是?
- 维护数据包空间的连续性
- 数据分割位
- 指向独立的数据空间
- 无任何作用
1.这个叫柔性数组,它的作用跟指针差不多,但是指针占空间,而它不占空间,这就意味着可以节省空间。
2.该数组的内存地址就和它后面的元素地址相同,意味着无需初始化,数组名就是后面元素的地址,直接就能当指针使用。例如,制作动态buffer,可以这样分配空间malloc(sizeof(structXXX) + buff_len); 直接就把buffer的结构体和缓冲区一块分配了。这样使用释放一次即可,如果使用指针,则需要释放两次。
3.也可以写成data[1]或data[],是考虑到可移植性的原因,因为有些编译器不支持0数组。
1
time_t t;
哪个选项可以将t初始化为当前程序的运行时间?
- t = clock();
- time( &t );
- time( t );
- t = localtime();
- None of the above
clock()
就是该程序从启动到函数调用占用CPU的时间
time( &t );为获取系统时间
localtime(&t);
将一个UTC时间转为本地时间
下面的函数中哪个是系统调用而不是库函数?
- printf
- scanf
- fgetc
- read
- print_s
- scan_s
-
在 C 语言中下面那个语句的结果是 1 ?
- main 函数正常结束的返回值
- return 7&1;
- char *p="hello"; return p == "hello";
- 上面都不对
A main 函数正常结束的返回值是0 ps:全局变量在main前构造,main结束后,程序关闭前析构
程序的完整编译过程分为是:预处理,编译,汇编等,如下关于编译阶段的编译优化的说法中不正确的是()?
- 死代码删除指的是编译过程直接抛弃掉被注释的代码
- 函数内联可以避免函数调用中压栈和退栈的开销
- For循环的循环控制变量通常很适合调度到寄存器访问
- 强度削弱是指执行时间较短的指令等价的替代执行时间较长的指令
死代码的含义是指永远不会被执行到的代码段,而不是直接抛弃被注释的代码
比如while(false){}
下面哪些属于使用"常引用"的原因?
- 提高程序的效率
- 节省存储空间
- 保护传递给函数的数据不在函数中被改变
- 以上都不正确
关于“深拷贝”,下列说法正确的是:
- 会拷贝动态分配的成员对象
- 会拷贝成员数据的值
- 会拷贝静态分配的成员对象
- B和C都对
深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。
浅拷贝是指源对象与拷贝对象共用一份实体,仅仅是引用的变量不同(名称不同)。对其中任何一个对象的改动都会影响另外一个对象。
静态成员的数据只有一份为大家共享,所以不能深拷贝
1
"My salary was increased by 15%!"
下列哪个选项可以准确的显示出上述语句?
- printf("\"My salary was increased by 15/%\!\"\n");
- printf("My salary was increased by 15%!\n");
- printf("My salary was increased by 15'%'!\n");
- printf("\"My salary was increased by 15%%!\"\n");
%因为%d %s比较特殊
A: 没\!这转义符,编译时报错
B,C: 一看前面输出时就少了双引号
D是对的,里面%%是输出的%,虽然有些编译器\%也能输出%,但貌似标准c不支持
1
2
3
4
5
6
7
8
9
10
11
12
int
func(
int
a)
{
int
b;
switch
(a)
{
case
1
: b =
30
;
case
2
: b =
20
;
case
3
: b =
16
;
default
: b =
0
;
}
return
b;
}
则func(1) = 0
因为没有break语句,switch中会一直计算到b=0
如果匹配到某个case,则从该case处开始顺序执行,否则就从default处开始执行,一直向下,直到出现break语句为止
1
2
3
4
5
6
7
8
9
10
11
12
int
func(
int
a)
{
int
b;
switch
(a)
{
default
: b =
0
;
case
1
: b =
30
;
case
2
: b =
20
;
case
3
: b =
16
;
}
return
b;
}
则func(1) = 16
若有以下程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<stdio.h>
main()
{
int
s=
0
,n;
for
(n=
0
; n<
4
; n++)
{
switch
(n)
{
default
:s+=
4
;
case1:s+=
1
;
case2:s+=
2
;
case3:s+=
3
;
}
}
printf (
"%d\n"
,s);
}
则程序的输出结果是?
24
第一次循环for循环,n的值为0,所以从default后面的语句开始执行,s+=4,s+=1,s+=2,s+=3,s的值为10。在进入第二次for循环,n的值为1,所以执行的s+=1,s+=2,s+=3,s的值为16。在进入第三次for循环,n的值为2,所以执行s+=2,s+=3,s的值为21。在进入第四次for循环,n的值为3,所以执行s+=3,s的值为24。
void recursive(int n, int m, int o)
{
if (n <= 0)
{
printf("%d,%d\n", m, o);
}
else
{
recursive(n - 1, m + 1, o);
recursive(n - 1, m, o + 1);
}
}
以上函数的时间复杂度()
时间复杂度只与n有关,m和o只是打酱油的。
n会递归两次n-1
n-1会递归两次n-2
n-2会递归两次n-3
所以,是一个完全二叉树,总共是2^n-1次,时间复杂度O(2^n)
头文件中的 ifndef/define/endif 干什么用?
- 定义常量
- 标记为特殊的头文件
- 防止头文件被重复引用
- 注释头文件
下面描述中,错误的是()
- 基类定义的public成员在公有继承的派生类中可见,也能在类外被访问
- 基类定义的public和protected成员在私有继承的派生类中可见,在类外可以被访问
- 基类定义的public和protected成员在保护继承的派生类中不可见
- 基类定义的protected成员在protected继承的派生类中可见,也能在类外被访问
有哪几种情况只能用intialization list 而不能用assignment?
- 当类中含有const成员变量
- 基类无默认构造函数时,有参的构造函数都需要初始化表。
- 当类中含有reference成员变量
- 当类中含有static成员变量
因为const对象以及引用只能初始化而不能赋值,所以只能使用成员初始化列表。
对于非内置类型,在进入函数体之前,如果没有提供显式初始化,会调用默认构造函数进行初始化。若没有默认构造函数,则编译器尝试调用默认构造函数将会失败,所以如果没有默认构造函数,则必须在初始化列表中显示的调用构造函数。
(1.2)基础类型与计算类
函数
1
2
3
fun(
char
* p) {
return
p;
}
的返回值是
行参p中存放的地址值
若有定义语句: char a ='\82'; 则变量a
- 说明不合法
- 包含1个字符
- 包含2个字符
- 包含3个字符
有一个‘\’,那么首先想到的是转义字符常量,‘\ddd’ 是用八进制数的ASCII码表示一个字符,但是本题中'\82',有一个8,显然已经不是八进制,那么这个时候实际上就'\82'中包含3个字符,分别是‘\’,'8','2',赋值时是将字符'2'给了a,实际上这个题和 char a = 'fdz'变量a的值是‘z’是一个道理,只是\具有迷惑作用而已,可以试验把‘\82’换成‘\zz’,则a的值为z,因此这道题选择包含一个字符。
c++中,声明const int i,是在哪个阶段做到 i只可读的?
- 编译
- 链接
- 运行
- 以上都不对
const int i = 10; 编译时候 就和 变量i做了对应,后面程序用到i的时候,直接从编译器的符号表中取10,不会再查找内存...
已知一函数中有下列变量定义,其中属于自动变量的有()。
- double k;
- register int i;
- static char c;
- auto long m;
普通的变量,不管是否声明为auto,都是自动型变量
A,普通变量,是auto的
B,寄存器变量,不是
C,静态变量,不是
D,声明为auto,是
引用可以是void类型吗?
- 不可以
- 可以
引用为对象起了另外的一个名字,该对象是已经存在的对象,引用必须初始化,有类型
下面关于迭代器失效的描述哪个是错误的()
vector的插入操作不会导致迭代器失效
map的插入操作不会导致迭代器失效
vector的删除操作只会导致指向被删除元素及后面的迭代器失效
map的删除操作只会导致指向被删除元素的迭代器失效
选A,因为由 Vector 的 iterator 和 listIterator 方法所返回的迭代器是快速失败的 :如果在迭代器创建后的任意时间从结构上修改了向量(通过迭代器自身的 remove 或 add 方法之外的任何其他方式),则迭代器将抛出 ConcurrentModificationException。
若有以下程序
1
2
3
4
5
6
7
8
9
#include <stdio. h>
main( )
{
int
a =
0
,b =
0
,c =
0
,d;
c = (a + = b,,b + = a); / * 第
4
行 * /
d = c; / * 第
5
行 * /
; / * 第
6
行 * /
;printf(
"%d,%d,%d\n"
,a,b,c);/ * 第
7
行 * /
}
编译时出现错误,你认为出错的是
第4行逗号表达式中间的第二个表达式为空,是不合法的,可以去掉写成a + = b,b + = a,也可以在里面补一个表达式,如a + = b,a,b + = a。所以选择A选项。
有函数定义:
1
2
void
test(
int
a){}
void
test(
float
a){}
则以下调用错误的是:
- test(1);
- test(‘c’);
- test(2+’d’)
- test(0.5)
C++中默认的类型转换是从下到上的,就是int ,float可能系统会转成double,但不会将double转化成int,char
test(0.5) 中的0.5在运算时是double类型的
已知x>=y and y>=z 为真,那么x>z or y=z 值为
- 真
- 假
- 无法确定
- x y z同为正数时为真
这题选c没有问题。首先要注意的是y=z是赋值,不是判断。 而后,x>=y>=z,当x=y=z的时候后面第一项x>z就不成立了,关键看第二项。当x=y=z=0,第二项为false,整个表达式为false。其他情况表达式是true
假设在n进制下,下面的等式成立,n值是() 567*456=150216
- 9
- 10
- 12
- 18
567*456=150216 -》 (5*n
2+5*n+7) * (4*n
2+5*n+6) = n
5 +5*n
4+2*n
2+n+6 解方程可得n=18
1735*1392=2415120
已有变量定义和函数调用语句,
1
2
int
a=
25
;
print_value(&a);
则下面函数的正确输出结果是______。
1
2
3
4
void
print_value(
int
* x)
{
printf(“%x\n”,++*x);
}
- 25
- 26
- 19
- 1a
%x是按十六进制输出,++*x = 26 = 0x1a
给定3个int类型的正整数x,y,z,对如下4组表达式判断正确的选项()
1
2
3
4
int
a1=x+y-z;
int
b1=x*y/z;
int
a2=x-z+y;
int
b2=x/z*y;
int
c1=x<<y>>z;
int
d1=x&y|z;
int
c2=x>>z<<y;
int
d2=x|z&y;
- a1一定等于a2
- b1一定等于b2
- c1一定等于c2
- d1一定等于d2
A
【解析】
由于整数除法的截断,b1和b2不一定相等
由于移位会丢弃超出位,c1和c2不一定相等
d1是(x&y)|z而d2是x|(y&z),不一定相等
1
2
3
4
5
void
swap_int(
int
*a,
int
*b){
*a=*a+*b;
*b=*a-*b;
*a=*a-*b;
}
以下说法正确的是:
- 结果不正确,因为会溢出,用位与的方式就没问题
- 结果正确,即使会溢出
- 结果正确,不会溢出
- 其他选项都不对
加减法可能会溢出。其实不然,第一步的加运算可能会造成溢出,但它所造成的溢出会在后边的减运算中被溢出回来
对以下程序,正确的输出结果是()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#define SUB(x,y) x-y
#define ACCESS_BEFORE(element,offset,value) *SUB(&element, offset) = value
int
main() {
int
array[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int
i;
ACCESS_BEFORE(array[5], 4, 6);
printf
(
"array: "
);
for
(i = 0; i < 10; ++i) {
printf
(
"%d"
, array[i]);
}
printf
(
"\n"
);
return
(0);
}
- array: 1 6 3 4 5 6 7 8 9 10
- array: 6 2 3 4 5 6 7 8 9 10
- 程序可以正确编译连接,但是运行时会崩溃
- 程序语法错误,编译不成功
“赋值号的左边操作数需要一个左值”。其原因是调用宏的那句被预处理器替换成了:
*&array[5]-4 =6;
由于减号比赋值优先级高,因此先处理减号;由于减号返回一个数而不是合法的左值,所以编译报错
下列代码的输出为:
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
#include "iostream"
#include "vector"
using namespace std;
int main(void)
{
vector<int>array;
array.push_back(100);
array.push_back(300);
array.push_back(300);
array.push_back(500);
vector<int>::iterator itor;
for
(itor=array.begin();itor!=array.end();itor++)
{
if
(*itor==300)
{
itor = array.erase(itor);
}
}
for
(itor=array.begin();itor!=array.end();itor++)
{
cout<<*itor<<
" "
;
}
return
0;
}
- 100 300 300 500
- 100 300 500
- 100 500
- 程序错误
vector在erase之后,指向下一个元素的位置,其实进行erase操作时将后面所有元素都向前移动,迭代器位置没有移动。itor=array.erase(itor) erase返回下一个元素的地址,相当于给itor一个新值。
以下STL的容器存放的数据,哪个肯定是排好序的()
- vector
- deque
- list
- map
关联式容器是排好序的
int func(unsigned int i)
{
Unsigned int temp = i;
temp = (temp & 0x55555555) + ((temp & 0xaaaaaaaa) >> 1);
temp = (temp & 0x33333333) + ((temp & 0xccccccccc) >> 2);
temp = (temp & 0x0f0f0f0f) + ((temp & 0xf0f0f0f0 >> 4));
temp = (temp & 0xff00ff) + ((temp & 0xff00fff00) >> 8);
temp = (temp & 0xffff) + ((temp & 0xffff0000) >> 16);
Return temp;
}
请问 func(0x11530828)的返回值是:8
求数的二进制表示中1的个数的“平行算法”,思路就是先将n写成二进制形式,然后相邻位相加,重复这个过程,直到只剩下一位。8
在c++中,
1
2
3
4
const
int
i =
0
;
int
*j = (
int
*) &i;
*j =
1
;
printf(
"%d,%d"
, i, *j)
输出是多少?
- 0,1
- 1,1
- 1,0
- 0,0
const
修饰符表示i为常量,值不可改变,但是通过指针可以改变内存中i所在地址中的值,所以输出*j的值变为1。但是通过编译器优化,i的值不再是每次都在内存中读取,而是见到i编译器就可自动赋值为最初的值0,所以输出i的值时为0,答案为A 0,1。
如果将i更改为volatile const int类型的,编译器就不会对变量i做优化,printf输出的结果就为1。
下面描述正确的是
1
2
int
*p1 =
new
int
[
10
]; // 10个未初始化int new student
int
*p2 =
new
int
[
10
]();// 10个值初始化为0的int new Student()
- p1和p2申请的空间里面的值都是随机值
- p1和p2申请的空间里的值都已经初始化
- p1申请的空间里的值是随机值,p2申请的空间里的值已经初始化
- p1申请的空间里的值已经初始化,p2申请的空间里的值是随机值
1
2
3
signed
char
a=0xe0;
unsigned
int
b=a;
unsigned
char
c=a;
下面说法正确的是:
- (a>0 )&&(b>0)为真
- c==a 为真
- b的16进制为0xffffffe0
- 都不对
a-------1110 0000-----因为是有符号数,负数-----取反+1 0010 0000----- -32
b-------高位按符号位补齐-------ff ff ff e0
c-------224
设
x
、
y
、
t
均为
int
型变量,则执行语句:
t=3; x=y=2; t=x++||++y;
后,变量
t
和
y
的值分别为
____
1,2
||返回0或者1
在一个64位的操作系统中定义如下结构体:
1
2
3
4
5
6
struct st_task
{
uint16_t id;
uint32_t value;
uint64_t timestamp;
};
同时定义fool函数如下:
1
2
3
4
5
6
7
void
fool()
{
st_task task = {};
uint64_t a =
0x00010001
;
memcpy(&task, &a, sizeof(uint64_t));
printf(
"%11u,%11u,%11u"
, task.id, task.value, task.timestamp);
}
上述fool()程序的执行结果为()
- 1,0,0
- 1,1,0
- 0,1,1
- 0,0,1
考点:字节对齐,低地址到高地址
因为字节对齐的原因,所以id占用4个字节,value和timestamp分别是4个字节、8个字节。虽然id占用四个字节的地址,但是只有低两位地址的数值有效(字节对齐的机制,即value存储时的地址对4(自身对齐值)求余应为0)。所以id为 0001 0001,高四位无效,所以为0001,value与timestamp分别为0.
比如:地址从0x0000开始,id存储地址本来为0x0000-0x0001,但value存储地址要从0x0004开始,因为0x0004%4==0,所以id存储地址为0x0000-0x0003, value存储地址为0x0004-0x0007, timestamp存储地址为0x0008-0x000F. 所以id == 0x00010001,去掉高4位,id=0x0001,其余为0.
经验:1、表示为习惯意义上的从高向低位写 高---》低 0010=2
2、小端机从右向左读,读的时候 元素间的字节外从右向左 元素内的字节内还是从左向右
nt main()
{
long long a=1;
long long b=2;
long long c=3;
printf("%d,%d,%d",a,b ,c);
return 0;
}
输出结果是什么?(32位环境,cpu为小端模式,所有参数用栈传递)
1、printf从右向左,压栈顺序c,b,a,栈从高向低,c在高位。
2、我们先表示为平常理解的方式高-->低,例如:1001 正常大端机器上:
【00 00 00 00 00 00 00 03】【00 00 00 00 00 00 00 02】【00 00 00 00 00 00 00 01】
大端机器读取,从左向右,%d为4字节,读取为0,3,0
小端机相当于从右向左读取,每次读取4个字节,1,0,2
unsigned int a= 0x1234;
unsigned char b=*(unsigned char *)&a;
在32位大端模式处理器上变量b= ?。
高--->低 00 00 12 34 大端机从左向右读取1个字节 00
在
x86
的机器上,
int a=0xabcd1234 char b=
((
char*
)
&a
)
[0]
请问
b
是多少 0x34
高向低 ab cd 12 34
X86小端机、1字节
在小端序的机器中,如果
1
2
3
4
union
X{
int
x;
char
y[4];
};
如果:
X a;
a.x=0x11223344;//16 进制 则:______
- a.y[0]=11
- a.y[1]=11
- a.y[2]=11
- a.y[3]=11
- a.y[0]=22
- a.y[3]=22
union类型,数据时重叠在同一块内存区域上的,这个内存区域的大小为对其后的最大长度,这里就是4
高--->低 11 22 33 44
小端从左向右取 y[3]=11
1
写出下列程序在X86上的运行结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct
mybitfields
{
unsigned
short
a : 4;
unsigned
short
b : 5;
unsigned
short
c : 7;
} test
void
main(
void
)
{
int
i;
test.a = 2;
test.b = 3;
test.c = 0;
i = *((
short
*)&test);
printf
(
"%d\n"
, i);
}
这个题的为难之处呢,就在于前面定义结构体里面用到的冒号,如果你能理解这个符号的含义,那么问题就很好解决了。这里的冒号相当于分配几位空间,也即在定义结构体的时候,分配的成员a 4位的空间, b 5位,c 7位,一共是16位,正好两个字节。下面画一个简单的示意:
变量名 位数
test 15 14 13 12 11 10 9 |8 7 6 5 4 |3 2 1 0
test.a | |0 0 1 0
test.b |0 0 0 1 1 |
test.c 0 0 0 0 0 0 0 | |
高--->低,从右读,每次都一个字节
在执行i=*((short *)&test); 时,取从地址&test开始两个字节(short占两个字节)的内容转化为short型数据,即为0x0032,再转为int型为0x00000032,即50
1
2
3
4
5
6
7
8
9
10
11
union Test
{
char
a[
4
];
short
b;
};
Test test;
test.a[
0
]=
256
;
test.a[
1
]=
255
;
test.a[
2
]=
254
;
test.a[
3
]=
253
;
printf(
"%d\n"
,test.b);
问题:在80X86架构下,输出什么值?
- -128
- -256
- 128
- 256
char类型的取值范围是-128~127,unsigned char的取值范围是0~256
这里a[0]=256,出现了正溢出,将其转换到取值范围内就是0,即a[0]=0;
同理,a[1]=-1, a[2]=-2, a[3]=-3,在C语言标准里面,用补码表示有符号数,故其在计算机中的表示形式如下:
a[0]=0, 0000 0000
a[1]=-1, 1111 1111
a[2]=-2, 1111 1110
a[3]=-3, 1111 1101
小端机器中:
1111 1101 1111 1110 1111 1111 0000 0000
short是2字节(a[0]和a[1]),由于80X86是小端模式,即数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中,在本例中,a[0]中存放的是b的低位,a[1]中存放的是b的高位,即b的二进制表示是:1111 1111 0000 0000,表示-256,故选B。
在32位小端的机器上,如下代码输出是什么:
1
2
3
4
5
char
array[
12
] = {
0x01
,
0x02
,
0x03
,
0x04
,
0x05
,
0x06
,
0x07
,
0x08
};
short
*pshort = (
short
*)array;
int
*pint = (
int
*)array;
int64 *pint64 = (int64 *)array;
printf(
"0x%x , 0x%x , 0x%llx , 0x%llx"
, *pshort , *(pshort+
2
) , *pint64 , *(pint+
2
));
- 0x201 , 0x403 , 0x807060504030201 , 0x0
- 0x201 , 0x605 , 0x807060504030201 , 0x0
- 0x201 , 0x605 , 0x4030201 , 0x8070605
- 0x102 , 0x506 , 0x102030405060708 , 0x0
小端机器的数据高位字节放在高地址,低位字节放在低地址。x86结构为小端模式。
pshort占用2个字节,在内存中的16进制为0x01 0x02,对应的16进制数为0x0201。
pshort + 2指向array数组的下标为4的元素,占用2个字节,在内存中的16进制为0x05 0x06,对应的16进制数为0x0605。
pint64的int64类型不确定,但根据名字可以看出占用8个字节,对应的16进制形式为0x807060504030201。
pint + 2占用4个字节,指向的array数组的下标为8的元素,8-11个元素没有指定数组的初始化值,默认为0,因此*(pint + 2)对应的16进制为0。
以下代码执行后,val的值是___:
1
2
3
4
unsigned
long
val = 0;
char
a = 0x48;
char
b = 0x52;
val = b << 8 | a;
- 20992
- 21064
- 72
- 0
b << 8 = 0x5200
val = 0x5200 | 0x48 = 0x5248 = 21064
写出一下程序的输出
1
2
3
4
5
6
7
8
int
main(
void
)
{
char
num;
for
(num =
0
; num <
255
; )
num += num;
printf(
"%d\n"
,num);
return
0
;
}
- 254
- 255
- 256
- 死循环
选D
这里num值一直是0,num < 255一直是成立的,程序进入死循环
下面这个程序执行后会有什么错误或者效果:
1
2
3
4
5
6
7
#define MAX
255
int
main()
{
unsigned
char
A[MAX], i;
for
(i =
0
; i <= MAX; i++)
A[i] = i;
}
- 数组越界
- 死循环
- 栈溢出
- 内存泄露
1
2
3
4
5
6
7
8
9
10
11
#include<stdio.h>
int
main()
{
uint32_t a =
100
;
while
(a >
0
)
{
--a;
}
printf(
"%d"
, a);
return
0
;
}
-1
100
0
死循环
Unsigned int型数字最小为0,因此不是死循环,a到0就跳出循环,最后输出0
使用printf函数打印一个double类型的数据,要求:输出为10进制,输出左对齐30个字符,4位精度。以下哪个选项是正确的?
- %-30.4e
- %4.30e
- %-30.4f
- %-4.30f f: double精度浮点数 e: 科学计数法
- 用C++语法来看,下列的哪个赋值语句是正确的?
- char a=12
- int a=12.0
- int a=12.0f
- int a=(int)12.0
A项在赋值为0-127时无警告,但B/C/D均有损失精度的警告,编译还是能通过的。B、C、D项的区别是:B 项的默认为double型转向int型,C项因等号后“12.0f”的 ‘f’使其转换为folate型,D项直接通过在等号的右边加“(int)”强制类型转换,与B项相同的是:是从默认的double型转换为int型。A项会对应的ASCII字符,但在大于127时会发生常量截断会有警告。
以下程序的输出结果为
#include "stdio.h"
int func(int x, int y)
{
return (x + y);
}
int main()
{
int a = 1, b = 2, c = 3, d = 4, e = 5;
printf(" % d\n", func((a + b, b + c, c + a), (d, e)));
return 0;
}
9
主要知识点是C++中的逗号操作符! C++ Primer第4版中145页关于逗号操作符论述如下:
逗号表达式的结果是其最右边表达式的值,但是是从左向右计算
以下选项中合法的实型常量是?
- 0
- 3.13e-2.1
- .914
- 2.0*10
A选项为整型数据。B选项中e后面必须为整数。D选项是表达式,不是常量,所以选择C。
有如下程序段:
1
2
3
4
5
6
7
8
9
int i, n = 0;
float x = 1, y1 = 2.1 / 1.9, y2 = 1.9 / 2.1;
for
( i = 1; i < 22; i++ )
x = x * y1;
while
( x != 1.0 )
{
x = x * y2; n++;
}
printf( “ %d / n ”, n );
请问执行结果是:
无限循环
浮点数有精确度的限制吧。所以肯定不能除尽,不能使用==和!=,以及位运算
下面两段代码中for循环分别执行了多少次?
1
2
3
4
5
6
7
8
9
1
.
unsigned
short
i,j;
for
(i=
0
, j=
2
; i!=j; i+=
5
, j+=
7
)
{}
2
.
unsigned
short
i,j;
for
(i=
3
,j=
7
;i!=j;i+=
3
,j+=
7
)
{}
32767 16383
答案分析:unsigned short能表示216个数,其范围为0~216-1,j在i前2个位置,i以5的速度增长,j以7的速度增长,当增长到unsigned short表示的最大值又会返回0(以一个圈的形式循环)开始重新走直到i、j相遇,所以就是7t - 5t + 2 = 216,所以为32767次
第二个类似 (7t + 7)-(5t - 3) = 216,所以为16383次
下面有关C++的类和C里面的struct的描述,正确的有?
- 来自class的继承按照private继承处理,来自struct的继承按照public继承处理
- class的成员默认是private权限,struct默认是public权限
- c里面的struct只是变量的聚合体,struct不能有函数
- c++的struct可有构造和析构函数
有变量int i = 0; int a = i++; int b=++a; int c = a+b; 请问表达式 a?b:c 的值是
- 0
- 1
- 2
- 3
a=i++. a----0
b=++a. b----1. a----1
c=a+b. c-----2
a?b:c a为1取b 也就是1
当参数*x==1, *y==1, *z==1时,下列不可能是函数add的返回值的( )?
1
2
3
4
5
6
int
add(
int
*x,
int
*y,
int
*z){
*x += *x;
*y += *x;
*z += *y;
return
*z;
}
- 4
- 5
- 6
- 7
开始不知道啥意思,后经牛客网的大神指点才知道这题要考虑的是,x,y,z三个参数是否指向同一地址(或者说调用该函数时是否实参相同),如:当a=b=c=1时,add(&a,&a,&a),add(&a,&b,&c)。
通过写程序测试得出结果,不可能得到答案7。
有以下5种情况
1
2
3
4
5
6
7
enum
string{
x1,
x2,
x3=
10
,
x4,
x5,
} x;
问x等于什么?
- 5
- 12
- 0
- 随机值
如果是函数外定义那么是0
如果是函数内定义,那么是随机值,因为没有初始化
数字字符0的ASCII值为48,若有以下程序:
1
2
3
4
5
6
main()
{
char a=’1’,b=’2’;
printf(“%c,”,b++);
printf(“%d\n”,b-a);
}
程序运行之后的输出结果是:
注意初始化时的数据类型,为char型,即此时int(a)=49,int(b)=50。第一条输出变量b的char类型,即char(b)=2,输出后int(b)自增=51,第二条输出整形即int(b-a)=51-49=2。
-
(1.3)函数类
从下列函数原形看,用GCC编译时,返回值类型为int的函数有?
- char F1(int n);
- int F2(char n);
- F3(int n);
- int *F4(int n);
函数原型格式:
函数返回值 函数名([形参表]);
A:返回char类型
C:默认返回类型为int类型
D:返回整型指针类型
如果没有返回值,必须声明为void类型
设有以下函数void fun(int n,char *s)(......),则下面对函数指针的定义和赋值均是正确的是:()
- void (*pf)(int,char); pf=&fun;
- void (*pf)(int n,char *s); pf=fun;
- void *pf(); *pf=fun;
- void *pf(); pf=fun;
B. 函数指针只需要把fun 改成(*pf) ,赋值 直接 pf = fun;即可 函数名赋值.指针函数赋值时候,可以直接用函数名赋值(书上一般都是这样赋值的) .但是也可以用&fun ,取地址操作符复制给函数指针. pf = &fun;也是可以的.亲测过
程序出错在什么阶段__?
1
2
3
4
int
main(
void
) {
http:
//www.taobao.com
cout <<
"welcome to taobao"
<< endl;
}
- 预处理阶段出错
- 编译阶段出错
- 汇编阶段出错
- 链接阶段出错
- 运行阶段出错
- 程序运行正常
http相当于一个label,//www.taobao.com是注释,所以答案错误,可以运行
(1.3.1)重载类
不能作为重载函数的调用的依据是:
- 参数个数
- 参数类型
- 函数类型
- 函数名称
std::vector::iterator重载了下面哪些运算符?
- ++
- >>
- *(前置)
- ==
在重载运算符函数时,下面()运算符必须重载为类成员函数形式()
- +
- -
- ++
- ->
只能使用成员函数重载的运算符有:=、()、[]、->、new、delete。
如果友元函数重载一个运算符时,其参数表中没有任何参数则说明该运算符是:
- 一元运算符
- 二元运算符
- 选项A)和选项B)都可能
- 重载错误
友元函数重载时,参数列表为1,说明是1元,为2说明是2元
成员函数重载时,参数列表为空,是一元,参数列表是1,为2元
类成员函数的重载、覆盖和隐藏区别描述正确的有?
- 覆盖是指在同一个类中名字相同,参数不同
- 重载是指派生类函数覆盖基类函数,函数相同,参数相同,基类函数必须有virtual关键字
- 派生类函数与基类函数相同,但是参数不同,会"隐藏"父类函数
- 函数名字相同,参数相同,基类无virtual关键字的派生类的函数会"隐藏"父类函数
a.成员函数被重载的特征:
(1)相同的范围(在同一个类中);
(2)函数名字相同;
(3)参数不同;
(4)virtual 关键字可有可无。
b.覆盖是指派生类函数覆盖基类函数,特征是:
(1)不同的范围(分别位于派生类与基类);
(2)函数名字相同;
(3)参数相同;
(4)基类函数必须有virtual 关键字。
c.“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)
(1.3.2)静态类
关于static用途说法正确的是?
- 声明静态外部类
- 声明静态外部全局变量
- 声明静态外部函数
- 声明静态局部变量
下面对静态成员的描述中,正确的是:
静态数据成员可以在类内初始化
静态数据成员不可以被类对象调用
静态数据成员不能受private控制符的作用
静态数据成员可以直接用类名调用
1、静态数据成员同样受 private,public,protected 等权限符限制
2、静态数据成员由于是属于整个类的,静态数据成员存储在静态数据区。静态数据成员定义时要分配空间,所以不能在类声明中定义(即初始化),对它们的初始化一般在类外,但是,当类型为const static时的整形时可以在类体内进行初始化。
3、可以通过累的对象,指针,类名等直接调用静态成员
4、类的静态成员函数可以在类内进行定义,也可以在类外,类的静态成员函数只能直接调用静态成员,如果想调用非静态成员只能通过间接的方式,而非静态成员可以直接访问静态成员。
Fill the blanks inside class definition
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Test
{
public:
____ int a;
____ int b;
public:
Test::Test(int _a , int _b) : a( _a )
{
b = _b;
}
};
int Test::b;
int main(void)
{
Test t1(0 , 0) , t2(1 , 1);
t1.b = 10;
t2.b = 20;
printf(
"%u %u %u %u"
,t1.a , t1.b , t2.a , t2.b);
return
0;
}
Running result : 0 20 1 20
- static/const
- const/static
- --/static
- conststatic/static
- None of above
对于成员变量a,若它为const类型,那么必须要使用Test::Test(int _a , int _b) : a( _a )这种初始化形式,若它为普通成员变量,也可以采取Test::Test(int _a , int _b) : a( _a )这种形式,所以a可以为const或者普通类型,由于b没有采取Test::Test(int _a , int _b) : b( _b )这种形式,所以b一定不是const类型,有main()中的t1.b和t2.b的输出都是20可以知道,b是静态变量。
(1.3.3)宏、抽象、内联、构造函数类
内联函数在编译时是否做参数类型检查?
做类型检查,因为内联函数就是在程序编译时,编译器将程序中出现的内联函数的调用表达式用内联函数的函数体来代替。
以下叙述中错误的是?
- 数值型常量有正值和负值的区分
- 常量可以用一个符号名来代表
- 定义符号常量必须用类型名来设定常量的类型
- 常量是在程序运行过程中值不能被改变的量
可以使用红定义来确定一个常量,宏定义不需要指定类型名,宏定义是一个符号名
若有定义
1
2
typedef
char
T[
10
] ;
T * a ;
上述定义中a的类型与下面选项中完全相同的是?
- char a [ 10 ] ;
- char ( *A) [ 10 ] ;
- char * a ;
- char *a [ 10 ] ;
T b;
相当于 char b[10];
相信大家对这个没啥意见吧
那么,
T *a;
也就是一个指针a指向了一片空间,空间连续,并且以T为基本单位
以下代码的输出结果是?
1
2
3
4
5
6
7
8
9
10
11
12
13
#define a 10
void
foo();
main(){
printf
(
"%d.."
,a);
foo();
printf
(
"%d"
,a);
}
void
foo(){
#undef a
#define a 50
}
- 10..10
- 10..50
- Error
- 0
选A,define在预处理阶段就把main中的a全部替换为10了.
另外,不管是在某个函数内,还是在函数外,define都是从定义开始知道文件结尾,所以如果把foo函数放到main上面的话,则结果会是50 ,50
以下代码的输出结果是?
#define a 10
void foo(){
#undef a
#define a 50
}
int main(){
printf("%d..",a);
foo();
printf("%d",a);
}
- 10..10
- 50..50
- Error
- 0
不管是在某个函数内,还是在函数外,define都是从定义开始知道文件结尾,所以如果把foo函数放到main上面的话,则结果会是50 ,50
下列叙述正确的是:
- 预处理命令行必须位于源文件的开头
- 在源文件的一行上可以有多条预处理命令
- 宏名必须用大写字母表示
- 宏替换不占用程序运行时间
A:预处理指令指示在程序正式编译前就由编译器进行的操作,可放在程序中任何位置。
B:源文件的每一行只能有一条预处理命令,如果指令一行放不下,可以通过反斜杠“/”进行控制。
C:宏名通常由大写字母表示,而非必须
D:宏是在预编译期间进行的,将代码中的指定字符转换,转换结束后,再进行编译,所以不占用程序运行时间
抽象基类是指( )
- 嵌套类
- 派生类
- 含有纯虚函数
- 多继承类
假设A为抽象类,下列声明( )是正确的
- A fun(int);
- A*p;
- int fun(A);
- A obj;
抽象类 不能实例化, D明细不对。
抽象类不能参数类型 和 函数返回类型
构造函数
拷贝构造函数的特点是()
- 该函数名同类名,也是一种构造函数,该函数返回自身引用
- 该函数只有一个参数,必须是对某个对象的引用
- 每个类都必须有一个拷贝初始化构造函数,如果类中没有说明拷贝构造函数,则编译器系统会自动生成一个缺省拷贝构造函数,作为该类的保护成员
- 拷贝初始化构造函数的作用是将一个已知对象的数据成员值拷贝给正在创建的另一个同类的对象
拷贝函数和构造函数没有返回值,A错;
拷贝构造函数的参数可以使一个或多个,但左起第一个必须是类的引用对象,B错;
若类定义中没有声明拷贝构造函数,则编译器会自动生成一个缺省的拷贝构造函数,但是不会是该类的保护成员,C错;
通过拷贝函数可以将另一个对象作为对象的初值,D对
以下哪些做法是不正确或者应该极力避免的:【多选】( )
- 构造函数声明为虚函数
- 派生关系中的基类析构函数声明为虚函数
- 构造函数中调用虚函数
- 析构函数中调用虚函数
在析构函数中也不要调用虚函数。在析构的时候会首先调用子类的析构函数,析构掉对象中的子类部分,然后在调用基类的析构函数析构基类部分,如果在基类的析构函数里面调用虚函数,会导致其调用已经析构了的子类对象里面的函数,这是非常危险的。
在构造函数不要调用虚函数。在基类构造的时候,虚函数是非虚,不会走到派生类中,既是采用的静态绑定。显然的是:当我们构造一个子类的对象时,先调用基类的构造函数,构造子类中基类部分,子类还没有构造,还没有初始化,如果在基类的构造中调用虚函数,如果可以的话就是调用一个还没有被初始化的对象,那是很危险的,所以C++中是不可以在构造父类对象部分的时候调用子类的虚函数实现。但是不是说你不可以那么写程序,你这么写,编译器也不会报错。只是你如果这么写的话编译器不会给你调用子类的实现,而是还是调用基类的实现。
以下描述正确的是?
- 虚函数是可以内联的,可以减少函数调用的开销提高效率
- 类里面可以同时存在函数名和参数都一样的虚函数和静态函数
- 父类的析构函数是非虚的,但是子类的析构函数是虚的,delete子类对象指针会调用父类的析构函数
- 以上都不对
delete子类对象是一定会调用父类的析构函数的先调用子类的析构函数然后调用父类的析构函数;
如果要调用父类指向子类的对象,此时才需要父类的析构函数是虚的。 Peson p=new son; delete person; 需要person中析构函数为虚函数,才能保证先把子类的清除掉
下列关于构造函数的描述中,错误的是( )
- 构造函数可以设置默认的参数
- 构造函数在定义类对象的自动执行
- 构造函数可以是内联函数
- 构造函数不可以重载
1、构造函数可以内联,甚至默认是内联的;
2、内联函数、构造函数、静态函数都不能是虚函数,但是,可以被声明为虚函数,编译器默认忽略掉
在C++中,为了让某个类只能通过new来创建(即如果直接创建对象,编译器将报错),应该()
- 将构造函数设为私有
- 将析构函数设为私有
- 将构造函数和析构函数均设为私有
- 没有办法能做到
这刀题的意思就是,只能在堆上建立示例。
我们知道,栈上的实例是系统自己建立的 Student s; 系统会自动delete释放内存 A()和~A()一对
堆上 Student * s=new Student(); 需要我们自己delete 【这题只能让这样子,其实就是让我们改得系统不能自动析构】 new和delete、new[]和delete[]一对
编 译器在为类对象分配栈空间时,会先检查类的析构函数的访问性,其实不光是析构函数,只要是非静态的函数,编译器都会进行检查。如果类的析构函数是私有的,则编译器不会在栈空间上为类对象分配内存。 因此, 将析构函数设为私有,类对象就无法建立在栈(静态)上了,只能在堆上(动态new)分配类对象 。
在C++中,为了让某个类只能通过直接创建对象(即如果new来创建,编译器将报错),应该()
- 将构造函数设为私有
- 私有化new运算符,同时重写delete函数
- 将构造函数和析构函数均设为私有
- 没有办法能做到
只有使用new运算符,对象才会建立在堆上,因此,只要禁用new运算符就可以实现类对象只能建立在栈上。虽然你不能影响new operator的能力(因为那是C++语言内建的),但是你可以利用一个事实:new operator 总是先调用 operator new,而后者我们是可以自行声明重写的。因此,将operator new()设为私有即可禁止对象被new在堆上。代码如下:
- class A
- {
- private:
- void* operator new(size_t t){} // 注意函数的第一个参数和返回值都是固定的
- void operator delete(void* ptr){} // 重载了new就需要重载delete
- public:
- A(){}
- ~A(){}
- };
编译运行如下程序会出现什么结果
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
class
A
{
A()
{
printf(
"A()"
);
}
};
void
main()
{
A a;
}
则输出
编译错误
编译出错,因为无参的构造函数被覆盖,并且构造方法默认是私有的,不能被调用。这种情况下不能隐式调用无参构造方法创建对象。
单例模式会把构造方法声明为私有的,但是会提供一个public的静态方法,用来获取对象实例。
有哪几种情况只能用intialization list 而不能用assignment?
- 当类中含有const成员变量
- 基类无默认构造函数时,有参的构造函数都需要初始化表。
- 当类中含有reference成员变量
- 当类中含有static成员变量
因为const对象以及引用只能初始化而不能赋值,所以只能使用成员初始化列表。
对于非内置类型,在进入函数体之前,如果没有提供显式初始化,会调用默认构造函数进行初始化。若没有默认构造函数,则编译器尝试调用默认构造函数将会失败,所以如果没有默认构造函数,则必须在初始化列表中显示的调用构造函数。
当类中含有const、reference 成员变量;基类的构造函数都需要初始化表。
虚函数
下面有关虚函数的描述,说法错误的是?
- 虚函数的作用是实现了继承性
- 虚函数的作用就是实现“动态联编”,也就是在程序的运行阶段动态地选择合适的成员函数
- 和类的静态成员函数与非类的成员函数相比,虚函数的效率较低
- 要正确的实现虚函数,只能用一个基类的指针或者引用来指向派生类对象
虚函数可不可以重载为内联?
可以
虚函数是可以内联的,但是编译器在处理的时候还是按照函数编译的,内联实际上是不起作用的因为虚函数是要为多态提供基础的,如果按照内联函数展开后就无法实现多态了。
以下描述正确的是?
- 虚函数是可以内联的,可以减少函数调用的开销提高效率
- 类里面可以同时存在函数名和参数都一样的虚函数和静态函数
- 父类的析构函数是非虚的,但是子类的析构函数是虚的,delete子类对象指针会调用父类的析构函数
- 以上都不对
虚函数不能是内联函数,不能是静态函数因为虚函数需要有实体,也不能是构造函数
虚函数的作用是实现了多态性
以下关于内联函数,说法正确的是:
- 一般用于加快程序执行速度
- 可能减小可执行文件大小
- 可能增加可执行文件大小
- 以上说法都不正确
(1.3.4)模板类
代码可以通过编译吗?如果不能应该如何修改?
1
2
3
4
5
6
7
8
9
10
11
template
<
class
T> Foo{
T tVar;
public
:
Foo(T t) : tVar(t) { }
};
class
FooDerived :
public
Foo{};
int
main(){
FooDerived d;
return
0;
}
- 代码可以正确通过编译。
- 编译错误,FooDerived是一个继承模板类的非模板类,它的类型不能改变。
- 编译错误,tVal变量是一个不确定的类型。
- 编译错误,可以在FooDerived类中添加一个构造函数解决问题。
//派生类对象的基类部分与派生类对象自己的数据成员都是在构造函数初始化阶段执行初始化操作;
//通过构造函数初始化列表将实参传递给基类构造函数
//格式如下: Derived(基类部分的初始化列表,派生类自己的数据成员初始化列表):Base(基类的数据成员),派生类自己的数据成员{}
//本题为如下:
classFooDerived : publicFoo{
public:
FooDerived(T t):Foo<T>(t){} //要加上模板参数
};
下面有关函数模板和类模板的说法正确的有?
- 函数模板的实例化是由编译程序在处理函数调用时自动完成的
- 类模板的实例化必须由程序员在程序中显式地指定
- 函数模板针对仅参数类型不同的函数
- 类模板针对仅数据成员和成员函数类型不同的类
模板(Template)是一种强大的C++软件复用特性,通常有两种形式:函数模板和类模板。函数模板针对仅参数类型不同的函数(答案C ok);类模板针对仅数据成员和成员函数类型不同的类(答案D ok)。函数模板和类模板可以是程序员只需制定一个单独的代码段,就可表示一整套称为函数模板特化的相关(重载)函数或是表示一整套称为类模板特化的相关的类。这种技术称为泛型程序设计(generic programming)。
使用模板的好处在于,可以使程序员编写与类型无关的代码。
模板是一个类家族的抽象,它只是对类的描述,
编译程序不为类模板(包括成员函数定义)创建程序代码,但是通过对类模板的实例化可以生成一个具体的类以及该具体类的对象。
下列关于模板的说法正确的是
- 模板的实参在任何时候都可以省略
- 类模板与模板类所指的是同一概念
- 类模板的参数必须是虚拟类型的
- 类模板中的成员函数全部都是模板函数
A:下面列举的几种情况不能省略模板实参:
1)从模板函数实参表获得的信息有矛盾之处。
2)需要获得特定类型的返回值,而不管参数的类型如何。
3)虚拟类型参数没有出现在模板函数的形参表中。
4)函数模板含有常规形参。
B:类模板与模板类的概念
⑴ 什么是类模板 一个类模板(也称为类属类或类生成类)允许用户为类定义一种模式,使得类中的某些数据成员、默写成员函数的参数、某些成员函数的返回值,能够取任意类型(包括系统预定义的和用户自定义的)。
如果一个类中数据成员的数据类型不能确定,或者是某个成员函数的参数或返回值的类型不能确定,就必须将此类声明为模板,它的存在不是代表一个具体的、实际的类,而是代表着一类类。
⑵ 模板类是类模板实例化后的一个产物。可以从类模板派生出新的类,既可以派生类模板,也可以派生非模板类。
类模板的重点是模板。表示的是一个模板,专门用于产生类的模子。
模板类的重点是类。表示的是由一个模板生成而来的类。
C:类模板有三种类型模板参数:类型模板参数、无类型模板参数和模板模板参数(以模板作为模板的参数)。并不局限于虚拟类型,非虚拟类型也可以作为类模板参数。
(1.1)库函数类
语句#include <stdlib.h>是正确的,而且程序编译速度比#include “stdlib.h”要快
语句#include <stdlib.h>和#include “stdlib.h”都是正确的,程序编译速度没有区别
语句#include “stdlib.h”是错误的
#inlude ""首先搜索本地目录,如果本地目录没有才会搜索系统目录.
可以把系统的文件 放到当前目录下 改成 "" 可以优先使用
- 汇编
- C语言
- :VB
- 以上全可以
- cdecl
- stdcall
- pascal
- fastcal
- memcpy()
- memmove()
- memset()
- strcpy()
1
2
3
4
|
class
packet{
int
size;
void
data[
0
];
}
|
- 维护数据包空间的连续性
- 数据分割位
- 指向独立的数据空间
- 无任何作用
1
|
time_t t;
|
- t = clock();
- time( &t );
- time( t );
- t = localtime();
- None of the above
- printf
- scanf
- fgetc
- read
- print_s
- scan_s
-
- main 函数正常结束的返回值
- return 7&1;
- char *p="hello"; return p == "hello";
- 上面都不对
- 死代码删除指的是编译过程直接抛弃掉被注释的代码
- 函数内联可以避免函数调用中压栈和退栈的开销
- For循环的循环控制变量通常很适合调度到寄存器访问
- 强度削弱是指执行时间较短的指令等价的替代执行时间较长的指令
- 提高程序的效率
- 节省存储空间
- 保护传递给函数的数据不在函数中被改变
- 以上都不正确
关于“深拷贝”,下列说法正确的是:
- 会拷贝动态分配的成员对象
- 会拷贝成员数据的值
- 会拷贝静态分配的成员对象
- B和C都对
1
|
"My salary was increased by 15%!"
|
- printf("\"My salary was increased by 15/%\!\"\n");
- printf("My salary was increased by 15%!\n");
- printf("My salary was increased by 15'%'!\n");
- printf("\"My salary was increased by 15%%!\"\n");
1
2
3
4
5
6
7
8
9
10
11
12
|
int
func(
int
a)
{
int
b;
switch
(a)
{
case
1
: b =
30
;
case
2
: b =
20
;
case
3
: b =
16
;
default
: b =
0
;
}
return
b;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
|
int
func(
int
a)
{
int
b;
switch
(a)
{
case
1
: b =
30
;
case
2
: b =
20
;
case
3
: b =
16
;
}
return
b;
}
|
若有以下程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#include<stdio.h>
main()
{
int
s=
0
,n;
for
(n=
0
; n<
4
; n++)
{
switch
(n)
{
default
:s+=
4
;
case1:s+=
1
;
case2:s+=
2
;
case3:s+=
3
;
}
}
printf (
"%d\n"
,s);
}
|
则程序的输出结果是?
24{
if (n <= 0)
{
printf("%d,%d\n", m, o);
}
else
{
recursive(n - 1, m + 1, o);
recursive(n - 1, m, o + 1);
}
}
- 定义常量
- 标记为特殊的头文件
- 防止头文件被重复引用
- 注释头文件
- 基类定义的public成员在公有继承的派生类中可见,也能在类外被访问
- 基类定义的public和protected成员在私有继承的派生类中可见,在类外可以被访问
- 基类定义的public和protected成员在保护继承的派生类中不可见
- 基类定义的protected成员在protected继承的派生类中可见,也能在类外被访问
- 当类中含有const成员变量
- 基类无默认构造函数时,有参的构造函数都需要初始化表。
- 当类中含有reference成员变量
- 当类中含有static成员变量
(1.2)基础类型与计算类
1
2
3
|
fun(
char
* p) {
return
p;
}
|
- 说明不合法
- 包含1个字符
- 包含2个字符
- 包含3个字符
- 编译
- 链接
- 运行
- 以上都不对
- double k;
- register int i;
- static char c;
- auto long m;
A,普通变量,是auto的
B,寄存器变量,不是
C,静态变量,不是
D,声明为auto,是
- 不可以
- 可以
下面关于迭代器失效的描述哪个是错误的()
vector的插入操作不会导致迭代器失效
map的插入操作不会导致迭代器失效
vector的删除操作只会导致指向被删除元素及后面的迭代器失效
map的删除操作只会导致指向被删除元素的迭代器失效
选A,因为由 Vector 的 iterator 和 listIterator 方法所返回的迭代器是快速失败的 :如果在迭代器创建后的任意时间从结构上修改了向量(通过迭代器自身的 remove 或 add 方法之外的任何其他方式),则迭代器将抛出 ConcurrentModificationException。
若有以下程序
1
2
3
4
5
6
7
8
9
|
#include <stdio. h>
main( )
{
int
a =
0
,b =
0
,c =
0
,d;
c = (a + = b,,b + = a); / * 第
4
行 * /
d = c; / * 第
5
行 * /
; / * 第
6
行 * /
;printf(
"%d,%d,%d\n"
,a,b,c);/ * 第
7
行 * /
}
|
编译时出现错误,你认为出错的是
第4行逗号表达式中间的第二个表达式为空,是不合法的,可以去掉写成a + = b,b + = a,也可以在里面补一个表达式,如a + = b,a,b + = a。所以选择A选项。
1
2
|
void
test(
int
a){}
void
test(
float
a){}
|
- test(1);
- test(‘c’);
- test(2+’d’)
- test(0.5)
- 真
- 假
- 无法确定
- x y z同为正数时为真
- 9
- 10
- 12
- 18
1
2
|
int
a=
25
;
print_value(&a);
|
1
2
3
4
|
void
print_value(
int
* x)
{
printf(“%x\n”,++*x);
}
|
- 25
- 26
- 19
- 1a
1
2
3
4
|
int
a1=x+y-z;
int
b1=x*y/z;
int
a2=x-z+y;
int
b2=x/z*y;
int
c1=x<<y>>z;
int
d1=x&y|z;
int
c2=x>>z<<y;
int
d2=x|z&y;
|
- a1一定等于a2
- b1一定等于b2
- c1一定等于c2
- d1一定等于d2
1
2
3
4
5
|
void
swap_int(
int
*a,
int
*b){
*a=*a+*b;
*b=*a-*b;
*a=*a-*b;
}
|
- 结果不正确,因为会溢出,用位与的方式就没问题
- 结果正确,即使会溢出
- 结果正确,不会溢出
- 其他选项都不对
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#include <stdio.h>
#define SUB(x,y) x-y
#define ACCESS_BEFORE(element,offset,value) *SUB(&element, offset) = value
int
main() {
int
array[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int
i;
ACCESS_BEFORE(array[5], 4, 6);
printf
(
"array: "
);
for
(i = 0; i < 10; ++i) {
printf
(
"%d"
, array[i]);
}
printf
(
"\n"
);
return
(0);
}
|
- array: 1 6 3 4 5 6 7 8 9 10
- array: 6 2 3 4 5 6 7 8 9 10
- 程序可以正确编译连接,但是运行时会崩溃
- 程序语法错误,编译不成功
*&array[5]-4 =6;
由于减号比赋值优先级高,因此先处理减号;由于减号返回一个数而不是合法的左值,所以编译报错
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
|
#include "iostream"
#include "vector"
using namespace std;
int main(void)
{
vector<int>array;
array.push_back(100);
array.push_back(300);
array.push_back(300);
array.push_back(500);
vector<int>::iterator itor;
for
(itor=array.begin();itor!=array.end();itor++)
{
if
(*itor==300)
{
itor = array.erase(itor);
}
}
for
(itor=array.begin();itor!=array.end();itor++)
{
cout<<*itor<<
" "
;
}
return
0;
}
|
- 100 300 300 500
- 100 300 500
- 100 500
- 程序错误
- vector
- deque
- list
- map
{
Unsigned int temp = i;
temp = (temp & 0x55555555) + ((temp & 0xaaaaaaaa) >> 1);
temp = (temp & 0x33333333) + ((temp & 0xccccccccc) >> 2);
temp = (temp & 0x0f0f0f0f) + ((temp & 0xf0f0f0f0 >> 4));
temp = (temp & 0xff00ff) + ((temp & 0xff00fff00) >> 8);
temp = (temp & 0xffff) + ((temp & 0xffff0000) >> 16);
Return temp;
}
1
2
3
4
|
const
int
i =
0
;
int
*j = (
int
*) &i;
*j =
1
;
printf(
"%d,%d"
, i, *j)
|
- 0,1
- 1,1
- 1,0
- 0,0
|
const
修饰符表示i为常量,值不可改变,但是通过指针可以改变内存中i所在地址中的值,所以输出*j的值变为1。但是通过编译器优化,i的值不再是每次都在内存中读取,而是见到i编译器就可自动赋值为最初的值0,所以输出i的值时为0,答案为A 0,1。
|
1
2
|
int
*p1 =
new
int
[
10
]; // 10个未初始化int new student
int
*p2 =
new
int
[
10
]();// 10个值初始化为0的int new Student()
|
- p1和p2申请的空间里面的值都是随机值
- p1和p2申请的空间里的值都已经初始化
- p1申请的空间里的值是随机值,p2申请的空间里的值已经初始化
- p1申请的空间里的值已经初始化,p2申请的空间里的值是随机值
1
2
3
|
signed
char
a=0xe0;
unsigned
int
b=a;
unsigned
char
c=a;
|
- (a>0 )&&(b>0)为真
- c==a 为真
- b的16进制为0xffffffe0
- 都不对
1
2
3
4
5
6
|
struct st_task
{
uint16_t id;
uint32_t value;
uint64_t timestamp;
};
|
1
2
3
4
5
6
7
|
void
fool()
{
st_task task = {};
uint64_t a =
0x00010001
;
memcpy(&task, &a, sizeof(uint64_t));
printf(
"%11u,%11u,%11u"
, task.id, task.value, task.timestamp);
}
|
- 1,0,0
- 1,1,0
- 0,1,1
- 0,0,1
{
long long a=1;
long long b=2;
long long c=3;
printf("%d,%d,%d",a,b ,c);
return 0;
}
输出结果是什么?(32位环境,cpu为小端模式,所有参数用栈传递)
unsigned char b=*(unsigned char *)&a;
在32位大端模式处理器上变量b= ?。
1
2
3
4
|
union
X{
int
x;
char
y[4];
};
|
X a;
a.x=0x11223344;//16 进制 则:______
- a.y[0]=11
- a.y[1]=11
- a.y[2]=11
- a.y[3]=11
- a.y[0]=22
- a.y[3]=22
1
|
写出下列程序在X86上的运行结果
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
struct
mybitfields
{
unsigned
short
a : 4;
unsigned
short
b : 5;
unsigned
short
c : 7;
} test
void
main(
void
)
{
int
i;
test.a = 2;
test.b = 3;
test.c = 0;
i = *((
short
*)&test);
printf
(
"%d\n"
, i);
}
|
1
2
3
4
5
6
7
8
9
10
11
|
union Test
{
char
a[
4
];
short
b;
};
Test test;
test.a[
0
]=
256
;
test.a[
1
]=
255
;
test.a[
2
]=
254
;
test.a[
3
]=
253
;
printf(
"%d\n"
,test.b);
|
- -128
- -256
- 128
- 256
1
2
3
4
5
|
char
array[
12
] = {
0x01
,
0x02
,
0x03
,
0x04
,
0x05
,
0x06
,
0x07
,
0x08
};
short
*pshort = (
short
*)array;
int
*pint = (
int
*)array;
int64 *pint64 = (int64 *)array;
printf(
"0x%x , 0x%x , 0x%llx , 0x%llx"
, *pshort , *(pshort+
2
) , *pint64 , *(pint+
2
));
|
- 0x201 , 0x403 , 0x807060504030201 , 0x0
- 0x201 , 0x605 , 0x807060504030201 , 0x0
- 0x201 , 0x605 , 0x4030201 , 0x8070605
- 0x102 , 0x506 , 0x102030405060708 , 0x0
1
2
3
4
|
unsigned
long
val = 0;
char
a = 0x48;
char
b = 0x52;
val = b << 8 | a;
|
- 20992
- 21064
- 72
- 0
1
2
3
4
5
6
7
8
|
int
main(
void
)
{
char
num;
for
(num =
0
; num <
255
; )
num += num;
printf(
"%d\n"
,num);
return
0
;
}
|
- 254
- 255
- 256
- 死循环
1
2
3
4
5
6
7
|
#define MAX
255
int
main()
{
unsigned
char
A[MAX], i;
for
(i =
0
; i <= MAX; i++)
A[i] = i;
}
|
- 数组越界
- 死循环
- 栈溢出
- 内存泄露
1
2
3
4
5
6
7
8
9
10
11
|
#include<stdio.h>
int
main()
{
uint32_t a =
100
;
while
(a >
0
)
{
--a;
}
printf(
"%d"
, a);
return
0
;
}
|
100
0
死循环
Unsigned int型数字最小为0,因此不是死循环,a到0就跳出循环,最后输出0
- %-30.4e
- %4.30e
- %-30.4f
- %-4.30f f: double精度浮点数 e: 科学计数法
- 用C++语法来看,下列的哪个赋值语句是正确的?
- char a=12
- int a=12.0
- int a=12.0f
- int a=(int)12.0
#include "stdio.h"
int func(int x, int y)
{
return (x + y);
}
int main()
{
int a = 1, b = 2, c = 3, d = 4, e = 5;
printf(" % d\n", func((a + b, b + c, c + a), (d, e)));
return 0;
}
- 0
- 3.13e-2.1
- .914
- 2.0*10
1
2
3
4
5
6
7
8
9
|
int i, n = 0;
float x = 1, y1 = 2.1 / 1.9, y2 = 1.9 / 2.1;
for
( i = 1; i < 22; i++ )
x = x * y1;
while
( x != 1.0 )
{
x = x * y2; n++;
}
printf( “ %d / n ”, n );
|
1
2
3
4
5
6
7
8
9
|
1
.
unsigned
short
i,j;
for
(i=
0
, j=
2
; i!=j; i+=
5
, j+=
7
)
{}
2
.
unsigned
short
i,j;
for
(i=
3
,j=
7
;i!=j;i+=
3
,j+=
7
)
{}
|
- 来自class的继承按照private继承处理,来自struct的继承按照public继承处理
- class的成员默认是private权限,struct默认是public权限
- c里面的struct只是变量的聚合体,struct不能有函数
- c++的struct可有构造和析构函数
- 0
- 1
- 2
- 3
1
2
3
4
5
6
|
int
add(
int
*x,
int
*y,
int
*z){
*x += *x;
*y += *x;
*z += *y;
return
*z;
}
|
- 4
- 5
- 6
- 7
1
2
3
4
5
6
7
|
enum
string{
x1,
x2,
x3=
10
,
x4,
x5,
} x;
|
- 5
- 12
- 0
- 随机值
1
2
3
4
5
6
|
main()
{
char a=’1’,b=’2’;
printf(“%c,”,b++);
printf(“%d\n”,b-a);
}
|
(1.3)函数类
从下列函数原形看,用GCC编译时,返回值类型为int的函数有?
- char F1(int n);
- int F2(char n);
- F3(int n);
- int *F4(int n);
- void (*pf)(int,char); pf=&fun;
- void (*pf)(int n,char *s); pf=fun;
- void *pf(); *pf=fun;
- void *pf(); pf=fun;
1
2
3
4
|
int
main(
void
) {
http:
//www.taobao.com
cout <<
"welcome to taobao"
<< endl;
}
|
- 预处理阶段出错
- 编译阶段出错
- 汇编阶段出错
- 链接阶段出错
- 运行阶段出错
- 程序运行正常
(1.3.1)重载类
- 参数个数
- 参数类型
- 函数类型
- 函数名称
std::vector::iterator重载了下面哪些运算符?
- ++
- >>
- *(前置)
- ==
- +
- -
- ++
- ->
- 一元运算符
- 二元运算符
- 选项A)和选项B)都可能
- 重载错误
成员函数重载时,参数列表为空,是一元,参数列表是1,为2元
- 覆盖是指在同一个类中名字相同,参数不同
- 重载是指派生类函数覆盖基类函数,函数相同,参数相同,基类函数必须有virtual关键字
- 派生类函数与基类函数相同,但是参数不同,会"隐藏"父类函数
- 函数名字相同,参数相同,基类无virtual关键字的派生类的函数会"隐藏"父类函数
a.成员函数被重载的特征:
(1)相同的范围(在同一个类中);
(2)函数名字相同;
(3)参数不同;
(4)virtual 关键字可有可无。
b.覆盖是指派生类函数覆盖基类函数,特征是:
(1)不同的范围(分别位于派生类与基类);
(2)函数名字相同;
(3)参数相同;
(4)基类函数必须有virtual 关键字。
c.“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)
(1.3.2)静态类
- 声明静态外部类
- 声明静态外部全局变量
- 声明静态外部函数
- 声明静态局部变量
3、可以通过累的对象,指针,类名等直接调用静态成员
4、类的静态成员函数可以在类内进行定义,也可以在类外,类的静态成员函数只能直接调用静态成员,如果想调用非静态成员只能通过间接的方式,而非静态成员可以直接访问静态成员。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
class Test
{
public:
____ int a;
____ int b;
public:
Test::Test(int _a , int _b) : a( _a )
{
b = _b;
}
};
int Test::b;
int main(void)
{
Test t1(0 , 0) , t2(1 , 1);
t1.b = 10;
t2.b = 20;
printf(
"%u %u %u %u"
,t1.a , t1.b , t2.a , t2.b);
return
0;
}
|
- static/const
- const/static
- --/static
- conststatic/static
- None of above
- 数值型常量有正值和负值的区分
- 常量可以用一个符号名来代表
- 定义符号常量必须用类型名来设定常量的类型
- 常量是在程序运行过程中值不能被改变的量
1
2
|
typedef
char
T[
10
] ;
T * a ;
|
- char a [ 10 ] ;
- char ( *A) [ 10 ] ;
- char * a ;
- char *a [ 10 ] ;
相当于 char b[10];
相信大家对这个没啥意见吧
那么,
T *a;
也就是一个指针a指向了一片空间,空间连续,并且以T为基本单位
以下代码的输出结果是?
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#define a 10
void
foo();
main(){
printf
(
"%d.."
,a);
foo();
printf
(
"%d"
,a);
}
void
foo(){
#undef a
#define a 50
}
|
- 10..10
- 10..50
- Error
- 0
以下代码的输出结果是?
|
|
- 10..10
- 50..50
- Error
- 0
下列叙述正确的是:
- 预处理命令行必须位于源文件的开头
- 在源文件的一行上可以有多条预处理命令
- 宏名必须用大写字母表示
- 宏替换不占用程序运行时间
抽象基类是指( )
- 嵌套类
- 派生类
- 含有纯虚函数
- 多继承类
- A fun(int);
- A*p;
- int fun(A);
- A obj;
构造函数
- 该函数名同类名,也是一种构造函数,该函数返回自身引用
- 该函数只有一个参数,必须是对某个对象的引用
- 每个类都必须有一个拷贝初始化构造函数,如果类中没有说明拷贝构造函数,则编译器系统会自动生成一个缺省拷贝构造函数,作为该类的保护成员
- 拷贝初始化构造函数的作用是将一个已知对象的数据成员值拷贝给正在创建的另一个同类的对象
- 构造函数声明为虚函数
- 派生关系中的基类析构函数声明为虚函数
- 构造函数中调用虚函数
- 析构函数中调用虚函数
在析构函数中也不要调用虚函数。在析构的时候会首先调用子类的析构函数,析构掉对象中的子类部分,然后在调用基类的析构函数析构基类部分,如果在基类的析构函数里面调用虚函数,会导致其调用已经析构了的子类对象里面的函数,这是非常危险的。
在构造函数不要调用虚函数。在基类构造的时候,虚函数是非虚,不会走到派生类中,既是采用的静态绑定。显然的是:当我们构造一个子类的对象时,先调用基类的构造函数,构造子类中基类部分,子类还没有构造,还没有初始化,如果在基类的构造中调用虚函数,如果可以的话就是调用一个还没有被初始化的对象,那是很危险的,所以C++中是不可以在构造父类对象部分的时候调用子类的虚函数实现。但是不是说你不可以那么写程序,你这么写,编译器也不会报错。只是你如果这么写的话编译器不会给你调用子类的实现,而是还是调用基类的实现。
- 虚函数是可以内联的,可以减少函数调用的开销提高效率
- 类里面可以同时存在函数名和参数都一样的虚函数和静态函数
- 父类的析构函数是非虚的,但是子类的析构函数是虚的,delete子类对象指针会调用父类的析构函数
- 以上都不对
- 构造函数可以设置默认的参数
- 构造函数在定义类对象的自动执行
- 构造函数可以是内联函数
- 构造函数不可以重载
- 将构造函数设为私有
- 将析构函数设为私有
- 将构造函数和析构函数均设为私有
- 没有办法能做到
- 将构造函数设为私有
- 私有化new运算符,同时重写delete函数
- 将构造函数和析构函数均设为私有
- 没有办法能做到
只有使用new运算符,对象才会建立在堆上,因此,只要禁用new运算符就可以实现类对象只能建立在栈上。虽然你不能影响new operator的能力(因为那是C++语言内建的),但是你可以利用一个事实:new operator 总是先调用 operator new,而后者我们是可以自行声明重写的。因此,将operator new()设为私有即可禁止对象被new在堆上。代码如下:
- class A
- {
- private:
- void* operator new(size_t t){} // 注意函数的第一个参数和返回值都是固定的
- void operator delete(void* ptr){} // 重载了new就需要重载delete
- public:
- A(){}
- ~A(){}
- };
1
2
3
4
5
6
7
8
9
10
11
12
|
#include <stdio.h>
class
A
{
A()
{
printf(
"A()"
);
}
};
void
main()
{
A a;
}
|
单例模式会把构造方法声明为私有的,但是会提供一个public的静态方法,用来获取对象实例。
- 当类中含有const成员变量
- 基类无默认构造函数时,有参的构造函数都需要初始化表。
- 当类中含有reference成员变量
- 当类中含有static成员变量
虚函数
- 虚函数的作用是实现了继承性
- 虚函数的作用就是实现“动态联编”,也就是在程序的运行阶段动态地选择合适的成员函数
- 和类的静态成员函数与非类的成员函数相比,虚函数的效率较低
- 要正确的实现虚函数,只能用一个基类的指针或者引用来指向派生类对象
- 虚函数是可以内联的,可以减少函数调用的开销提高效率
- 类里面可以同时存在函数名和参数都一样的虚函数和静态函数
- 父类的析构函数是非虚的,但是子类的析构函数是虚的,delete子类对象指针会调用父类的析构函数
- 以上都不对
- 一般用于加快程序执行速度
- 可能减小可执行文件大小
- 可能增加可执行文件大小
- 以上说法都不正确
(1.3.4)模板类
1
2
3
4
5
6
7
8
9
10
11
|
template
<
class
T> Foo{
T tVar;
public
:
Foo(T t) : tVar(t) { }
};
class
FooDerived :
public
Foo{};
int
main(){
FooDerived d;
return
0;
}
|
- 代码可以正确通过编译。
- 编译错误,FooDerived是一个继承模板类的非模板类,它的类型不能改变。
- 编译错误,tVal变量是一个不确定的类型。
- 编译错误,可以在FooDerived类中添加一个构造函数解决问题。
- 函数模板的实例化是由编译程序在处理函数调用时自动完成的
- 类模板的实例化必须由程序员在程序中显式地指定
- 函数模板针对仅参数类型不同的函数
- 类模板针对仅数据成员和成员函数类型不同的类
模板(Template)是一种强大的C++软件复用特性,通常有两种形式:函数模板和类模板。函数模板针对仅参数类型不同的函数(答案C ok);类模板针对仅数据成员和成员函数类型不同的类(答案D ok)。函数模板和类模板可以是程序员只需制定一个单独的代码段,就可表示一整套称为函数模板特化的相关(重载)函数或是表示一整套称为类模板特化的相关的类。这种技术称为泛型程序设计(generic programming)。
- 模板的实参在任何时候都可以省略
- 类模板与模板类所指的是同一概念
- 类模板的参数必须是虚拟类型的
- 类模板中的成员函数全部都是模板函数
1)从模板函数实参表获得的信息有矛盾之处。
2)需要获得特定类型的返回值,而不管参数的类型如何。
3)虚拟类型参数没有出现在模板函数的形参表中。
4)函数模板含有常规形参。
B:类模板与模板类的概念
⑴ 什么是类模板 一个类模板(也称为类属类或类生成类)允许用户为类定义一种模式,使得类中的某些数据成员、默写成员函数的参数、某些成员函数的返回值,能够取任意类型(包括系统预定义的和用户自定义的)。
如果一个类中数据成员的数据类型不能确定,或者是某个成员函数的参数或返回值的类型不能确定,就必须将此类声明为模板,它的存在不是代表一个具体的、实际的类,而是代表着一类类。
vector的插入操作不会导致迭代器失效
map的插入操作不会导致迭代器失效
vector的删除操作只会导致指向被删除元素及后面的迭代器失效
map的删除操作只会导致指向被删除元素的迭代器失效
选A,因为由 Vector 的 iterator 和 listIterator 方法所返回的迭代器是快速失败的 :如果在迭代器创建后的任意时间从结构上修改了向量(通过迭代器自身的 remove 或 add 方法之外的任何其他方式),则迭代器将抛出 ConcurrentModificationException。
(1.3.5)const函数
指出下面程序哪里可能有问题?
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
|
class
CBuffer
{
char
* m_pBuffer;
int
m_size;
public
:
CBuffer()
{
m_pBuffer=NULL;
}
~CBuffer()
{
Free();
}
void
Allocte(
int
size) (1) {
m_size=size;
m_pBuffer=
new
char
[size];
}
private
:
void
Free()
{
if
(m_pBuffer!=NULL) (2)
{
delete
m_pBuffer;
m_pBuffer=NULL;
}
}
public
:
void
SaveString(
const
char
* pText)
const
(3)
{
strcpy
(m_pBuffer, pText); (4)
}
char
* GetBuffer()
const
{
return
m_pBuffer;
}
};
void
main (
int
argc,
char
* argv[])
{
CBuffer buffer1;
buffer1.SaveString(
"Microsoft"
);
printf
(buffer1.GetBuffer());
}
|
- 1
- 2
- 3
- 4
1. 不能在const函数中修改所在类的对象的数据,因为const函数中的*this是常量,同样只能访问const函数;
2. const函数中只能调用其他的const函数,不能调用非const函数,因为对象调用函数是需要传递对象自己,const函数中的*this是常量,非const函数中的*this是变量,因此不可以调用(除非去除*this的const属性);
Note:使用const_cast后,可以在const函数中调用非const函数的
3. const函数与同名的非const函数是重载函数;
4. const对象只能调用const函数 ,但是非const对象可以调用const函数。
1
2
3
4
5
6
7
8
9
10
|
class
A {
...
private
:
int
a;
public
:
const
int
b;
float
* &c;
static
const
char
* d;
static
double
* e;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#define a 10
void
foo();
main(){
printf
(
"%d.."
,a);
foo();
printf
(
"%d"
,a);
}
void
foo(){
#undef a
#define a 50
}
|
- 10..10
- 10..50
- Error
- 0
- 可用来创建动态增长和减小的数据结构
- 它是类型无关的,因此具有很高的可复用性
- 它运行时检查数据类型,保证了类型安全
- 它是平台无关的,可移植性
- C++语言的多态性分为编译时的多态性和运行时的多态性
- 编译时的多态性可通过函数重载实现
- 运行时的多态性可通过模板和虚函数实现
- 实现运行时多态性的机制称为动态绑定
- template<class Type>class C1;
- template<class T, U, class V>class C2;
- template<class C1, ypename C2>class C3{};
- template<typename myT, class myT>class C4{};
template <class 形参名,class 形参名,......> 返回类型 函数名(参数列表)
{
函数体
类模板的格式为:
template<class 形参名 ,class 形参名,…> class 类名
{ ... };