C指針2:指針變量

前面已經介紹過數據在內存中的地址稱爲指針。

C語言中允許用一個變量來存放指針,如果一個變量存儲的是一份數據的指針,那麼這個變量稱爲指針變量。即指針變量的值是有一份數據的地址,這樣的一份數據可以是數組、字符串、函數,也可以是另外的一個普通變量或指針變量。

舉個例子:

有一個指針變量P,它的值是地址爲0X01A。我們還有一個char類型的變量c,他存儲的是“k”。即char c ="k";但是我們輸出char類型的c所佔用的地址爲0X01A。

此時可以說P指向c。

定義指針變量:

(1)知道了普通變量的定義規則,那麼指針變量的定義就是在變量名前加*號即可,格式爲:

datatype *name;//*表示這是一個指針變量,datatype表示該指針變量所指向的數據的類型。
//例如:
int *p1;//此時的p1是一個指向int類型數據的指針變量,至於p1究竟指向哪一份數據,應該由賦予它的值決定。
//形式如下
datatype *name=value;
//例如:
int a=10;
int *p_a=&a;//在定義指針變量p_a的同時對它進行初始化,並將變量a的地址賦予它,此時p_a就指向了a;此處p_a需要的是一個地址(注意是p_a需要的是一個地址,而不是*p_a),所以a前邊必須要加取地址符,否則是不對的。

(2)同普通變量一樣,指針變量也可以被多次寫入,只要你想修改指針變量的值,隨時都能夠改變指針變量的值。舉例如下:

//定義普通變量
float a=65.9,b=5.3;
char c='a',d='2';
//定義指針變量
float *p1=&a;//p1的類型是float*不是float//p1需要的是地址;//此處看見*號這個特殊的符號,表明定義的這個變量是指針變量,定義指針變量p1時必須帶*號。下邊對p1進行賦值時,見下。
char *p2=&c;//p2的類型是char*//p2需要的是地址;
//修改指針變量的值
p1=&b;//對p1進行賦值時,因爲已經知道了p1是一個指針變量,所以就沒必要再多此一舉的帶上*號,後邊可以像使用普通變量一樣來使用指針變量。
p2=&d;//即定義指針變量時必須帶*號,給指針變量賦值時不能帶*號。

p1,p2指向關係如下圖:假設變量a,b,c,d的地址分別爲0X1000、0X1004、0X2000、0X2004

(3)通過指針變量取得數據,(PS:看清楚獲得的是數據數據數據)格式如下:

//指針變量存儲了數據的地址,通過指針變量能夠獲取地址上的數據,格式如下:
*pointer//此處的*號爲指針運算符,用來取得某個地址上得數據。

下面舉一個例子看一下輸出結果就知道了:

#include <stdio.h>
#include <iostream>
using namespace std;
int main() {
	int a = 15;
	int *p = &a;//p指向a後,p本身的值就會變成a的地址。
	cout << a <<","<<p <<","<<*p << endl;//p是地址,*p是15,在指針變量前邊加*表示獲取指針指向的數據,或者說表示的是指針指向的數據本身。(此處就是說明了使用指針變量時的*與定義指針變量時的*號意義完全不同)
	printf("%d, %d,%#X\n", a, *p, p);  //兩種方式都可以輸出a的值,*p與a等價。
	return 0;
}

由前一節的介紹我們知道,CPU 讀寫數據必須要知道數據在內存中的地址,普通變量和指針變量都是地址的助記符,由上邊我們可以看出*p和a輸出的結果是一樣的,但是他們的運行過程不一樣,a只需要一次運算就能夠取得數據,而 *p 要經過兩次運算,多了一層“間接”。

假設變量 a、p 的地址分別爲 0X1000、0XF0A0,它們的指向關係如下圖所示:

程序被編譯和鏈接後,a、p 被替換成相應的地址。使用 *p 的話,要先通過地址 0XF0A0 取得變量 p 本身的值,這個值是變量 a 的地址,然後再通過這個值取得變量 a 的數據,前後共有兩次運算;而使用 a 的話,可以通過地址 0X1000 直接取得它的數據,只需要一步運算。

也就是說,使用指針是間接獲取數據,使用變量名是直接獲取數據,前者比後者的代價要高。

(4)通過指針修改內存上的數據

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

int main() {
	int a = 1, b = 17, c = 2;
	int *p = &a;  //定義指針變量,(1)此時*p代表的是a中的數據,即*p=a;
	*p = b;  //通過指針變量修改內存上的數據//(2)將另一份數據賦值給他
	c = *p;  //通過指針變量獲取內存上的數據//(3)再將它賦值給另外一個變量
	cout << a <<" , "<< b <<" , "<< c <<" , " <<*p << endl;
	printf("%d, %d, %d, %d\n", a, b, c, *p);
	return 0;
}

結果如下:

使用指針交換值的例子:

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

int main() {
	int a = 10, b = 99, temp;//臨時變量temp
	int *pa = &a, *pb = &b;
	cout << a << " , " << b << endl;
	printf("a=%d, b=%d\n", a, b);
	/*****開始交換*****/
	temp = *pa; //*pa=a=10 //將a的值先保存起來//因爲下一個語句中a的值會被b的值覆蓋
	cout << a << " , " << b << ","<<temp<<endl;
	*pa = *pb;  //將b的值交給a//a的值會被b的值覆蓋
	*pb = temp;  //再將保存起來的a的值交給b
				 /*****結束交換*****/
	printf("a=%d, b=%d\n", a, b);
	return 0;
}

結果如下:

總結:

假設有一個 int 類型的變量 a,pa 是指向它的指針,那麼*&a&*pa分別是什麼意思呢?

*&a可以理解爲*(&a)&a表示取變量 a 的地址(等價於 pa),*(&a)表示取這個地址上的數據(等價於 *pa),繞來繞去,又回到了原點,*&a仍然等價於 a(是一個int型的數據)。

&*pa可以理解爲&(*pa)*pa表示取得 pa 指向的數據(等價於 a),&(*pa)表示數據的地址(等價於 &a),所以&*pa等價於 pa(是一個地址)。

ps:星號*主要有三種用途:

  • 表示乘法,例如int a = 1, b = 2, c;  c = a * b;,這是最容易理解的。
  • 表示定義一個指針變量,以和普通變量區分開,例如int a = 10;  int *p = &a;
  • 表示獲取指針指向的數據,是一種間接操作,例如int a1, b1, *p = &a1;  *p = 100;  b1 = *p;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章