天天看點

重拾C++經典筆試30題(11-20)include"stdafx.h"include

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;           

}

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;
           

};

CA A(10,"Hello!");
CA B=A; //此處會調用預設的拷貝構造函數,是為淺拷貝。
B.Show();

//淺拷貝後A,B對象的str字元串是同一個位址。當發生析構時會出現運作報錯!

return 0;           
 

**自定義拷貝構造函數是一種良好的程式設計風格,它可以阻止編譯器形成預設的拷貝構造函數,提高源碼效率。**

//對比淺拷貝,以下是深拷貝。           

include"stdafx.h"

include

usingnamespace std;

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;
     }
           
int a;
     char *str;           
CA A(10,"Hello!");
     CA B=A;
     B.Show();
    return 0;           
 
深拷貝和淺拷貝的定義可以簡單了解成:如果一個類擁有資源(堆,或者是其它系統資源),當這個類的對象發生複制過程的時候,這個過程就可以叫做**深拷貝**,反之對象存在資源,但複制過程并未複制資源的情況視為**淺拷貝**。

淺拷貝資源後在釋放資源的時候會産生資源歸屬不清的情況導緻程式**運作出錯**。
           

繼續閱讀