[C++基礎]C++筆試題中非常常見的sizeof問題

來源:互聯網
上載者:User

sizeof 是一個操作符(operator),其作用返回一個對象或資料類型所佔的記憶體位元組數。

strlen(char*)函數求的是字串的實際長度,它求得方法是從開始到遇到第一個'\0',如果你只定義沒有給它賦初值,這個結果是不定的,它會從aa首地址一直找下去,直到遇到'\0'停止。strlen返回的是有效字串長度,不包含結束符‘\0’。函數strcpy則連‘\0’一起複製。 

基本類型sizeof執行個體
#include "stdafx.h"#include <stdlib.h>#include <iostream>using namespace std;void testStrlen(){    char aa[10];    char bb[10]={'\0'};     char cc[10]="jun";     cout<<strlen(aa)<<endl; //結果是不定的    cout<<strlen(bb)<<endl; //結果為0    cout<<strlen(cc)<<endl; //結果為3    cout<<sizeof(cc)<<endl; //10 而sizeof()函數返回的是變數聲明後所佔的記憶體數,不是實際長度。 }void* Fun1(){    printf("void\n");    return NULL;}char Fun2(){    char c='c';    printf("char c='c'");    return c;}int Fun3(){    int i=2;    printf("int i=2");    return i;}struct strc0{ };struct strc00{     int getA();};struct strc000{     int* getA()    {        return NULL;    }};struct strc1{    int a;    char b;};struct strc2{    char b;    int a;};struct strc3{    char b;    int a;    double c;};struct strc4{    double c;    char b;    int a;};struct strc5{    char b;    double c;    int a;};struct strc6{    int a;    double c;    char b;};struct strc7{    int a;    double c;    char b;    char d;};class classA0{};class classA00{    int GetA();    char GetB();};class classA000{    int GetA()    {        return 1;    }    char GetB()    {        return 'c';    }};class classA1{    int a;    double b;};class classA2{    char b;    double c;    int a;};class classA3{    char b;    double c;    int a;    char d;};int _tmain(int argc, _TCHAR* argv[]){      testStrlen();    //基礎資料型別 (Elementary Data Type)    printf("%d\n",sizeof(char));// 1    printf("%d\n",sizeof(short));// 2    printf("%d\n",sizeof(int));// printf("%d\n",sizeof(2)); 4     printf("%d\n",sizeof(long));// 4    printf("%d\n",sizeof(float));// 4    printf("%d\n",sizeof(double));// printf("%d\n",sizeof(2.12)); 8     printf("%d\n",sizeof(string));// 32    //函數:看其傳回值,與內部申請的變數無關,且不調用函數    printf("%d\n",sizeof(Fun1()));// 4  //沒有調用函數    printf("%d\n",sizeof(Fun2()));// 1    printf("%d\n",sizeof(Fun3()));// 4    //指標:佔用記憶體位元組數都為4    printf("%d\n",sizeof(void*));//4    printf("%d\n",sizeof(int*));// 4    //數組:其值是(下標*資料類型),當數組為參數時,則淪為了指標    int a1[4];    char a2[]="abcd";//char a2[4]="abcd";//數組界限溢出    char a3[6]="abcd\0";//說明“\0”是一個字元(逸出字元)    char a4[20]="abc";    printf("%d\n",sizeof(a1));// 4*4=16    printf("%d\n",sizeof(a2));// 5,字元末尾還存在一個NULL的結束符    printf("%d\n",sizeof(a3));//6    printf("%d\n",sizeof(a4));//20,說明給a4分配了20個位元組的記憶體空間,不論是否填充滿    printf("%d\n",sizeof(a4[10]));//1,a4[4]是一個char類型的資料    //結構體,涉及到位元組對齊的問題,而位元組對齊的細節與編譯器實現有關。    //結構體的總大小為結構體最寬基本類型成員大小的整數倍    //結構體每個成員相對於結構體首地址的位移量(offset)都是成員大小的整數倍    //自己總結的:結構體的大小=最寬基本類型成員大小+其前後丈量的個數。其成員函數不佔用記憶體    printf("%d\n",sizeof(strc0));//1,空的結構體占記憶體為1    printf("%d\n",sizeof(strc00));//1,在結構體內什麼的函數不佔記憶體    printf("%d\n",sizeof(strc000));//1,在結構體內定義的函數不佔記憶體,不論其傳回值是什麼。    printf("%d\n",sizeof(strc1));//8,說明結構體中存在字元對齊的現象    printf("%d\n",sizeof(strc2));//8    printf("%d\n",sizeof(strc3));//不是24,而是16    printf("%d\n",sizeof(strc4));//不是24,而是16    printf("%d\n",sizeof(strc5));//不是16,而是24    printf("%d\n",sizeof(strc6));//不是16,而是24    printf("%d\n",sizeof(strc7));//24     //共同體Union    union U    {        char* a;        double b;        float c;    };    cout<<"sizeof(uniion U)="<<sizeof(union U)<<endl;//8 結構體在記憶體組織上是順序式的,共同體則是重疊式,各成員共用一段記憶體,所以整個共同體的sizeof也就是每個成員sizeof的最大值。    //類:與結構體一樣。類的大小=最寬基本類型成員大小+其前後丈量的個數。且成員函數不佔用記憶體    printf("%d\n",sizeof(classA0));//1    printf("%d\n",sizeof(classA00));//1,說明申明的函數不佔記憶體    printf("%d\n",sizeof(classA000));//1,說明定義的函數不佔記憶體    printf("%d\n",sizeof(classA1));//16,說明類中也存在字元對齊的現象    printf("%d\n",sizeof(classA2));//24    printf("%d\n",sizeof(classA3));//24    system("pause");    return 0;}

最後總結:類/結構體的大小=最寬成員類型+其前後丈量的個數。且普通成員函數(包括指標函數和靜態函數,不包括虛函數)不佔用記憶體,不論其是否有傳回值。


類(虛函數,抽象函數,靜態變數,靜態函數,虛繼承)sizeof 執行個體 

#include "stdafx.h"#include <iostream>using namespace std;  //編譯器為每個有虛函數的類都建立一個虛函數表(其大小不計算在類中),並為這個類安插一個指向虛函數表的指標,即每個有虛函數的類其大小至少為一個指標的大小4   class A{   public:   int a;   void Function();   };   class B{   public:   int a;   virtual void Function();   };   class C : public B{   public:   char b;   };   class D : public B{   public:   virtual void Function2();   };   class E{   public:   static void Function();   };   class staticE   {   static int intVar;   static void fun(){} };  void test1(){cout<<"sizeof(A)="<<sizeof(A)<<endl;//4   (內含一個int,普通函數不佔大小)   cout<<"sizeof(B)="<<sizeof(B)<<endl;//8   (一個int ,一個虛函數表指標)   cout<<"sizeof(C)="<<sizeof(C)<<endl;//12   (一個int ,一個虛函數表指標,一個char ,再加上資料對齊)  cout<<"sizeof(D)="<<sizeof(D)<<endl;//8 (一個int ,一個虛函數表指標,多個虛函數是放在一個表裡的,所以虛函數表指標只要一個就行了)   cout<<"sizeof(E)="<<sizeof(E)<<endl;//1   (static 函數不佔大小,空類大小為1)   cout<<"sizeof(staticE)="<<sizeof(staticE)<<endl;//1   待用資料成員不計入類內   }class cA   {   public:   virtual void PrintA1(void){}    virtual void PrintA2(void){}   };   class cB   {   public:   virtual void PrintB(void){}    };   class cC   {   public:   virtual void PrintC(void){}    };   class cD : public cA, public cB, public cC {   };   class cE : public cA, public cB, public cC   {   public:   virtual void PrintE(void){}    };   void test2(){cout<<"sizeof(cD)="<<sizeof(cD)<<endl;//12 如果一個類裡面什麼也不實現,只實現一個或多個虛函數的話,測它的sizeof會得到4,但如果一個類從多個類繼承,並且它的多個基類有虛函數的話,它就會有多個虛函數表了,這個在COM也有體現.cout<<"sizeof(cE)="<<sizeof(cE)<<endl;//12    }class dA {int a;virtual ~dA(){}};class dB:virtual public dA{virtual void myfunB(){}};class dC:virtual public dA{virtual void myfunC(){}};class dD:public dB,public dC{virtual void myfunD(){}};void test3(){ cout<<"sizeof(dA)="<<sizeof(dA)<<endl;//8  cout<<"sizeof(dB)="<<sizeof(dB)<<endl;//12 cout<<"sizeof(dC)="<<sizeof(dC)<<endl;//12   cout<<"sizeof(dD)="<<sizeof(dD)<<endl;//16  //解釋:A中int+虛表指標。B,C中由於是虛繼承因此大小為A+指向虛基類的指標,B,C雖然加入了自己的虛函數,但是虛表指標是和基類共用的,因此不會有自己的虛表指標。D由於B,C都是虛繼承,因此D只包含一個A的副本,於是D大小就等於A+B中的指向虛基類的指標+C中的指向虛基類的指標。//如果B,C不是虛繼承,而是普通繼承的話,那麼A,B,C的大小都是8(沒有指向虛基類的指標了),而D由於不是虛繼承,因此包含兩個A副本,大小為16. 注意此時雖然D的大小和虛繼承一樣,但是記憶體布局卻不同。}class T1   {    };   class T2 : public T1   {    };   class T3 : public T1   {    int a;};   class M1   {     virtual void GetM()=0;};   class M2 {    virtual void GetM2()=0;virtual void Get();};   class M3 : public M1, public M2 {    int a;};   void test4(){cout<<"sizeof(T2)="<<sizeof(T2)<<endl;//1   繼承一個空父類,這時sizeof(父類)=0cout<<"sizeof(T3)="<<sizeof(T3)<<endl;//4   同上cout<<"sizeof(M1)="<<sizeof(M1)<<endl;// 4cout<<"sizeof(M2)="<<sizeof(M2)<<endl;// 4cout<<"sizeof(M3)="<<sizeof(M3)<<endl;// 12  抽象函數與虛函數一樣} void main(){    test1();test2();test3();test4();} /*虛函數表(http://www.uml.org.cn/c%2B%2B/200811143.asp) C++中的虛函數的作用主要是實現了多態的機制。關於多態,簡而言之就是用父類型別的指標指向其子類的執行個體,然後通過父類的指標調用實際子類的成員函數。這種技術可以讓父類的指標有“多種形態”,這是一種泛型技術。所謂泛型技術,說白了就是試圖使用不變的代碼來實現可變的演算法。比如:模板技術,RTTI技術,虛函數技術,要麼是試圖做到在編譯時間決議,要麼試圖做到運行時決議。對C++瞭解的人都應該知道虛函數(Virtual Function)是通過一張虛函數表(Virtual Table)來實現的。簡稱為V-Table。 在這個表中,主是要一個類的虛函數的地址表,這張表解決了繼承、覆蓋的問題,保證其容真實反應實際的函數。這樣,在有虛函數的類的執行個體中這個表被分配在了 這個執行個體的記憶體中,所以,當我們用父類的指標來操作一個子類的時候,這張虛函數表就顯得由為重要了,它就像一個地圖一樣,指明了實際所應該調用的函數。這裡我們著重看一下這張虛函數表。C++的編譯器應該是保證虛函數表的指標存在於對象執行個體中最前面的位置(這是為了保證取到虛函數表的有最高的效能——如果有多層繼承或是多重繼承的情況下)。 這意味著我們通過對象執行個體的地址得到這張虛函數表,然後就可以遍曆其中函數指標,並調用相應的函數。debug時,在局部變數視窗中可以看到,虛函數表*/

備忘:struct與class類似。

嚴重我這個發現:記憶體對齊(位元組對齊,結構體對齊)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.