单选题:
1.有以下定义:
int a[10];
char b[80];
函数声明为:
void sss(char[],int[]);
则正确的函数调用形式是() 。
A sss(a,b);
B sss(char b[],int a[]);
C sss(b[],a[]);
D sss(b,a);
我的回答: B (错误)
正确答案: D
2.数组a的定义语句为“float a[3][4];”,下列()是对数组元素不正确的引用方法。
A a[i][j]
B *(a[i]+j)
C ((a+i)+j)
D (a+i4+j)
我的回答: B (错误)
正确答案: D
A:是正确的,比如a[0][0]
B:是正确的,a[i]+j是a[i][j]的地址,在用*指向也是引用了这个地址
C:是正确的,*(a+i)表示a[i][0]的地址*(a+i)+j是a[i][j]的地址*(*(a+i)+j)也是使用了他
D:是错误的,因为他只指向了一次,就是a[i*4+j]的地址.
3.下列代码的运行结果是()
int a[]={1,2,3,4};
int *b=a;
*b+=2;
*(b+2)=2;
b++;
printf(“%d,%d\n”,*b,*(b+2));
A 1,3
B 1,2
C 2,4
D 3,2
我的回答: D (错误)
正确答案: C
*b首先指向a的第一个元素,
*b+=2,表示将第一个元素下标加2,所以数组a的第三个元素变为3,
*(b+2)表示指向数组a的第三个元素,所以*(b+2)将数组a的第三个元素变为2,
b++使指针后移一位,就是数组a的第二位,所以输出2,4。
4.以下关于C++的描述中哪一个是正确的:
A 任何指针都必须指向一个实例
B 子类指针不可以指向父类实例
C 任何引用都必须指向一个实例
D 引用所指向的实例不可能无效
我的回答: D (错误)
正确答案: C
B 父类指针可以指向子类,但子类指针不能指向父类。A,D都可能发生。
5.以下不是double compare(int,int)的重载函数的是()
A int compare(double,double)
B double compare(double,double)
C double compare(double,int)
D int compare(int,int)
我的回答: A (错误)
正确答案: D
a. 成员函数被重载的特征:
( 1 )相同的范围(在同一个类中);
( 2 )函数名字相同;
( 3 )参数不同;
( 4 ) virtual 关键字可有可无。
b. 覆盖是指派生类函数覆盖基类函数,特征是:
( 1 )不同的范围(分别位于派生类与基类);
( 2 )函数名字相同;
( 3 )参数相同;
( 4 )基类函数必须有 virtual 关键字。
c.“ 隐藏 ” 是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
( 1 )如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无 virtual 关键字,基类的函数将被隐藏(注意别与重载混淆)。
( 2 )如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有 virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。
6.关于虚函数的描述正确的是()
A 派生类的虚函数与基类的虚函数具有不同的参数个数和类型
B 内联函数不能是虚函数
C 派生类必须重新定义基类的虚函数
D 虚函数可以是一个static型的函数
我的回答: C (错误)
正确答案: B
A 派生类的虚函数与基类中对应的虚函数具有相同的函数名、相同的参数个数和类型。
B D 虚函数是为了实现动态绑定,不能声明为虚函数的有:
1、静态成员函数; 2、类外的普通函数; 3、构造函数; 4、友元函数
此外,还有一些函数可以声明为虚函数,但是没有意义,但编译器不会报错,如:
● 赋值运算符的重载成员函数: 因为复制操作符的重载函数往往要求形参与类本身的类型一致才能实现函数功能,故形参类型往往是基类的类型,因此即使声明为虚函数,也把虚函数当普通基类普通函数使用。
● 内联函数:内联函数目的是在代码中直接展开(编译期),而虚函数是为了继承后能动态绑定执行自己的动作(动态绑定),因此本质是矛盾的,因此即使内联函数声明为虚函数,编译器遇到这种情况是不会进行inline展开的,而是当作普通函数来处理。因此声明了虚函数不能实现内敛的,即内敛函数可以声明为虚函数,但是毫无了内联的意义。
虚函数可以很好的实现多态,在使用虚函数时应注意如下问题:
1.虚函数的声明只能出现在类函数原型的声明中,不出现在函数体实现的时候,而且,基类中只有保护成员或公有成员才能被声明为虚函数。
2.在派生类中重新定义虚函数时,关键字virtual可以写也可以不写,但是在容易引起混乱时,应该写上该关键字。
3.重载一个虚函数时,要求函数名、返回类型、参数个数、参数类型和参数顺序都必须与基类中的虚函数完全一致。
7.请将下列构造函数补充完整,使得程序的运行结果是5 ()
#include<iostream>
using namespace std;
class Sample
{
public:
Sample(int x) {
________
}
~Sample() {
if(p) delete p;
}
int show() {
return *p;
}
private:
int *p;
};
int main(){
Sample S(5);
cout<<S.show()<<endl;
return 0;
}
A *p=x;
B p=new int(x);
C *p=new int(x);
D p=&x;
我的回答: A (错误)
正确答案: B
8.在32位cpu上选择缺省对齐的情况下,有如下结构体定义:
struct A{
unsigned a : 19;
unsigned b : 11;
unsigned c : 4;
unsigned d : 29;
char index;
};
则sizeof(struct A)的值为()
A 9
B 12
C 16
D 20
我的回答: C (正确)
正确答案: C
解析:题目不说,默认4字节对齐
19+11=30<32bit 4
4+29=33>32bit 4+4
1byte=8bit 1 对齐到 4
4+4+4+4=16
9.关于c++的inline关键字,以下说法正确的是()
A 使用inline关键字的函数会被编译器在调用处展开
B 头文件中可以包含inline函数的声明
C 可以在同一个项目的不同源文件内定义函数名相同但实现不同的inline函数
D 定义在Class声明内的成员函数默认是inline函数
E 优先使用Class声明内定义的inline函数
F 优先使用Class实现的内inline函数的实现
我的回答: C (错误)
正确答案: D
A 项错误,因为使用 inline 关键字的函数只是用户希望它成为内联函数,但编译器有权忽略这个请求,比如:若此函数体太大,则不会把它作为内联函数展开的。
B 项错误,头文件中不仅要包含 inline 函数的声明,而且必须包含定义,且在定义时必须加上 inline 。【关键字 inline 必须与函数定义体放在一起才能使函数成为内联,仅将 inline 放在函数声明前面不起任何作用】
C 项错误, inline 函数可以定义在源文件中,但多个源文件中的同名 inline 函数的实现必须相同。一般把 inline 函数的定义放在头文件中更加合适。
D 项正确,类内的成员函数,默认都是 inline 的。【定义在类声明之中的成员函数将自动地成为内联函数】
EF 项无意思,不管是 class 声明中定义的 inline 函数,还是 class 实现中定义的 inline 函数,不存在优先不优先的问题,因为 class 的成员函数都是 inline 的,加了关键字 inline 也没什么特殊的。
编程题:
1.排列子序列:牛牛定义排序子序列为一个数组中一段连续的子序列,并且这段子序列是非递增或者非递减排序的。牛牛有一个长度为n的整数数组A,他现在有一个任务是把数组A分为若干段排序子序列,牛牛想知道他最少可以把这个数组分为几段排序子序列。
【解题思路】:
通过上面理解了排序子序列,如果我们把这里值画到一个坐标图里面,本质就是去找这里图里面的波峰和波谷的个数,再加一。
注意:非递减就是a[i]<=a[i+1],递减就是a[i]>a[i+1],非递增就是a[i]>=a[i+1],递增就是a[i]<a[i+1]。
【代码实现】
#include<iostream>
#include<vector>
#include<stdlib.h>
using namespace std;
int main()
{
int n;
cin >> n;
vector<int> v;
v.resize(n);
for (int i = 0; i < n; ++i)
cin >> v[i];
int ret = 1;
for (int i = 1; i<n - 1; i++)
{
//找出波峰波谷
if ((v[i - 1] < v[i] && v[i] > v[i + 1]) || (v[i - 1] > v[i] && v[i] < v[i + 1]))
{
ret++;
// 处理特例
if (i != n - 3)
i++;
}
}
cout << ret << endl;
system("pause");
}
2.倒置字符串:就是将一段字符串中的前后单词交换,以单词为单位逆置。
【解题思路1】:
先将整个字符串逆置过来,再遍历字符串,找出每个单词,对单词逆置。这里我们使用了stl算法中的 reverse,所以这里使用迭代器遍历string。
【代码实现】
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string s;
// 注意这里要使用getline,cin>>s遇到空格就接收结束了
getline(cin, s);
// 翻转整个句子
reverse(s.begin(), s.end());
// 翻转单词
auto start = s.begin();
while (start != s.end())
{
auto end = start;
while (end != s.end() && *end != ' ')
end++;
reverse(start, end);
if (end != s.end())
start = end + 1;
else
start = end;
}
cout << s << endl;
system("pause");
return 0;
}
【解题思路2】:
第二思路是一个比较讨巧的思路,直接利用cin>>s接收输入,遇到空格就结束了,自然就分割开了每个单词,其次将每次接收到的单词拼接到之前串的前面就逆置过来了。
【代码实现】
#include <iostream>
#include <string>
using namespace std;
// cin读取string时自动会被空格分隔开,用另一个字符串存储进行逆序输出
int main()
{
string s1, s2;
cin >> s2;
while (cin >> s1)
s2 = s1 + " " + s2;
cout << s2 << endl;
return 0;
}