前面已經介紹過數據在內存中的地址稱爲指針。
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;
。