问答题
问答题1:下面C程序的输出结果:
int i=0,a=1,b=2,c=3;
i=++a||++b||++c;
printf("%d %d %d %d",i,a,b,c);
首先 i 的右边会发生短路,如果a 是非0,则后面不会计算,而且右边整个是一个表达式,对于 i 只有两个值,要么是0,要么是 1,由于左边是真,所以 i 为1
答案是:1 2 2 3
问答题2:下面哪个操作符不能被重载?
提示:c++不能重载的运算符有.成员访问运算符
,::域解析符
,?:条件语句运算符
,*成员指针访问运算符
,sizeof
,typeid
,static_cast
,dynamic_cast
,interpret_cast
. 和 *
两个运算符不能重载是为了保证访问成员的功能不能被改变,域运算符和 sizeof 运算符的运算对象是类型而不是变量或一般表达式,不具备重载的特征,三目运算符可以看做 if else,由于重载的本质是函数的调用,if 和 else 语句应该是分支执行的,如果可以被重载,则无法实现分支这一功能.
问答题3:分析这段程序的输出?
class B{
public:
B(){
cout << "default constructor" << " ";
}
~B(){
cout << "destructed" << " ";
}
B(int i) : data(i){
cout << "constructed by parameter" << data << " ";
}
private: int data;
};
B Play(B b){
return b;
}
int main(int argc, char *argv[]) {
Play(5);
system("pause");
return 0;
}
提示:首先调用函数 Play,在进行传参的时候,会将 5 赋值给形参b,这时候调用有参数的构造函数,输出 constructed by parameter5
,在 Play 函数返回之前,由于形参需要释放,所以第一次调用 析构函数释放形参 b,输出一个 destructed
,之后会进行拷贝构造函数,将返回的对象拷贝给 temp,但是由于类中没有显示定义,所以调用的是编译器默认的拷贝构造函数,这一步骤并没有输出任何内容,最后释放 temp 对象,再调用一次析构函数输出一次 destructed
;
答案:constructed by parameter5 destructed destructed
问答题4: 下列程序输出什么?
class A{
public:
virtual void print(){
cout << "A::print()" << "\n";
}
};
class B : public A {
public:
virtual void print() {
cout << "B::print()" << "\n";
}
};
class C : public A {
public:
virtual void print() {
cout << "C::print()" << "\n";
}
};
void print(A a) {
a.print();
}
int main(){
A a, *aa, *ab, *ac;
B b;
C c;
aa = &a;
ab = &b;
ac = &c;
a.print(); // A::print()
b.print(); // B::print()
c.print(); // C::print()
aa->print();//A::print()
ab->print();//B::print()
ac->print();//C::print()
print(a);//A::print()
print(b);//A::print()
print(c);//A::print()
system("pause");
return 0;
}
a.print(); // A::print()
b.print(); // B::print()
c.print(); // C::print()
这段程序分别是对应的类对象调用各自的函数,
a,b,c分别属于 类A,B,C,调用各自类的函数,
aa->print();//A::print()
ab->print();//B::print()
ac->print();//C::print()
这段程序是父类指针指向了子类对象,本来aa,ab,ac都是属于
类A的对象,但是分别指向了子类A,B,C,所以调用各自类的函数
print(a);//A::print()
print(b);//A::print()
print(c);//A::print()
最后一段程序,a,b,c本来是类A,B,C的对象,但是在进行函数
传参的时候,由于是传值类型,所以自动转换为类A的类型,
所以都调用类A的函数.
另外如果把函数传值类型改为传引用的类型,那么结果就是分别
调用A,B,C类的函数
问答题5:下列选项不能正确输出 hello
的是?
#include<stdio.h>
struct str_t{
long long len;
char data[32];
};
struct data1_t{
long long len;
int data[2];
};
struct data2_t{
long long len;
char *data[1];
};
struct data3_t{
long long len;
void *data[];
};
int main(void){
struct str_t str;
memset((void*)&str,0,sizeof(struct str_t));
str.len=sizeof(struct str_t)-sizeof(int);
//str.len = 36;
snprintf(str.data,str.len,"hello");//VS下为_snprintf
____________________________________;
____________________________________;
return 0;
}
A选项:
- struct data3_t* pData=(struct data3_t* )&str;
- printf(“data:%s%s\n”,str.data,(char*)(&(pData->data[0])));
B选项:
- struct data2_t * pData=(struct data2_t * )&str;
- printf(“data:%s%s\n”,str.data,(char * )(pData->data[0]));
C选项:
- struct data1_t * pData=(struct data1_t * )&str;
- printf(“data:%s%s\n”,str.data,(char*)(pData->data));
D选项:
- struct str_t * pData=(struct str_t * )&str;
- printf(“data:%s%s\n”,str.data,(char*)(pData->data));
首先我们要搞明白要输出hello ,就必须得到 'h '地址;
编程题
1、 参数解析
在命令行输入如下命令:xcopy /s c:\ d:\
各个参数如下:
参数1:命令字xcopy
参数2:字符串/s
参数3:字符串c:\
参数4:字符串d:\
请编写一个参数解析程序,实现将命令行各个参数解析出来
解析规则如下:
参数分隔符为空格
对于用" "
包含起来的参数,如果中间有空格,不能解析为多个参数。比如在命令行输入
xcopy /s "C:\program files" "d:\"
时,
参数仍然是4个,第3个参数应该是字符串C:\program files
,注意输出参数时,需要将" "
去掉,引号不存在嵌套情况
输入描述:输入一行字符串,可以有空格
输出描述:输出参数个数,分解后的参数,每个参数都独占一行
示例:
输入:xcopy /s c:\ d:\
输出:
4
xcopy
/s
c:\
d:\
方法一 :遍历一遍字符串,如果遇到空格,则判断空格后面是不是引号,如果不是引号,则把该空格位置换成'\n'
,如果该空格位置的下一位是引号,则把引号位置的字符改为'\n'
,然后再寻找下一个引号,把结尾的引号改为'\n'
#include <iostream>
#include <string>
using namespace std;
int main(){
string str;
int count = 0;
while (getline(cin, str)) {
//先整体遍历一遍
for (size_t i = 0; i < str.size(); ++i){
//如果遇到空格,则先跳过,判断它下一位是不是引号?
if (str[i] == ' '){
++i;
if (str[i] == '\"' || str[i] == '\'') {
//如果是引号则把引号的位置置换为\n,前面那个空格可以不管了
str[i--] = '\n';
++count;
//遍历一直到下一个引号为止
while (str[i++] != '\"'){}
str[i] = '\0';
//如果没有引号就将空格直接替换为\0
}else {
str[--i] = '\n';
++count;
}
}
}
cout << count + 1 << endl;
cout << str;
}
return 0;
}
总结:该方法是利用C++输出遇到'\n'
或'\0'
会自动换行.
方法二(推介):以空格和双引号为间隔,统计参数个数,对于双引号,通过添加flag,保证双引号中的空格被输出
#include <iostream>
#include <string>
using namespace std;
int main(){
string str;
while (getline(cin, str)){
int count = 0;
// 首先计算参数数量
for (size_t i = 0; i < str.size(); i++){
if (str[i] == ' ')
count++;
// 如果是双引号,向后遍历,直到下一个双引号结束
if (str[i] == '"'){
do{
i++;
} while (str[i] != '"');
}
}
// 以空格计算个数,空格数量比参数个数少 1
cout << count + 1 << endl;
// 用 flag 表示是否包含双引号, 0 表示有双引号
// 双引号中的空格要打印出来
// 用异或改变 flag 的值,两个双引号可以使 flag 复原
int flag = 1;
for (size_t i = 0; i < str.size(); i++){
//有双引号,flag通过异或变为0,下一次再遇到双引号,flag置为1
if (str[i] == '"')
flag ^= 1;
// 双引号和普通空格不打印
if (str[i] != ' ' && str[i] != '"')
cout << str[i];
// 双引号中的空格要打印
if (str[i] == ' ' && (!flag))
cout << str[i];
// 遇到双引号之外的空格就换行
if (str[i] == ' ' && flag)
cout << endl;
}
cout << endl;
}
return 0;
}
2 、跳石板
小易来到了一条石板路前,每块石板上从1挨着编号为:1、2、3…这条石板路要根据特殊的规则才能前进:对于小易当前所在的编号为K的 石板,小易单次只能往前跳K的一个约数(不含1和K)步,即跳到 K+X 的位置。
小易当前处在编号为 N 的石板,他想跳到编号恰好为M的石板去,小易想知道最少需要跳跃几次可以到达
例如:N = 4,M = 24
跳跃次数为:4->6->8->12->18->24
于是小易最少需要跳跃5次,就可以从4号石板跳到24号石板
输入描述:输入为一行,有两个整数N,M,以空格隔开。 (4 ≤ N ≤ 100000) (N ≤ M ≤ 100000)
输出描述:输出小易最少需要跳跃的步数,如果不能到达输出 -1
输入:4 24
输出:5
思路:动态规划
初始化大小为 M+1 数组 stepNum
,把下标4的位置赋值1,其余都为0;
stepNum[i]
代表的是,从初始位置到 i
的步数+1,加1可以不用管,因为最后减去1就行了.
每到达一个步数,计算可以走的次数,比如走到了 15 的位置,把可以走的步数 [3,5] 保存到一个容器中,然后遍历.
转义方程:伪代码,i
为当前位置,divNum[j]
为可以走的距离,divNum[j]+i
代表可以到达的位置.
if divNum[j] + i <= M
if stepNum[divNum[j] + i] != 0
stepNum[divNum[j] + i] = min(stepNum[divNum[j] + i], stepNum[i] + 1);
else
stepNum[divNum[j] + i] = stepNum[i] + 1;
参考代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 计算约数,求除了 1 和本身的约数
void divisorNum(int n, vector<int> &divNum){
for (int i = 2; i <= sqrt(n); i++){
if (n%i == 0){
divNum.push_back(i);
//平方数的另一个数不加入
if (n / i != i){
divNum.push_back(n / i);
}
}
}
}
int Jump(int N, int M){
// 储存的到达此 stepNum 点的步数,初始 N 为 1 步,从 N 到 N 为 1 步
vector<int> stepNum(M + 1, 0);
stepNum[N] = 1;
for (int i = N; i < M; i++){
//N 的所有约数,即为从本身这个点开始能走的数量
vector<int> divNum;
//0 代表这个点不能到
if (stepNum[i] == 0)
continue;
//求出所有能走的步数储存在divNum的容器中
divisorNum(i, divNum);
for (int j = 0; j < divNum.size(); j++){
// 由位置 i 出发能到达的点为 stepNum[divNum[j]+i]
if ((divNum[j] + i) <= M && stepNum[divNum[j] + i] != 0)
stepNum[divNum[j] + i] = min(stepNum[divNum[j] + i], stepNum[i] + 1);
else if ((divNum[j] + i) <= M)
stepNum[divNum[j] + i] = stepNum[i] + 1;
}
}
if (stepNum[M] == 0)
return -1;
else
//初始化时多给了一步,故需要减 1
return stepNum[M] - 1;
}
int main(){
int n, m;
cin >> n >> m;
cout << Jump(n, m) << endl;
return 0;
}