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

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

第一部分:题目

  1. 如下函数,在32 bit系统foo(2^31-3)的值是:()

    1. int foo(int x)
    2. {
    3. return x&-x;
    4. }

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

  2. 运算符优先级 
    unsigned char i=0x80; 
    printf("0x%x\n", ~i>>3+1); 
    输出什么?
  3. 静态对象是否调用构造函数?
    1. #include <iostream>
    2. using namespace std;
    3. class A
    4. {
    5. public:
    6. A() { cout << "A‘s Constructor Called " << endl; }
    7. };
    8. class B
    9. {
    10. static A a;
    11. public:
    12. B() { cout << "B‘s Constructor Called " << endl; }
    13. };
    14. int main()
    15. {
    16. B b;
    17. return 0;
    18. }
  4. union问题
    1. #include <stdio.h>
    2. union
    3. {
    4. int i;
    5. char x[2];
    6. }a;
    7. int main()
    8. {
    9. a.x[0] = 10;
    10. a.x[1] = 1;
    11. printf("%d",a.i);
    12. return 0;
    13. }
  5. 下面代码会报错吗?为什么?
    1. class A {
    2. public:
    3. int m;
    4. void print() { cout << "A\n"; }
    5. };
    6. A *pa = 0;
    7. pa->print();
  6. 下面代码的输出是什么?(非常考基础水平的一道题)
    1. char *c[] = {"ENTER","NEW","POINT","FIRST"};
    2. char **cp[] = { c + 3 , c + 2 , c + 1 , c};
    3. char ***cpp = cp;
    4. int main(void)
    5. {
    6. printf("%s",**++cpp);
    7. printf("%s",*--*++cpp+3);
    8. printf("%s",*cpp[-2]+3);
    9. printf("%s\n",cpp[-1][-1]+1);
    10. return 0;
    11. }
  7. 结构体
    1. #include <stdio.h>
    2. struct data
    3. {
    4. int a;
    5. unsigned short b;
    6. };
    7. int main(void)
    8. {
    9. data mData;
    10. mData.b = 0x0102;
    11. char *pData = (char *)&mData;
    12. printf("%d %d", sizeof(pData), (int)(*(pData + 4)));
    13. return 0;
    14. }
  8. 改变string变量的值?
    1. #include <iostream>
    2. #include <string>
    3. using namespace std;
    4. void chg_str(string str) {
    5. str = "ichgit";
    6. }
    7. int main() {
    8. string s = "sarrr";
    9. chg_str(s);
    10. printf("%s\n", s.c_str());
    11. cout << s << endl;
    12. return 0;
    13. }
  9. 静态变量的输出
    1. #include <stdio.h>
    2. int sum(int a) {
    3. int c = 0;
    4. static int b = 3; // 只执行一次
    5. c++;
    6. b += 2;
    7. return (a + b + c);
    8. }
    9. int main() {
    10. int i;
    11. int a = 2;
    12. for(i = 0; i < 5; ++i) {
    13. printf("%d\n", sum(a));
    14. }
    15. return 0;
    16. }
  10. 返回值加const修饰的必要性 
    你觉得下面两种写法有区别吗?
    1. int GetInt(void)
    2. const int GetInt(void)

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

    1. A GetA(void)
    2. const A GetA(void)

第二部分:答案详细解析

  1. 如下函数,在32 bit系统foo(2^31-3)的值是:

    1. int foo(int x)
    2. {
    3. return x&-x;
    4. }

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

  2. 运算符优先级 
    unsigned char i=0x80; 
    printf("0x%x\n", ~i>>3+1);输出什么? 
    输出:0xfffffff7(提示:+的优先级优于>>) 
    如果将unsigned去掉,则输出0x7。
  3. 静态对象是否调用构造函数?
    1. #include <iostream>
    2. using namespace std;
    3. class A
    4. {
    5. public:
    6. A() { cout << "A‘s Constructor Called " << endl; }
    7. };
    8. class B
    9. {
    10. static A a;
    11. public:
    12. B() { cout << "B‘s Constructor Called " << endl; }
    13. };
    14. int main()
    15. {
    16. B b;
    17. return 0;
    18. }

    输出:

    B‘s Constructor Called

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

    1. #include <iostream>
    2. using namespace std;
    3. class A
    4. {
    5. int x;
    6. public:
    7. A() { cout << "A‘s constructor called " << endl; }
    8. };
    9. class B
    10. {
    11. static A a;
    12. public:
    13. B() { cout << "B‘s constructor called " << endl; }
    14. static A getA() { return a; }
    15. };
    16. int main()
    17. {
    18. B b;
    19. A a = b.getA();
    20. return 0;
    21. }

    输出:

    Compiler Error: undefined reference to `B::a

    如果我们加上a的定义,那么上面的程序可以正常运行, 
    注意:如果A是个空类,没有数据成员x,则就算B中的a未定义也还是能运行成功的,即可以访问A。

    1. #include <iostream>
    2. using namespace std;
    3. class A
    4. {
    5. int x;
    6. public:
    7. A() { cout << "A‘s constructor called " << endl; }
    8. };
    9. class B
    10. {
    11. static A a;
    12. public:
    13. B() { cout << "B‘s constructor called " << endl; }
    14. static A getA() { return a; }
    15. };
    16. A B::a; // definition of a
    17. int main()
    18. {
    19. B b1, b2, b3;
    20. A a = b1.getA();
    21. return 0;
    22. }

    输出:

    A‘s constructor called 
    B‘s constructor called 
    B‘s constructor called 
    B‘s constructor called

    上面的程序调用B的构造函数3次,但是只调用A的构造函数一次,因为静态成员变量被所有对象共享,这也是它被称为类变量的原因。同时,静态成员变量也可以通过类名直接访问,比如下面的程序没有通过任何类对象访问,只是通过类访问a。

    1. int main()
    2. {
    3. // static member ‘a‘ is accessed without any object of B
    4. A a = B::getA();
    5. return 0;
    6. }

    输出:

    A‘s constructor called

  4. union问题
    1. #include <stdio.h>
    2. union
    3. {
    4. int i;
    5. char x[2];
    6. }a;
    7. int main()
    8. {
    9. a.x[0] = 10;
    10. a.x[1] = 1;
    11. printf("%d",a.i);
    12. return 0;
    13. }

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

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

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

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

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

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

    解答: 
    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"。
  7. 结构体
    1. #include <stdio.h>
    2. struct data
    3. {
    4. int a;
    5. unsigned short b;
    6. };
    7. int main(void)
    8. {
    9. data mData;
    10. mData.b = 0x0102;
    11. char *pData = (char *)&mData;
    12. printf("%d %d", sizeof(pData), (int)(*(pData + 4)));
    13. return 0;
    14. }

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

    补充知识点:

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

  8. 改变string变量的值?
    1. #include <iostream>
    2. #include <string>
    3. using namespace std;
    4. void chg_str(string str) {
    5. str = "ichgit";
    6. }
    7. int main() {
    8. string s = "sarrr";
    9. chg_str(s);
    10. printf("%s\n", s.c_str());
    11. cout << s << endl;
    12. return 0;
    13. }

    输出:仍为“sarrr”。 
    解释:string是传值参数,不能修改其值。要想改变string变量的值,可以改为传地址方式:

    1. #include <iostream>
    2. #include <string>
    3. using namespace std;
    4. void chg_str(string *str) {
    5. *str = "ichgit";
    6. }
    7. int main() {
    8. string s = "sarrr";
    9. chg_str(&s);
    10. printf("%s\n", s.c_str());
    11. cout << s << endl;
    12. return 0;
    13. }
  9. 静态变量的输出
    1. #include <stdio.h>
    2. int sum(int a) {
    3. int c = 0;
    4. static int b = 3; // 只执行一次
    5. c++;
    6. b += 2;
    7. return (a + b + c);
    8. }
    9. int main() {
    10. int i;
    11. int a = 2;
    12. for(i = 0; i < 5; ++i) {
    13. printf("%d\n", sum(a));
    14. }
    15. return 0;
    16. }

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

  10. 返回值加const修饰的必要性 
    你觉得下面两种写法有区别吗?
    1. int GetInt(void)
    2. const int GetInt(void)

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

    1. A GetA(void)
    2. const A GetA(void)

    答案:没有任何区别。 
    解释:如果函数返回值采用“值传递方式”,由于函数会把返回值复制到外部临时的存储单元中,加const 修饰没有任何价值。所以,对于值传递来说,加const没有太多意义。 
    所以:

    • 不要把函数int GetInt(void) 写成const int GetInt(void)。
    • 不要把函数A GetA(void) 写成const A GetA(void)。

    在编程中要尽可能多的使用const(比如函数参数采用const&修饰),这样可以获得编译器的帮助,以便写出健壮性的代码。

时间: 2024-10-14 19:16:22

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

10道C++输出易错笔试题收集

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

【转载】经典10道c/c++语言经典笔试题(含全部所有参考答案)

经典10道c/c++语言经典笔试题(含全部所有参考答案) 1. 下面这段代码的输出是多少(在32位机上). char *p; char *q[20]; char *m[20][20]; int (*n)[10]; struct MyStruct { char dda; double dda1; int type ; }; MyStruct k; printf("%d %d %d %d %d",sizeof(p),sizeof(q),sizeof(m),sizeof(n),sizeof(

一道简单易错笔试题

#include<stdio.h> int main(int argc, char* argv[]) { char c=128; printf("十进制c=%d\n",c); printf("十六进制c=0X%0X\n",c); return 0; } 结果为 十进制c= -128: 十六进制c=0XFFFFFF80: 解析: 128的十六进制是0x80, 也就是2^7, 二进制看起来像这样:1000 0000 ,赋值给有符号数char c,其二进制不变

ios笔试题收集(持续更新)

IOS开发笔试题目 一.OC语法部分: 1. NSObject 中description属性的意义,它可以重写吗 用法举例:定义一个Person类,声明两个成员变量 @interface Person : NSObject { NSString * name; int age; } 在类的实现中,init方法初始化成员变量 @implementation Person - (instancetype)init { self = [super init]; if (self) { name = @

python 饥饿的小易(网易笔试题)

本周早些时候,学弟给我发了一道网易的笔试题,饥饿的小易,感觉有点意思-分享给大家 题目描述: 小易总是感觉饥饿,所以作为章鱼的小易经常出去寻找贝壳吃.最开始小易在一个初始位置x_0.对于小易所处的当前位置x,他只能通过神秘的力量移动到 4 * x + 3或者c.因为使用神秘力量要耗费太多体力,所以它只能使用神秘力量最多100,000次.贝壳总生长在能被1,000,000,007整除的位置(比如:位置0,位置1,000,000,007,位置2,000,000,014等).小易需要你帮忙计算最少需要

Java五道输出易错题解析(进来挑战下)

收集了几个易错的或好玩的Java输出题,分享给大家,以后在编程学习中稍微注意下就OK了. 1. 看不见的空格? 下面的输出会正常吗? package basic; public class IntegerTest { public static void main(String[] args) { System.out.println(Integer.parseInt("1")); System.out.println(Integer.parseInt("?2"))

Java五道输出易错题解析(避免小错误)

收集了几个易错的或好玩的Java输出题,分享给大家,以后在编程学习中稍微注意下就OK了. 1. 看不见的空格? 下面的输出会正常吗? package basic; public class IntegerTest { public static void main(String[] args) { System.out.println(Integer.parseInt("1")); System.out.println(Integer.parseInt("2"));

【苏宁易购笔试题】冒泡排序把数字“1492586&quot;排序成&quot;9865421&quot;然后生成新的字符串。

public class Bubble { public static void main(String[] args) { // TODO Auto-generated method stub String initial = "1492586"; StringBuffer sb = new StringBuffer(""); int[] array = new int[initial.length()]; for (int i = 0; i < initi

C#.NET笔试题收集

写在前面 一题一题过,基本都亲自测试:不定期收录更新,欢迎拍砖(请轻拍~). 跳槽是真的累,要准备笔试面试~ 本文大纲: 填空或简述题 程序或编程题 数据库题 一.填空或简述题: 1. c#中错误处理机制有哪些 答:Try catch finally throw: 2. public/protect/private/internal修饰符的区别 答:Public:公共的,都能访问: Protect:受保护的,只有该类和派生类能访问: Private:私有的,只有该类可以访问: Internal: