10道C++输出易错笔试题收集(敢进来挑战吗?)

下面这些题目都是我之前准备笔试面试过程中积累的,大部分都是知名公司的笔试题,C++基础薄弱的很容易栽进去。我从中选了10道简单的题,C++初学者可以进来挑战下,C++大牛也可以作为娱乐玩下(比如下面的第6题)。为了便于大家思考,将题目与答案分开,不过无论题目本身如何,我觉得后面的解析过程更值得学习,因为涉及很多我们学习C++过程中必知必会的小知识点 。

第一部分:题目

  1. 如下函数,在32 bit系统foo(2^31-3)的值是:()
    int foo(int x)
    {
        return x&-x;
    }
    

A:0 B: 1 C: 2 D: 4

  1. 运算符优先级
    unsigned char i=0x80;
    printf("0x%x\n", ~i>>3+1);
    输出什么?

  2. 静态对象是否调用构造函数?

    #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 0;
    }
    
  3. union问题

    #include <stdio.h>
     
    union
    {
        int i;
        char x[2];
    }a;
    int main()
    {
        a.x[0] = 10;
        a.x[1] = 1;
        printf("%d",a.i);
        return 0;
    }
    
  4. 下面代码会报错吗?为什么?

class A {
public:
     int m;
     void print() {  cout << "A\n";  } 
};
 A *pa = 0;
 pa->print();
  1. 下面代码的输出是什么?(非常考基础水平的一道题)
char *c[] = {"ENTER","NEW","POINT","FIRST"};  
char **cp[] = { c + 3 , c + 2 , c + 1 , c};  
char ***cpp = cp;  
int main(void)  
{  
    printf("%s",**++cpp);  
    printf("%s",*--*++cpp+3);  
    printf("%s",*cpp[-2]+3);  
    printf("%s\n",cpp[-1][-1]+1);  
  
    return 0;  
}  
  1. 结构体
#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 + 4)));
 return 0;
}
  1. 改变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 0;
}
  1. 静态变量的输出
#include <stdio.h>
int sum(int a) {
    int c = 0;
    static int b = 3; // 只执行一次
    c++;
    b += 2;
    return (a + b + c);
}
int main() {
    int i;
    int a = 2;
    for(i = 0; i < 5; ++i) {
        printf("%d\n", sum(a));
    }
    return 0;
}
  1. 返回值加const修饰的必要性
    你觉得下面两种写法有区别吗?
int GetInt(void) 
const int GetInt(void)

如果是下面的呢?其中A 为用户自定义的数据类型。

A GetA(void)
const A GetA(void)

<p>
</p>


第二部分:答案详细解析

  1. 如下函数,在32 bit系统foo(2^31-3)的值是:
    int foo(int x)
    {
        return x&-x;
    }
    

A:0 B: 1 C: 2 D: 4
答案:C
解释:我只想说注意运算符优先级,注意^是异或而不是幂次方。

  1. 运算符优先级
    unsigned char i=0x80;
    printf("0x%x\n", ~i>>3+1);输出什么?
    输出:0xfffffff7(提示:+的优先级优于>>)
    如果将unsigned去掉,则输出0x7。

  2. 静态对象是否调用构造函数?

    #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 0;
    }
    

输出:

B's Constructor Called

解释:上面的程序只是调用了B的构造函数,没有调用A的构造函数。因为静态成员变量只是在类中声明,没有定义。静态成员变量必须在类外使用作用域标识符显式定义。
如果我们没有显式定义静态成员变量a,就试图访问它,编译会出错,比如下面的程序编译出错:
```cpp
#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 0;
}
```

输出:

Compiler Error: undefined reference to `B::a

如果我们加上a的定义,那么上面的程序可以正常运行,
注意:如果A是个空类,没有数据成员x,则就算B中的a未定义也还是能运行成功的,即可以访问A。
```cpp
#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 0;
}
```

输出:

A's constructor called
B's constructor called
B's constructor called
B's constructor called

上面的程序调用B的构造函数3次,但是只调用A的构造函数一次,因为静态成员变量被所有对象共享,这也是它被称为类变量的原因。同时,静态成员变量也可以通过类名直接访问,比如下面的程序没有通过任何类对象访问,只是通过类访问a。
```cpp
int main()
{
// static member 'a' is accessed without any object of B
A a = B::getA();

    return 0;
}
```

输出:

A's constructor called

  1. union问题
    #include <stdio.h>
     
    union
    {
        int i;
        char x[2];
    }a;
    int main()
    {
        a.x[0] = 10;
        a.x[1] = 1;
        printf("%d",a.i);
        return 0;
    }
    

输出:266,自己画个内存结构图就知道了,注意union的存放顺序是所有成员都从低地址开始存放。Union的大小为其内部所有变量的最大值,并且按照类型最大值的整数倍进行内存对齐。

  1. 下面代码会报错吗?为什么?
class A {
public:
     int m;
     void print() {  cout << "A\n";  } 
};
 A *pa = 0;
 pa->print();

答案:正常输出。上面的代码可以这样理解(这非常重要):

void print(A *this) {  cout << "A\n";  } 
A *pa = 0;
print_A(); 

也就是:并不是类没有初始化就不能调用类的成员函数,如果成员函数只是简单的打印个东西,没有调用类成员啥的就不会报段错误。

  1. 下面代码的输出是什么?(非常考基础水平的一道题)
char *c[] = {"ENTER","NEW","POINT","FIRST"};  
char **cp[] = { c + 3 , c + 2 , c + 1 , c};  
char ***cpp = cp;  
int main(void)  
{  
    printf("%s",**++cpp);  
    printf("%s",*--*++cpp+3);  
    printf("%s",*cpp[-2]+3);  
    printf("%s\n",cpp[-1][-1]+1);  
  
    return 0;  
}  

解答:
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"。
  1. 结构体
#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 + 4)));
 return 0;
}

输出:4 2
说明:一般变量都是从高到低分配内存地址,但对于结构体来说,结构体的成员在内存中顺序存放,所占内存地址依次增高,第一个成员处于低地址处,最后一个成员处于最高地址处,但结构体成员的内存分配不一定是连续的,编译器会对其成员变量依据前面介绍的 “对齐”原则进行处理。

结构体内存分布图

补充知识点:

除了栈以外,堆、只读数据区、全局变量地址增长方向都是从低到高的。

  1. 改变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 0;
}

输出:仍为“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 0;
}
  1. 静态变量的输出
#include <stdio.h>
int sum(int a) {
    int c = 0;
    static int b = 3; // 只执行一次
    c++;
    b += 2;
    return (a + b + c);
}
int main() {
    int i;
    int a = 2;
    for(i = 0; i < 5; ++i) {
        printf("%d\n", sum(a));
    }
    return 0;
}

输出:8 10 12 14 16
解释:存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化,此后该初始化不再执行,相当于一次执行后就作废,静态局部变量保存了前次被调用后留下的值。

  1. 返回值加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&修饰),这样可以获得编译器的帮助,以便写出健壮性的代码

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容