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

面 这些题目都是我以前准备笔试面试过程当中积累的,大部分都是知名公司的笔试题,C++基础薄弱的很容易栽进去。我从中选了10道简单的题,C++初学者能够 进来挑战下,C++大牛也能够做为娱乐玩下(好比下面的第6题)。为了便于你们思考,将题目与答案分开,不过不管题目自己如何,我以为后面的解析过程更值得学习,由于涉及不少咱们学习C++过程当中必知必会的小知识点 。ios

 

第一部分:题目

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

    int foo(int x) 
    { return x&-x; }
     

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

  2. 运算符优先级 面试

    unsigned char i=0x80;
    printf("0x%x\n", ~i>>3+1);


    输出什么?编程

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

    #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; 
    }
     
  4. 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; 
    }
  5. 下面代码会报错吗?为何?学习

    class A 
    { 
        public: 
            int m; 
            void print() { cout << "A\n"; } 
    }; 
        A *pa = 0; 
        pa->print();

     

  6. 下面代码的输出是什么?(很是考基础水平的一道题)this

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

     

  7. 结构体spa

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

     

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

     

  9. 静态变量的输出

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

     

  10. 返回值加const修饰的必要性
    你以为下面两种写法有区别吗?

    int GetInt(void) 
    const int GetInt(void)

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

    A GetA(void) 
    const A GetA(void)

     


 

第二部分:答案详细解析

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

    int foo(int x) { return x&-x; }

    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. 静态对象是否调用构造函数?
     

    #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

     

  4. 解释:上面的程序只是调用了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 0; 
    }

    输出:

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

    输出:

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

    输出:

    A's constructor called

     

  5. 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的大小为其内部全部变量的最大值,而且按照类型最大值的整数倍进行内存对齐。

     

  6. 下面代码会报错吗?为何?

    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();

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

  7. 下面代码的输出是什么?(很是考基础水平的一道题)

    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"。

     

  8. 结构体

    #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 

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

    补充知识点:

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

 

8.改变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
    解释:存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是惟一的一次初始化,此后该初始化再也不执行,至关于一次执行后就做废,静态局部变量保存了前次被调用后留下的值。
     

  2. 返回值加const修饰的必要性
    你以为下面两种写法有区别吗?
     

    int GetInt(void) 
    const int GetInt(void)

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

    A GetA(void) 
    const A GetA(void)

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

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

    • 不要把函数int GetInt(void) 写成const int GetInt(void)。
    • 不要把函数A GetA(void) 写成const A GetA(void)。
相关文章
相关标签/搜索