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//此處的*號為指針運算符,用來取得某個地址上得數據。
下面舉一個例子看一下輸出結果就知道了:(對于指針變量p,它的類型是int *)
#include <stdio.h>
#include <iostream>
using namespace std;
int main() {int a = 15;int *p = &a;//p指向a后,p本身的值就會變成a的地址。對于指針變量 p,它的類型是int *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;//臨時變量tempint *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;。
總結
- 上一篇: C指针1:基础
- 下一篇: C指针3:指针变量的运算