重拾C++经典笔试30题(11-20)

简介: 重拾C++经典笔试30题(11-20)

11. C++对象模型基本概念之程序使用内存区


计算机程序主要由代码+数据组成,两部分是影响一个程序所需内存的重要因素。


数据区存储分类


存储内容


全局/静态数据区


全局变量及静态变量(全局静态变量、局部静态变量)


常量数据区


存储程序中的常量字符串等



存储自动变量或局部变量,以及传递的函数参数等



用户控制的存储区,存储动态产生的数据


代码区


程序中代码


12.不被重视的sizeof()大小问题。


(1)情况一


int a = 8;


cout<< sizeof(a=6) <<endl; //a=6是不被编译的,只是转换为a的类型。


cout<< a<< endl; //8


注意:sizeof(a=6)在编译过程中是不被翻译的,而是被替代类型。


(2)情况二,求函数大小等价于其对应返回值的大小。


int fun1()

{

    return 0;

}

void fun2()

{

}

char fun3()

{

    return 'c';

}

double fun4()

{

        return 0.0;

}

       cout << sizeof(fun1()) <<endl; //4

       cout << sizeof(fun2()) <<endl; //error C2070:illegal sizeof operand**

       cout << sizeof(fun3()) <<endl; //1

       cout<< sizeof(fun4()) <<endl; //8


(3)情况三,求数组大小。


char c[2][3] ={"a",""};


cout <<sizeof(c) << endl; //2*3*1


(4)情况四,括号、给数组大小赋值(主要原因,编译的时候已经计算过sizeof大小了)。


 


       int na = 35;

        //等价于sizeof(na),如果是变量名,可以不加括号。

        cout << sizeof na << endl;

        cout << sizeof(int)<<endl;

        int nArray[25] = {0};

        //可以通过sizeof( )定义数组的大小,等价于new int[100].

        int *pArray = new int[sizeof(nArray)];

13.深究结构体地址对齐的原则及应用实例


struct simpleA

{

        float f; //0

        char p; //4

        int adf[3]; //5—>8[按照基本数据类型对齐,第一个对齐了后面的自然也就对齐了]

};//8+12-->20

这里有三点很重要:


(1)每个成员分别按自己的方式对齐,并能最小化长度


(2).复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,可以最小化长度;


(3).对齐后的长度必须是成员中最大的对齐参数的整数倍,这样在处理数组时可以保证每一项都边界对齐


补充一下,对于数组,比如:char a[3];这种,它的对齐方式和分别写3个char是一样的。也就是说它还是按1个字节对齐。


如果写:typedef char Array3[3];Array3这种类型的对齐方式还是按1个字节对齐,而不是按它的长度。不论类型是什么,对齐的边界一定是1,2,4,8,16,32,64....中的一个。


总结如下:


数组:按照基本数据类型对齐,第一个对齐了后面的自然也就对齐了。


联合:按其包含的长度最大的数据类型对齐。


结构体:结构体中每个数据类型都要对齐。



14.注意此处错误的原因


void swap1(int* p ,int* q)

{

    int* temp; //单纯的temp会出现temp' used withouthaving beeninitialized

    *temp = *p;

    *p = *q;

    *q = *temp;

}


给随机地址赋值,会有如下的错误提示:




15.地址相减计算


int main()

{

        int a[3];

        a[0] = 0;

        a[1] = 1;

        a[2] = 2;

        int *p, *q;

        p = a;

        q = &a[2];

        cout << p << endl;

        cout << q << endl;

        //q-p等价于[(q的地址值-p的地址值)/sizeof(int)].

        cout << q-p << endl; //2

        cout << a[q-p] <<endl;//a[2] = 2;

        return 0;

}



16.为什么是1?


class A

{

public:

A() { m_a = 1, m_b =2; }

~A(){}

void fun() { printf("%d \t%d\n", m_a, m_b); }

int m_a;

int m_b;

};

class B

{

public:

B() { m_c = 3;}

~B(){}

void fun() {printf("%d\n",m_c); } //为什么是1,思考!

int m_c;

};

int main()

{

A a;

B *pb = (B*)&a;

pb->fun(); //为什么是1,思考!

cout << &a<<endl; //12FF6C

cout << &(a.m_a)<<endl; //12FF6C

printf("%08x\n",&A::m_a);

printf("%08x\n",&A::m_b);

printf("%08x\n",&B::m_c);

return 0;

}

17.一个含有10个指针的数组,该指针指向一个函数,该函数有一个整形参数并返回一个整形数。


int(*p[10])(int)


18.有了malloc/free为什么还用new/delete?


1)malloc/free为C/C++标准库函数;new/delete为C++运算符。他们都可以申请和释放动态内存。


2)只用malloc/free无法满足非内部数据类型的要求;对象在创建的时候自动调用构造函数,在销毁的时候自动调用析构函数;而malloc/free是库函数而不是运算符,不再编译器控制权限之内,所以不能把调用构造函数和析构函数的任务强加给它们。


19.注意下列的取值



int main()

{

int a[] = {1,2,3,4,5};

int *ptr = (int*)(&a+1); //1代表1个sizeof(a)

printf("%d%d\n",*(a+1),*(ptr-1));//2 , 5

return 0;

}

int main()

{

char* a[]={"hello","the","word"};

char** pa = a; //pa为指向字符串数组的指针.

pa++;

cout << *pa << endl; //the

cout << *pa[0] << endl;//t

cout << *(*pa+1)<<endl;//h

cout << *(*pa+2) <<endl;//e

return 0;

}


20.题解:深拷贝+浅显拷贝,为什么?


通俗解释深、浅拷贝:


深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。举个例子,一个人名叫张三,后来用他克隆(假设法律允许)了另外一个人,叫李四,不管是张三缺胳膊少腿还是李四缺胳膊少腿都不会影响另外一个人。


浅拷贝是指源对象与拷贝对象共用一份实体,仅仅是引用的变量不同(名称不同)。对其中任何一个对象的改动都会影响另外一个对象。举个例子,一个人一开始叫张三,后来改名叫李四了,可是还是同一个人,不管是张三缺胳膊少腿还是李四缺胳膊少腿,都是这个人倒霉。


如果在类中没有显式地声明一个拷贝构造函数,那么,编译器将会自动生成一个默认的拷贝构造函数,该构造函数完成对象之间的位拷贝。位拷贝又称浅拷贝。


class CA

{

public:

CA(int b,char* cstr)

{

          cout <<"CAconstructor!" << endl;

          a=b;

          str=new char[b];

          strcpy(str,cstr);

}

void Show()

{

          cout<<str<<endl;

}

~CA()

{

          cout <<"~CAconstructor!" << endl;

          delete str;

}

private:

int a;

char *str;

};

int main()

{

CA A(10,"Hello!");

CA B=A; //此处会调用默认的拷贝构造函数,是为浅拷贝。

B.Show();

//浅拷贝后A,B对象的str字符串是同一个地址。当发生析构时会出现运行报错!

return 0;

}



自定义拷贝构造函数是一种良好的编程风格,它可以阻止编译器形成默认的拷贝构造函数,提高源码效率。


//对比浅拷贝,以下是深拷贝。


#include"stdafx.h"

#include<iostream>

usingnamespace std;

class CA

{

public:

       CA(int b,char* cstr)

        {

                  cout <<"CAconstructor!" << endl;

                  a=b;

                  str=new char[b];

                  strcpy(str,cstr);

        }

        //自定义拷贝构造函数

       CA(constCA& C)

       {

               a=C.a;

               str=newchar[a]; //深拷贝

                 if(str!=0)

               strcpy(str,C.str);

       }

       void Show()

       {

               cout<<str<<endl;

       }

        ~CA()

        {

               cout <<"~CAconstructor!" << endl;

                 delete str;

        }

private:

        int a;

        char *str;

};

int main()

{

       CA A(10,"Hello!");

        CA B=A;

        B.Show();

       return 0;

}

深拷贝和浅拷贝的定义可以简单理解成:如果一个类拥有资源(堆,或者是其它系统资源),当这个类的对象发生复制过程的时候,这个过程就可以叫做深拷贝,反之对象存在资源,但复制过程并未复制资源的情况视为浅拷贝。


浅拷贝资源后在释放资源的时候会产生资源归属不清的情况导致程序运行出错。


相关文章
|
7月前
|
存储 算法 C语言
从C语言到C++_39(C++笔试面试题)next_permutation刷力扣
从C语言到C++_39(C++笔试面试题)next_permutation刷力扣
67 5
|
7月前
|
存储 编译器 C语言
从C语言到C++_22(继承)多继承与菱形继承+笔试选择题(下)
从C语言到C++_22(继承)多继承与菱形继承+笔试选择题
54 1
|
7月前
|
Java 编译器 定位技术
从C语言到C++_22(继承)多继承与菱形继承+笔试选择题(中)
从C语言到C++_22(继承)多继承与菱形继承+笔试选择题
50 0
|
7月前
|
安全 程序员 C语言
从C语言到C++_22(继承)多继承与菱形继承+笔试选择题(上)
从C语言到C++_22(继承)多继承与菱形继承+笔试选择题
58 0
|
7月前
|
C语言 C++
从C语言到C++⑧(第二章_类和对象_下篇_续)笔试选择题和OJ题
从C语言到C++⑧(第二章_类和对象_下篇_续)笔试选择题和OJ题
40 0
|
21天前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
31 2
|
27天前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
70 5
|
1月前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
72 4
|
1月前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
82 4
|
2月前
|
存储 编译器 对象存储
【C++打怪之路Lv5】-- 类和对象(下)
【C++打怪之路Lv5】-- 类和对象(下)
31 4