我們都知道指標C/C++的一大特色,但其實指標並不是C/C++獨有的,像C#和java等其實也是有指標的,只不過都被語言本身用其他的方式替代和封裝了一般程式設計師接觸不到,C/C++就不一樣,它是直接將指標暴露給開發者,因為大部分牽涉到指標的都與記憶體有關,而計算機記憶體很重要,萬一出什麼問題可能系統都會崩潰,下面我們就簡單來看一下程式在執行時指標與記憶體之間到底是個什麼樣的關係:
先看一段程式碼:
#include <stdio.h>
#include <string>
#include <iostream>
#include <time.h>
using namespace std;
class people
{
public:
people();
~people();
string Name ;
int age ;
bool sex ;
char info[1024] ;
void run(){}
void eat(){}
private:
};
people::people()
}
people::~people()
int main()
people* p1 = new people();
cout<<p1<<endl;
cout<<&p1<<endl;
cout<<sizeof(p1)<<endl;
cout<<sizeof(*p1)<<endl;
system("pause");
return 0 ;
執行看結果:
接下來來一一進行分析:
首先people* p1 = new people();這一句是類的一個例項化,系統會給people例項化一個物件*p並且給它在堆上開闢空間,注意是在堆上,開闢的空間用來儲存物件的資料。資料包括哪些?就是物件的屬性和虛擬函式指標,但是函式並不儲存在各物件中。因此run()和eat()方法是不存在物件*p指向的記憶體處的。
cout<<p1<<endl;輸出的是00279360,這是一個地址,是系統給new people()物件分配的地址。
cout<<&p1<<endl;輸出的是0012FD90,這也是地址,但這是指標變數p本身的地址。
透過這兩個我們就更清晰的認識到了,p1本身只佔用4個位元組的空間,而他所指向的物件的地址所佔的空間就很大,等於類中所有資料型別所佔空間之和。
接下來我們在main函數里寫一點邏輯:
我們來看一下程式執行時間,指標和記憶體是怎麼工作的。我畫一個圖給大家:
程式在執行時,資料主要是儲存在棧、堆、程式碼區、全域性區。程式碼區主要就是存程式碼中出現的一些字元常量、方法等,比如這裡程式碼中給物件的Name屬性賦的值“xiaoli”之類的都是存在此處,然後我們透過new出來的物件,都是由堆透過計算好類中各屬性所需空間然後開闢出來的。這裡p3不是透過new開闢出來的,所以他是存在棧上的並且地址是固定的,是不能更改的,而p1和p2是能更改的。
改變地址
如此,我們三個物件互相賦值後會發生什麼呢?
對比程式碼和輸出結果我們發現了什麼?賦值後p1和p2本身的地址並無改變,但是他所指向的記憶體都程式設計p3所在的記憶體了。下面用圖解給大家看一下:
改變地址的值
如果我將程式碼中的 p2 = &p3;換成*p2=p3呢?我們看下輸出結果:
造成這種情況的原因,其實這就牽涉到指標的兩種賦值問題:一種是改變指向的地址,一種是改變本身指向地址的值p2 = &p3是改變指向地址,*p2=p3是改變指向地址的值。
我們都知道指標C/C++的一大特色,但其實指標並不是C/C++獨有的,像C#和java等其實也是有指標的,只不過都被語言本身用其他的方式替代和封裝了一般程式設計師接觸不到,C/C++就不一樣,它是直接將指標暴露給開發者,因為大部分牽涉到指標的都與記憶體有關,而計算機記憶體很重要,萬一出什麼問題可能系統都會崩潰,下面我們就簡單來看一下程式在執行時指標與記憶體之間到底是個什麼樣的關係:
先看一段程式碼:
#include <stdio.h>
#include <string>
#include <iostream>
#include <time.h>
using namespace std;
class people
{
public:
people();
~people();
string Name ;
int age ;
bool sex ;
char info[1024] ;
void run(){}
void eat(){}
private:
};
people::people()
{
}
people::~people()
{
}
int main()
{
people* p1 = new people();
cout<<p1<<endl;
cout<<&p1<<endl;
cout<<sizeof(p1)<<endl;
cout<<sizeof(*p1)<<endl;
system("pause");
return 0 ;
}
執行看結果:
分析接下來來一一進行分析:
首先people* p1 = new people();這一句是類的一個例項化,系統會給people例項化一個物件*p並且給它在堆上開闢空間,注意是在堆上,開闢的空間用來儲存物件的資料。資料包括哪些?就是物件的屬性和虛擬函式指標,但是函式並不儲存在各物件中。因此run()和eat()方法是不存在物件*p指向的記憶體處的。
cout<<p1<<endl;輸出的是00279360,這是一個地址,是系統給new people()物件分配的地址。
cout<<&p1<<endl;輸出的是0012FD90,這也是地址,但這是指標變數p本身的地址。
cout<<sizeof(p1)<<endl;
cout<<sizeof(*p1)<<endl;
透過這兩個我們就更清晰的認識到了,p1本身只佔用4個位元組的空間,而他所指向的物件的地址所佔的空間就很大,等於類中所有資料型別所佔空間之和。
接下來我們在main函數里寫一點邏輯:
圖解我們來看一下程式執行時間,指標和記憶體是怎麼工作的。我畫一個圖給大家:
程式在執行時,資料主要是儲存在棧、堆、程式碼區、全域性區。程式碼區主要就是存程式碼中出現的一些字元常量、方法等,比如這裡程式碼中給物件的Name屬性賦的值“xiaoli”之類的都是存在此處,然後我們透過new出來的物件,都是由堆透過計算好類中各屬性所需空間然後開闢出來的。這裡p3不是透過new開闢出來的,所以他是存在棧上的並且地址是固定的,是不能更改的,而p1和p2是能更改的。
改變地址
如此,我們三個物件互相賦值後會發生什麼呢?
對比程式碼和輸出結果我們發現了什麼?賦值後p1和p2本身的地址並無改變,但是他所指向的記憶體都程式設計p3所在的記憶體了。下面用圖解給大家看一下:
改變地址的值
如果我將程式碼中的 p2 = &p3;換成*p2=p3呢?我們看下輸出結果:
造成這種情況的原因,其實這就牽涉到指標的兩種賦值問題:一種是改變指向的地址,一種是改變本身指向地址的值p2 = &p3是改變指向地址,*p2=p3是改變指向地址的值。