10道C++输出易错笔试题收集
下面这些题目都是我之前准备笔试面试过程中积累的,大部分都是知名公司的笔试题,C++基础薄弱的很容易栽进去。我从中选了10道简单的题,C++初学者可以进来挑战下,C++大牛也可以作为娱乐玩下(比如下面的第6题)。为了便于大家思考,将题目与答案分开,不过无论题目本身如何,我觉得后面的解析过程更值得学习,因为涉及很多我们学习C++过程中必知必会的小知识点 。
第一部分:题目
如下函数,在32 bit系统foo(2^31-3)的值是:()
int foo(int x)
{
return x&-x;
}A:0 B: 1 C: 2 D: 4
运算符优先级
unsigned char i=0x80;
printf("0x%x\n", ~i>>3+1);
输出什么?静态对象是否调用构造函数?
#include <iostream>
using namespace std; class A
{
public:
A() { cout << "A's Constructor Called " << endl; }
}; class B
{
static A a;
public:
B() { cout << "B's Constructor Called " << endl; }
}; int main()
{
B b;
return ;
}union问题
#include <stdio.h> union
{
int i;
char x[];
}a;
int main()
{
a.x[] = ;
a.x[] = ;
printf("%d",a.i);
return ;
}下面代码会报错吗?为什么?
class A {
public:
int m;
void print() { cout << "A\n"; }
};
A *pa = ;
pa->print();下面代码的输出是什么?(非常考基础水平的一道题)
char *c[] = {"ENTER","NEW","POINT","FIRST"};
char **cp[] = { c + , c + , c + , c};
char ***cpp = cp;
int main(void)
{
printf("%s",**++cpp);
printf("%s",*--*++cpp+);
printf("%s",*cpp[-]+);
printf("%s\n",cpp[-][-]+); return ;
}结构体
#include <stdio.h>
struct data
{
int a;
unsigned short b;
};
int main(void)
{
data mData;
mData.b = 0x0102;
char *pData = (char *)&mData;
printf("%d %d", sizeof(pData), (int)(*(pData + )));
return ;
}改变string变量的值?
#include <iostream>
#include <string>
using namespace std;
void chg_str(string str) {
str = "ichgit";
}
int main() {
string s = "sarrr";
chg_str(s); printf("%s\n", s.c_str());
cout << s << endl;
return ;
}静态变量的输出
#include <stdio.h>
int sum(int a) {
int c = ;
static int b = ; // 只执行一次
c++;
b += ;
return (a + b + c);
}
int main() {
int i;
int a = ;
for(i = ; i < ; ++i) {
printf("%d\n", sum(a));
}
return ;
}返回值加const修饰的必要性
你觉得下面两种写法有区别吗?int GetInt(void)
const int GetInt(void)如果是下面的呢?其中A 为用户自定义的数据类型。
A GetA(void)
const A GetA(void)
第二部分:答案详细解析
如下函数,在32 bit系统foo(2^31-3)的值是:
int foo(int x)
{
return x&-x;
}A:0 B: 1 C: 2 D: 4
答案:C
解释:我只想说注意运算符优先级,注意^是异或而不是幂次方。运算符优先级
unsigned char i=0x80;
printf("0x%x\n", ~i>>3+1);
输出什么?输出:0xfffffff7(提示:+的优先级优于>>)
如果将unsigned去掉,则输出0x7。静态对象是否调用构造函数?
#include <iostream>
using namespace std; class A
{
public:
A() { cout << "A's Constructor Called " << endl; }
}; class B
{
static A a;
public:
B() { cout << "B's Constructor Called " << endl; }
}; int main()
{
B b;
return ;
}输出:
B's Constructor Called
解释:上面的程序只是调用了B的构造函数,没有调用A的构造函数。因为静态成员变量只是在类中声明,没有定义。静态成员变量必须在类外使用作用域标识符显式定义。
如果我们没有显式定义静态成员变量a,就试图访问它,编译会出错,比如下面的程序编译出错:#include <iostream>
using namespace std; class A
{
int x;
public:
A() { cout << "A's constructor called " << endl; }
}; class B
{
static A a;
public:
B() { cout << "B's constructor called " << endl; }
static A getA() { return a; }
}; int main()
{
B b;
A a = b.getA();
return ;
}输出:
Compiler Error: undefined reference to `B::a
如果我们加上a的定义,那么上面的程序可以正常运行,
注意:如果A是个空类,没有数据成员x,则就算B中的a未定义也还是能运行成功的,即可以访问A。#include <iostream>
using namespace std; class A
{
int x;
public:
A() { cout << "A's constructor called " << endl; }
}; class B
{
static A a;
public:
B() { cout << "B's constructor called " << endl; }
static A getA() { return a; }
}; A B::a; // definition of a int main()
{
B b1, b2, b3;
A a = b1.getA(); return ;
}输出:
A's constructor called
B's constructor called
B's constructor called
B's constructor called上面的程序调用B的构造函数3次,但是只调用A的构造函数一次,因为静态成员变量被所有对象共享,这也是它被称为类变量的原因。同时,静态成员变量也可以通过类名直接访问,比如下面的程序没有通过任何类对象访问,只是通过类访问a。
int main()
{
// static member 'a' is accessed without any object of B
A a = B::getA(); return ;
}输出:
A's constructor called
union问题
#include <stdio.h> union
{
int i;
char x[];
}a;
int main()
{
a.x[] = ;
a.x[] = ;
printf("%d",a.i);
return ;
}输出:266,自己画个内存结构图就知道了,注意union的存放顺序是所有成员都从低地址开始存放。Union的大小为其内部所有变量的最大值,并且按照类型最大值的整数倍进行内存对齐。
下面代码会报错吗?为什么?
class A {
public:
int m;
void print() { cout << "A\n"; }
};
A *pa = ;
pa->print();答案:正常输出。上面的代码可以这样理解(这非常重要):
void print(A *this) { cout << "A\n"; }
A *pa = ;
print_A();也就是:并不是类没有初始化就不能调用类的成员函数,如果成员函数只是简单的打印个东西,没有调用类成员啥的就不会报段错误。
下面代码的输出是什么?(非常考基础水平的一道题)
char *c[] = {"ENTER","NEW","POINT","FIRST"};
char **cp[] = { c + , c + , c + , c};
char ***cpp = cp;
int main(void)
{
printf("%s",**++cpp);
printf("%s",*--*++cpp+);
printf("%s",*cpp[-]+);
printf("%s\n",cpp[-][-]+); return ;
}解答:
c是一个指针数组,每个数组元素都是char*类型的指针,值分别是那些字符串(的首地址):c[0] = "ENTER"
c[1] = "NEW"
c[2] = "POINT"
c[3] = "FIRST"而[]和*是本质一样的运算,即
c[i]=*(c+i)
。c和c+i都是char *[]类型,它可以退化成char **类型,再看cp,它正好是一个char **的数组,来看它的值:
cp[0] = c + 3
cp[1] = c + 2
cp[2] = c + 1
cp[3] = c引用后就有:
cp[0][0]=*(c + 3)=c[3]="FIRST"
,以此类推。cp是char **[]类型,它可以退化成char ***类型,看最后的cpp,它正是char ***类型,它是一个指针变量,和上面两个不同,上面两个是数组。
这样分析过后,下面的解析就一目了然了:
printf("%s",**++cpp);
++cpp的值是cp+1,引用一次后是cp[1]再引用是*cp[1]=c[2]="POINT",第一句的输出printf("%s",*--*++cpp+3);
再++cpp的值是cp+2,引用一次是cp[2]=c+1,再对这进行--,减后是c再引用是c[0]="ENTER"再+3,字符串指针指到"ER",输出是"ER"printf("%s",*cpp[-2]+3);
这时cpp的值是cp+2,cpp[-2]=*(cpp-2)=*(cp+2-2)=cp[0]=c+3,再引用是c[3]="FIRST",+3 字符串指针指到"ST",输出是"ST"printf("%s\n",cpp[-1][-1]+1);
cpp还是cp+2,cpp[-1]=*(cpp-1)=*(cp+2-1)=cp[1]=c+2,再[-1]得*(c+2-1)=c[1]="NEW",+1字符串指针指到"EW",输出是"EW"。
结构体
#include <stdio.h>
struct data
{
int a;
unsigned short b;
};
int main(void)
{
data mData;
mData.b = 0x0102;
char *pData = (char *)&mData;
printf("%d %d", sizeof(pData), (int)(*(pData + )));
return ;
}输出:4 2
说明:一般变量都是从高到低分配内存地址,但对于结构体来说,结构体的成员在内存中顺序存放,所占内存地址依次增高,第一个成员处于低地址处,最后一个成员处于最高地址处,但结构体成员的内存分配不一定是连续的,编译器会对其成员变量依据前面介绍的 “对齐”原则进行处理。
补充知识点:
除了栈以外,堆、只读数据区、全局变量地址增长方向都是从低到高的。
改变string变量的值?
#include <iostream>
#include <string>
using namespace std;
void chg_str(string str) {
str = "ichgit";
}
int main() {
string s = "sarrr";
chg_str(s); printf("%s\n", s.c_str());
cout << s << endl;
return ;
}输出:仍为“sarrr”。
解释:string是传值参数,不能修改其值。要想改变string变量的值,可以改为传地址方式:#include <iostream>
#include <string>
using namespace std;
void chg_str(string *str) {
*str = "ichgit";
}
int main() {
string s = "sarrr";
chg_str(&s); printf("%s\n", s.c_str());
cout << s << endl;
return ;
}静态变量的输出
#include <stdio.h>
int sum(int a) {
int c = ;
static int b = ; // 只执行一次
c++;
b += ;
return (a + b + c);
}
int main() {
int i;
int a = ;
for(i = ; i < ; ++i) {
printf("%d\n", sum(a));
}
return ;
}输出:8 10 12 14 16
解释:存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化,此后该初始化不再执行,相当于一次执行后就作废,静态局部变量保存了前次被调用后留下的值。返回值加const修饰的必要性
你觉得下面两种写法有区别吗?int GetInt(void)
const int GetInt(void)如果是下面的呢?其中A 为用户自定义的数据类型。
A GetA(void)
const A GetA(void)答案:没有任何区别。
解释:如果函数返回值采用“值传递方式”,由于函数会把返回值复制到外部临时的存储单元中,加const 修饰没有任何价值。所以,对于值传递来说,加const没有太多意义。
所以:- 不要把函数int GetInt(void) 写成const int GetInt(void)。
- 不要把函数A GetA(void) 写成const A GetA(void)。
在编程中要尽可能多的使用const(比如函数参数采用const&修饰),这样可以获得编译器的帮助,以便写出健壮性的代码。
10道C++输出易错笔试题收集的更多相关文章
- 【转载】经典10道c/c++语言经典笔试题(含全部所有参考答案)
经典10道c/c++语言经典笔试题(含全部所有参考答案) 1. 下面这段代码的输出是多少(在32位机上). char *p; char *q[20]; char *m[20][20]; int (*n ...
- 10道不得不会的JavaEE面试题
10道不得不会的 JavaEE 面试题 我是 JavaPub,专注于面试.副业,技术人的成长记录. 以下是 JavaEE 面试题,相信大家都会有种及眼熟又陌生的感觉.看过可能在短暂的面试后又马上忘记了 ...
- 《java入门第一季》之面向对象(一个易错面试题)
这个面试题有点难度,有一些饶.不明白可以在下面讨论.还是值得搞懂的. / * 看程序写结果: A:成员变量的问题 int x = 10; //成员变量x是基本类型 Student s = new St ...
- python 饥饿的小易(网易笔试题)
本周早些时候,学弟给我发了一道网易的笔试题,饥饿的小易,感觉有点意思-分享给大家 题目描述: 小易总是感觉饥饿,所以作为章鱼的小易经常出去寻找贝壳吃.最开始小易在一个初始位置x_0.对于小易所处的当前 ...
- Java五道输出易错题解析(避免小错误)
收集了几个易错的或好玩的Java输出题,分享给大家,以后在编程学习中稍微注意下就OK了. 1. 看不见的空格? 下面的输出会正常吗? package basic; public class Integ ...
- Java五道输出易错题解析(进来挑战下)
转自:http://blog.csdn.net/lanxuezaipiao/article/details/41985243 收集了几个易错的或好玩的Java输出题,分享给大家,以后在编程学习中稍微注 ...
- 中高级JavaScript易错面试题
写出下题的输出 1.函数的实参与形参length var length = 10; function fn() { console.log(this.length); } var obj = { le ...
- 编程菜鸟的日记-初学尝试编程-易传媒笔试题(C++实现)
题目:已知存在两个非递减的有序链表List1和List2,现在需要你将两个链表合并成一个有序的非递增序列链表List3,请用C++编码实现.(所有链表均为单链表结构) 思路:此处链表是否都有表头并没有 ...
- 【web后端开发】笔试题收集
4399Web后端开发笔试题 题目来源:牛客网 1.linux中,用mkdir命令创建新的目录时,如果需要在其父目录不存在时先创建父目录的选项是 D A -h B -d C -f D -p [ ...
随机推荐
- 关于个人博客和Github地址提交
请大家尽快按照http://www.cnblogs.com/SivilTaram/p/5857858.html的要求提交个人博客和Github地址.谢谢!
- Convert和Parse对null值处理的区别
类型的转换在日常的变成中是经常被用到的,我们最常用的类型转换的方法就是Convert和Parse, 下面来说一下这两者null值处理的区别. int i1 = Convert.ToInt32(null ...
- 系统安全扫描工具(appscan)的扫描类型小记
扫描分类 不同场景需要使用不同方式的扫描类型.不能盲目的.暴力的去折腾. 自动扫描 刚开始扫描的时候适合用这种方式.有助于,理解整个网站的结构. 需要注意的是:去伪静态和业务冗余 伪静态 url结构相 ...
- 《TCP/IP详解卷1:协议》第11章 UDP:用户数据报协议-读书笔记
章节回顾: <TCP/IP详解卷1:协议>第1章 概述-读书笔记 <TCP/IP详解卷1:协议>第2章 链路层-读书笔记 <TCP/IP详解卷1:协议>第3章 IP ...
- 07.C#泛型的限制和可空类型的简单说明(三章3.5-四章4.1)
自己在写文章的同时,也是在学习,对于书中的语句很多其实没有太好的理解,读一本书,要消化!!!三章都是讲泛型的,最后写一下泛型的限制,对于本章学习的完结,one end,one begin. 看下面的代 ...
- 思甜雅--关于qq的NABCD模型分析
个人连接:http://www.cnblogs.com/xiaoliulang/ 关于QQ的NABCD模型 N--Need 随着电脑的普及,人们在网络上进行交流的时间越来越多,由于现有的交流工具还不是 ...
- Git代码管理心得
一.概述: 这次按照要求进行了看似复杂,实则非常复杂并且麻烦(网上教程众多且啰嗦)的对git使用的学习,从星期六晚18:48我准备这次作业开始,直到了晚上22:44才结束电脑上的操作···(导致这篇随 ...
- iOS开发获取本机手机号码
最近有个奇葩需求,用户登录返回手机号匹配本机号码相同才可以登录,吓得我虎躯一震,经了解,iOS7后不越狱实现不了 "For security reasons, iPhone OS restr ...
- 利用HTML5的Video进行视频截图并保存到本地
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
- 【UVA 11401】Triangle Counting
题 题意 求1到n长度的n根棍子(3≤n≤1000000)能组成多少不同三角形. 分析 我看大家的递推公式都是 a[i]=a[i-1]+ ((i-1)*(i-2)/2-(i-1)/2)/2; 以i 为 ...