-
1 # IT劉小虎
-
2 # 浮生若夢2020
假設你住在酒店裡。你就是一個具體的數值。房間號是你的地址。找你可以透過房間號,也可以呼喊你的名字。
我們定義一個變數就是開了房,給變數賦值就是住進去了旅客。直接呼叫變數就是間接喊你,透過服務員喊你,服務員還是會到你房號敲門。
指標就是指向房號的變數。就是我們安排的某一個旅客他可以找到任何旅客的房號,而不知道姓名。我們讓他到某某號(增或減或隨機)去敲門。
也可形象理解指標是你手指頭,指在旅客登記簿上,需要誰指向誰,然後撥通電話喊他。
-
3 # 程式設計老大叔
理解指標
首先,你需要掌握兩個運算子“*”和“&”;
“&”運算子:取物件在記憶體中的地址
“*”運算子:取記憶體中地址上的物件(值);
大家一定要深刻的理解上面兩個運算子,然後才能去進一步理解指標;
int a = 100 ;這一行程式碼我想大家都沒問題。那麼“&a”返回的就是物件(變數)a在記憶體中的地址,它是一個16進位制數。
然後用“*”號去a的地址去取物件:“*(&a)”,,就能取到物件a,也就就是100 ;
接下來進入重點了,指標,本身也是一個變數(物件),它本身佔用記憶體,但是它只存地址(別人的地址),它存的誰的地址我們就稱它為指向誰的指標;
int* p = &a ;int* p_2 = new int(200) ;先不管他的型別申明,只看變數本身p和p_2。前面講到指標存放的是物件的地址,那麼可以理解為指標是一個地址變數,那麼賦值的話就需要也賦一個地址給它一個地址。int* 和char*都可以表示地址型別,它們的區別就是地址所存的值得型別不同,一個是存整型,一個是存字元型;
對指標取值的話,就是用“*”號,後面接物件地址,也就是指標變數,所以*p和*p_2就分別是a和200;
指標的運用
指標並不是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呢?我們看下輸出結果:
-
4 # 小熊可可茶a
如果你光看,那肯定很難。一定要上機敲程式碼,把書上的那些例題,習題挨著敲一遍。
int a;a的資料型別是int型
int * p;p是指標,它的資料型別是int *型
*p指的是p所指向的內容
指標就是地址
int a=5,*p=&a;//說明p指向了a所在的地址
*p是p所指向的內容,就是5此時你改變*p的值,a的值也就隨之改變。
回覆列表
“指標是C語言的靈魂,指標可以直接操作記憶體,指標使C語言程式更加高效”,等等等等。相信C語言初學者學到指標時,會看到很多這樣描述指標的話,但是卻往往一頭霧水。
其實C語言的指標並沒有什麼難的,將其看做是一種類似於 char、int 的基本資料型別就簡單了。
我在上個問答中提到C語言中的不同的基礎資料型別主要區別之一就是佔用的儲存空間不同,程式是執行在計算機的記憶體中的,因此C語言程式的變數也是存在於記憶體中的。
C語言標準規定 char 型別佔用一個位元組的儲存空間,對其他整型卻沒有做規定,現在為了解釋的方便,我們假設 int 型別的資料佔用記憶體 4 個位元組。
假設我們如下定義了兩個變數:
那麼,i 佔用了 1 位元組的記憶體空間,j 佔用了 4 位元組的記憶體空間,請看下圖。
方框表示記憶體空間,內部表示儲存的值。我們把記憶體逐位元組編號,方框外部的數字表示方框的編號(這樣的記憶體“編號”即所謂的“記憶體地址”)。
修改變數 i 的值,實際上就是修改地址為 4000 的記憶體空間裡的值。那反過來呢?如果我修改了地址為 4000 的記憶體空間裡的值,i 的值會相應改變嗎?答案是肯定的,請繼續往下看。
上圖中的記憶體地址“4000”是我為了解釋方便隨意取的。那麼,在實際應用中,變數 i 的地址如何獲取呢?C語言提供了“&”運算子,就是獲取變數地址的。請看下面的例子:
我們取出了 i 的地址,把它強制轉換為 long 型,傳遞給 p1 了。編譯並執行這段C語言程式碼,得到如下輸出:
發現變數 i 的地址被打印出來了,這說明,C語言程式變數的地址也是一個整數。
按照上面的說法,修改 i 的值除了直接對 i 賦值以外,還可以透過修改 p1 地址處的記憶體空間裡的數值。那,怎樣才能“透過修改 p1 地址處的記憶體空間裡的數值”修改 i 的值呢?
上面的程式碼例項中使用了 long 型變數 p1 儲存了 i 的地址。事實上,C語言有專門的資料型別儲存地址(即所謂的指標),定義方式也很簡單,就是:“型別描述符 * ”,例如,可以定義以下變數儲存地址:
p1 和 p2 就是C語言中所謂的指標型別,因為 i 是 signed char 型別的,所以定義了 signed char * 型別的指標儲存 i 的地址。j 是 int 型別的,所以定義了 int * 型別的指標儲存 j 的地址。
另外,C 語言提供了“&”運算子取變數地址,與之對應的,還提供了“ * ”運算子從相應地址記憶體裡取出數值。
瞭解了C語言的指標型別和“ * ”運算子,現在來看看如何“透過修改 p1 地址處的記憶體空間裡的數值”修改 i 的值。請看如下C語言程式碼:
編譯並執行,得到如下輸出:
編譯執行,發現程式輸出“i=5”,這一值實際上就是透過指標修改的。可以看出,C語言中的指標並沒有什麼難的。
在定義變數時,” * “放在變數符號前,可以定義指標變數。在定義完指標變數後,“ * ”放在變數前,就表示從地址取值的運算子了。另外,“ * ”還可以表示乘法運算子,讀者自己思考什麼情況下,“ * ”表示乘法運算子。