C指針3:指針變量的運算

由上節介紹我們知道,通過指針可以修改內存上的數據,並進一步可以交換數據。這種操作實際上也是在對地址進行操作運算。具體怎麼實現指針變量的元素呢?爲什麼能實現指針變量的運算呢?

因爲指針變量保存的是地址,而地址本質上是一個整數,所以指針變量可以進行部分運算,例如加法、減法、比較等。

#include <stdio.h>
#include <iostream>
using namespace std;


int main() {
	int    a = 8, *pa = &a, *paa = &a;
	double b = 70.3, *pb = &b;
	char   c = '#', *pc = &c;
	//最初的值----打印地址
	cout << "---打印最初的7個地址---" << endl;
	printf("&a=%#X, &b=%#X, &c=%#X\n", &a, &b, &c);
	printf("pa=%#X, paa=%#X,pb=%#X, pc=%#X\n", pa, paa, pb, pc);//pa和paa地址一樣,因爲都是指向a。
	//------------打印數據
	cout << "---打印最初的7個數據---" << endl;
	cout << a <<" , "<< b << " , " << c << endl;
	cout << *pa << " , " << *paa << " , " << *pb << " , " << *pc << endl;//*pa和*paa數據一樣,因爲都是指向a。
	//加法運算----打印地址
	pa++; pb++; pc++;
	cout << "---打印加法後的7個地址---" << endl;
	printf("&a=%#X, &b=%#X, &c=%#X\n", &a, &b, &c);
	printf("pa=%#X, paa=%#X,pb=%#X, pc=%#X\n", pa, paa, pb, pc);
	//------------打印數據
	cout << "---打印加法後的7個數據---" << endl;
	cout << a << " , " << b << " , " << c << endl;
	cout << *pa << " , " << *paa << " , " << *pb << " , " << *pc << endl;
	//減法運算---打印地址
	pa -= 2; pb -= 2; pc -= 2;
	cout << "---打印減法後的7個地址---" << endl;
	printf("&a=%#X, &b=%#X, &c=%#X\n", &a, &b, &c);
	printf("pa=%#X, paa=%#X,pb=%#X, pc=%#X\n", pa, paa, pb, pc);
	//------------打印數據
	cout << "---打印減法後的7個數據---" << endl;
	cout << a << " , " << b << " , " << c << " , " << endl;
	cout << *pa << " , " << *paa << " , " << *pb << " , " << *pc << endl;
	//比較運算-----打印數據
	if (pa == paa)
	{
		printf("%d\n", *paa);
		cout << *paa << endl;
	}
	else
	{
		printf("%d\n", *pa);
		cout <<"不相等"<< *pa << endl;
	}
	return 0;
}

結果展示:

pa執行++之後,因爲pa指向的是int型所以地址加4,pa此時指向了新的地址,至於新地址裏邊是什麼數據我們沒有對他進行賦值,所以不能操作極其危險,此時系統裏邊存的是1,所以就給我們1,至於爲什麼是1,我們不知道。

有上述代碼可以看出:指針變量除了可以參與加減運算,還可以參與比較運算。當對指針變量進行比較運算時,比較的是指針變量本身的值,也就是數據的地址。如果地址相等,那麼兩個指針就指向同一份數據,否則就指向不同的數據。

從運算結果可以看出:pa、pb、pc 每次加 1,它們的地址分別增加 4、8、1,正好是 int、double、char 類型的長度;減 2 時,地址分別減少 8、16、2,正好是 int、double、char 類型長度的 2 倍。
這很奇怪,指針變量加減運算的結果跟數據類型的長度有關,而不是簡單地加 1 或減 1,這是爲什麼呢?

以 a 和 pa 爲例,a 的類型爲 int,佔用 4 個字節,pa 是指向 a 的指針,如下圖所示:

剛開始的時候,pa 指向 a 的開頭,通過 *pa 讀取數據時,從 pa 指向的位置向後移動 4 個字節,把這 4 個字節的內容作爲要獲取的數據,這 4 個字節也正好是變量 a 佔用的內存。

如果pa++;使得地址加 1 的話,就會變成如下圖所示的指向關係:

這個時候 pa 指向整數 a 的中間,*pa 使用的是紅色虛線畫出的 4 個字節,其中前 3 個是變量 a 的,後面 1 個是其它數據的,把它們“攪和”在一起顯然沒有實際的意義,取得的數據也會非常怪異。

如果pa++;使得地址加 4 的話,正好能夠完全跳過整數 a,指向它後面的內存,如下圖所示:

我們知道,數組中的所有元素在內存中是連續排列的,如果一個指針指向了數組中的某個元素,那麼加 1 就表示指向下一個元素,減 1 就表示指向上一個元素,這樣指針的加減運算就具有了現實的意義。

不過C語言並沒有規定變量的存儲方式,如果連續定義多個變量,它們有可能是挨着的,也有可能是分散的,這取決於變量的類型、編譯器的實現以及具體的編譯模式,所以對於指向普通變量的指針,我們往往不進行加減運算,雖然編譯器並不會報錯,但這樣做沒有意義,因爲不知道它後面指向的是什麼數據。PS:警告讀者不要嘗試通過指針獲取下一個變量的地址(因爲你定義的幾個變量他們可能並不挨着,它們中間還參雜了別的輔助數據)。

如上面的例子,在比較 pa 和 paa 的值時,pa 已經指向了 a 的上一份數據,所以它們不相等。而 a 的上一份數據又不知道是什麼,所以會導致 printf() 輸出一個沒有意義的數,這正好印證了上面的觀點,不要對指向普通變量的指針進行加減運算。

參考:C語言中文網

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章