孫東風(fēng):聯(lián)網(wǎng)游戲、應(yīng)用開發(fā)方面有獨特的優(yōu)勢!
并不完全算是我的原創(chuàng),只是在原來文章基礎(chǔ)上加上了一點自己的理解.
1.結(jié)構(gòu)大小
int *pi = new int[12];
中的pi純粹是個指針變量,它就是一個指針,在32位環(huán)境下占4個字節(jié)。
pi申請完內(nèi)存后,是整個內(nèi)存塊的首地址,*pi代表的就是第一個元素,每個元素為int類型的,當(dāng)然為4了,如果為char *pi = new char[12];
cout<<"*pi:"<
int ia[]={0, 1, 2};
中的ia是個數(shù)組,它代表了整個這一個數(shù)組,數(shù)組中有三個元素,每個int類型的元素占4 個字節(jié),共是12個字節(jié)。但是ia是個變量,變量總要有一定的值,C++就把數(shù)組第一個元素的地址賦給它了。
#include
//using namespace std;
int main(int argc, _TCHAR* argv[])
{
int *pi = new int[12];
int ai[] = {0,1,2};
std::cout<<"*pi :"<
std::cout<<"ai :"<
return 0;
}
2.指針與引用
引用是一種沒有指針語法的指針.與指針一樣,引用提供對對象的間接訪問.
傳指針時,我們可以通過指針來修改它在外部所指向的內(nèi)容。但如果要修改外部指針讓它指向別的對象是不可能的。
例如傳遞外部指針到函數(shù)內(nèi)來分配空間,必須傳遞指針的指針或指針的引用。
3. 引用與指針的比較:
①引用在創(chuàng)建的同時必須初始化,即引用到一個有效的對象(因為引用原本就是對象的一個別名);
而指針在定義的時候不必初始化,可以在定義后面的任何地方重新賦值.
②不存在NULL引用,引用必須與合法的存儲單元關(guān)聯(lián);
而指針則可以是NULL.
③引用一旦被初始化為指向一個對象,它就不能被改變?yōu)榱硪粋€對象的引用;
而指針在任何時候都可以改變?yōu)橹赶蛄硪粋€對象.
給引用賦值并不是改變它和原始對象的綁定關(guān)系.
④引用的創(chuàng)建和銷毀并不會調(diào)用類的拷貝構(gòu)造函數(shù);
⑤在語言層面,引用的用法和對象一樣;
在二進(jìn)制層面,引用一般都是通過指針來實現(xiàn)的,只不過編譯器幫我們完成了轉(zhuǎn)換.
總的來說:引用既具有指針的效率,又具有變量使用的方便性和直觀性.
1:值傳遞
void Func(int x)
{
x=x+10;//修改的是n在堆棧中的拷貝x
}
int n=0;
Func(n);
cout<<"n="<
2:指針傳遞
void Func2(int *x)
{
(*x)=(*x)+10;//修改指針x指向的內(nèi)存單元的值
}
int n=0;
Func(&n);
cout<<"n="<
3:引用傳遞
void Func3(int &x)
{
x=x+10;//修改的是x引用到的對象n
}
int n=0;
Func3(n);
cout<<"n="<
4. 函數(shù)指針
在注冊一個回調(diào)函數(shù)時候,我們常常使用函數(shù)指針.
c/c++的連接器在連接程序的時候必須把函數(shù)的調(diào)用語句加上,因此函數(shù)地址必須在編譯時就確定下來.也就是編譯器為函數(shù)生成代碼的時候.
typedef int(* FuncPtr) (const char*)//定義一個函數(shù)指針的類型
類的成員函數(shù)有4種類型:inline,virtual,static,normal;
inline函數(shù)在運行時會展開,雖然語言允許取其地址,但是沒有太大的意義.
virtual成員函數(shù)的地址指的是其在vtable中的位置.
static成員函數(shù)的地址和普通全局函數(shù)的地址沒有任何區(qū)別.
普通成員函數(shù)的地址和一般函數(shù)的地址也沒有區(qū)別,就是函數(shù)代碼在內(nèi)存中的真實地址,但是由于它的調(diào)用要綁定到一個實實在在的對象身上,因此無論是其函數(shù)指針的聲明方式還是其地址的獲取方式都比較特別.
#i nclude
class CTest
{
public:
void f(void) //普通成員函數(shù)
{
cout<<"CTest::f()"<
}
static void g(void) //靜態(tài)成員函數(shù)
{
cout<<"CTest::g()"<
}
virtual void h(void) //虛擬的成員函數(shù)
{
cout<<"CTest::h()"<
}
private:
};
void main()
{
typedef void (*GFPtr) (void); //定義一個全局函數(shù)指針類型
GFPtr fp=CTest::g; //取靜態(tài)成員函數(shù)地址的方法和取一個全局函數(shù)的地址相似
fp(); //通過函數(shù)指針調(diào)用類靜態(tài)成員函數(shù)
typedef void (CTest::*MemFuncPtr)(void); //聲明類成員函數(shù)指針類型
MemFuncPtr mfp_1=&CTest::f; //聲明成員函數(shù)指針變量并初始化
MemFuncPtr mfp_2=&CTest::h; //注意獲得成員函數(shù)地址的方法
CTest theObj;
(theObj.*mfp_1)(); //使用對象和成員函數(shù)指針調(diào)用成員函數(shù)
(theObj.*mfp_2)();
CTest *pTest=&theObj; //使用對象指針和成員函數(shù)指針調(diào)用成員函數(shù)
(pTest->*mfp_1)();
(pTest->*mfp_2)();
}
實際上,任何成員函數(shù)的代碼體都是獨立于類的對象而存在的,只是非靜態(tài)成員函數(shù)在調(diào)用的時候需要與具體的對象建立綁定關(guān)系而已(即this指針),c/c++編譯器最終把所有的成員函數(shù)經(jīng)過Name-Mangling的處理后轉(zhuǎn)換全局函數(shù),并且增加一個入?yún)his作為第一個參數(shù),供所屬類的所有對象共享.因此成員函數(shù)的地址實際上就是這些全局函數(shù)的地址.
5. 內(nèi)存管理
內(nèi)存分配的方式:
(1)從靜態(tài)存儲區(qū)域分配.內(nèi)存在程序的時候就已經(jīng)分配好了(即已經(jīng)編址),這些內(nèi)存在程序的整個運行期間都存在.例如全局變量,static變量度等.
(2)在堆棧上創(chuàng)建.在函數(shù)執(zhí)行期間,函數(shù)內(nèi)局部變量(包括形參)的存儲單元都創(chuàng)建在堆棧上,函數(shù)結(jié)束時這些存儲單元自動釋放(堆棧清棧).堆棧內(nèi)存分配運算內(nèi)置于處理器的指令集中,效率很高,并且不存在失敗的危險,但是分配的內(nèi)存容量有限.
(3)從堆上分配,亦稱動態(tài)內(nèi)存分配.程序在運行期間用malloc 或new 申請任意數(shù)量的內(nèi)存,程序員自己掌握釋放內(nèi)存的恰當(dāng)時機(使用free或delete).動態(tài)內(nèi)存的生存期由程序員決定,使用非常靈活,但也最容易產(chǎn)生問題.
有了malloc/free為什么還要new/delete?
malloc與free是c/c++ 語言的標(biāo)準(zhǔn)庫函數(shù),new/delete是c++的運算符,它們都是用于申請和釋放動態(tài)內(nèi)存.
對于非內(nèi)部的數(shù)據(jù)類型(如ADT/UDT)的對象而言,光用malloc/free無法滿足動態(tài)對象的要求:對象在創(chuàng)建的同時要自動調(diào)用構(gòu)造函數(shù),對象在銷毀的時候要自動調(diào)用析構(gòu)函數(shù).由于malloc/free是庫函數(shù),不在編譯器控制范圍內(nèi).
malloc/free的使用要點:
函數(shù)malloc的原型如下
void *malloc(size_t size);
用malloc申請一塊長度為length的整型數(shù)組的內(nèi)存,程序如下
int *p=(int*)malloc(length);
函數(shù)free的原型如下一步
void free(void* memblock);
如果p==NULL,free對p的操作無論多次都不會出現(xiàn)問題.
new/delete的使用要點:
int *p1=(int*)malloc(sizeof(int)*length);
int* p2=new int[length];
note:如果用new 創(chuàng)建對象數(shù)組,那么只能使用對象的默認(rèn)構(gòu)造函數(shù),不能使用帶參數(shù)的構(gòu)造函數(shù).
在使用delete釋放對象數(shù)組時,留意不要丟了符號"[]"
對于內(nèi)部數(shù)據(jù)類型(int,float,double)的動態(tài)數(shù)組p而言,delete p與delete[]p是等價的.
全寫法Cache(Write through)
每次寫入Cache時同時寫入內(nèi)存,使內(nèi)存和Cache始終保持一致.
寫回法Cache(Write back)
當(dāng)每一次寫入時,只對Cache寫入,如果已經(jīng)寫入過的Cache需要再寫入時,就要把它的內(nèi)容寫入內(nèi)存中