C-學習筆記6-指標基礎
1.變數的地址
在計算機中,記憶體是連續的儲存空間。為了便於對其中某個指定部分進行操作,要對記憶體進行編址,記憶體編址的基本單位為位元組。對於程式中定義的變數,編譯時根據它的型別給它分配一定程度的記憶體單元。分配給每個變數的記憶體單元的起始地址。編譯後每個變數都對應一個變數地址。當引用一個變數時就是從該變數名對應的地址開始的若干單元取出資料;當給一個變數賦初值時,則是將資料按該變數定義的型別存入對應的記憶體單元,於是該變數的地址存入的內容即該變數的值。short int型資料佔用2個位元組,int型和float型資料各佔用4個位元組,double佔用8個位元組,char型佔用1個位元組。
例如: short int a = 10;
float t = 0.618;
x t
1500 1501 1502 1503 1504 1505
10 0.618
2.指標的概念
用變數名直接從它對應的地址存取變數的值,稱為“直接訪問”。若將變數x的地址存放在另一個變數P中,訪問時先從P中取出變數x的地址,再按x的地址訪問變數x的值,這種訪問稱為“間接訪問”。C語言規定用一種特殊型別的變數來存放地址,這種型別就是指標型別。通過指標型別的變數可以實現間接訪問,C語言將它們稱為變數的指標。變數的指標就是變數的地址,即指標P存放變數x的地址。
因此對於一個記憶體單元而言,記憶體單元的地址即為指標,記憶體單元中存放的資料才是該單元的內容。訪問記憶體地址其實是為了更方便的操作記憶體中的資料,以上面的資料為例,在1500地址中存放的是一個整型的變數x,其值為10。如果定義一個指標變數p,p的值定義為1500,那麼我們就稱p是指向變數x的指標。
指標其實就是一個地址,是一個地址常量。但是指標變數卻可以被賦予不同的指標值,即不同的地址值,可以指向不同的地址單元,是個變數。即指標變數專門用於儲存其他變數地址的變數,定義指標的目的是為了通過指標去訪問記憶體單元,對記憶體單元中的資料進行操作。
指標變數的值是一個地址,這個地址不僅可以使變數的地址,也可以是其他資料結構的首地址。用指標指向某種資料結構,其實就是將該資料結構的首地址賦予指標,因為許多資料結構都是連續存放的。所以通過訪問指標變數取得了該資料結構的首地址,就可以訪問到該資料結構的所有成員。這樣就可以用一個指標變數來表示資料結構,只要該指標變數中賦予資料結構的首地址即可。
二. 指標變數的定義和初始化
1.指標變數的定義
指標變數定義的一般格式:
資料型別名 *指標變數名1,*指標變數名2,...;
指標變數定義時在變數名前加"*"表示
例如:
int * p;
定義了一個指向整型變數的指標p(注意:不是*p),它是一個指標變數,它所代表的是它所指向的整形變數的地址,具體它指向是哪個整形變數的地址,這是由該指標變數的初始化工作來決定的。又如:
int *p1; float *p2; char *p3;
指標指向的資料型別一旦定義後不能改變,且定義多個指標時可以寫作 int *p1,*p2;(不是int *p1,p2;)
2.指標變數的初始化
當定義指標變數時,指標變數的值是隨機的,不能確定它具體的指向,必須為其賦值才有意義。若使用未經賦值的指標變數將造成系統混亂,甚至出現宕機。指標變數的賦值只能賦予地址,絕不能賦予任何其他資料,否則將引起錯誤。在C語言中,變數的地址是有編譯系統分配的,對使用者完全透明,使用者不知道變數的具體地址。C語言中提供了地址運算子"&"來表示變數的地址。
指標初始化的一般格式:
資料型別名 *指標變數值 = 初始的地址值;
例如:
int a;
int *p1;
*p1 = &a;
或者:
float b;
float *p2 = &b;
然而 float *p = &c; 或者 int a; float *p = &a; 是錯誤的
可以將一個地址的值付給另一個地址: int *p2 = p1;
p1 = &a;是將a的地址賦給p1,*p1 = 3;是給p1所指向的變數賦值為3兩者的意義完全不同。
int *p = 0; 在初始化中可以將一個指標初始化為一個空指標。
3.指標變數的引用和運算
&和*互為逆運算。
#include<stdio.h>
int main()
{
int *p1,*p2,*p,a,b;
scanf(,&a,&b);
p1 = &a, p2 = &b;
if(a<b){
p = p1;
p1 = p2;
p2 = p;
}
printf("\na=%d,b = %d\n",a,b);
printf("max = %d, min = %d\n",*p1,*p2);
return 0;
}
4.指標的運算
(1)指標變數賦值
將一個變數的地址付給一個指標變數。
int *p;
p = &a; //將變數a的地址賦給p
p = array; //將陣列array的首地址賦給p
p = &array[i]; //將陣列array第i個元素的地址賦給p
p1 = p2; //p1和p2都是指標變數,將p2的值賦給p1
#include<stdio.h>
int main()
{
int a,*pa;
pa = &a;
printf("\na的地址為:%p",&a);
printf("\npa = %p",pa);
printf("\npa的地址:%p",&pa);
return 0;
}
程式結果為:
a的地址為:0012FF7C
pa = 0012FF7C
pa的地址:0012FF78
(2)指標的取值
可以通過"*"運算子來去除相應地址中的變數值
(3)指標變數加(減)一個數
指標加減法與一般加減法規則不同,它是將整數和指標所指型別的位元組數相乘,再加到指標所指向記憶體單元的地址上。這種運算適合與陣列的運算,因為陣列的記憶體空間的申請是連續的。所以一個指標變數加(減)一個整數並不是簡單地將原址簡單的加減一個整數。
(4)指標的自增自減
指標變數也可以進行增加和減小的運算,即通過++和--運算子來運算。運算規則為:指標所指向記憶體單元的地址上加上或者減去該指標所指向記憶體單元的位元組數。在陣列運算中,++和--可以指向前一個和後一個元素。
(5)空值運算
空值運算是指該指標變數不指向任何變數,即:
p = NULL;
(6)兩個指標變數相減
兩個指標變數相減,結果為兩個指標的差值,採用這種方法可以得到兩個元素之間的差值。差值的單位指的是指標所指向記憶體的大小。兩個指標變數進行有效減法運算的前提條件是兩個指標變數指向同一個陣列,這樣才有意義,若指向不同的陣列則不僅沒有意義,還會引起執行時的錯誤。
(7)兩個指標變數比較
如果兩個指標變數指向同一個陣列的元素,則兩個指標變數可以進行比較。指向前面的元素的指標變數“小於”指向後面的元素的指標變數。
注意:比較的前提條件是兩個指標指向相同型別的變數。
int *p1,*p2,K;
int a[10] = {1,3,5,7,9,11,13,15,17,19};
p1 = a; //p1指向陣列的首元素地址,即p=&a[0]
p2 = a; //p2指向陣列的首元素地址,即p=&a[0]
p1++; //p1指向陣列中的下一元素,即a[1]
K = *p1; //將p1所指元素賦給K,K = 3
K = *(p1+3) //將p1後第三個元素賦給K,K = 9,但p1本身不變
K = *p1 + 2 //將p1所指元素加2後賦給K,K = a[1]+2 = 5
if(p1>p2) //比較兩個所指陣列元素的下標
K = p1-p2 //將p1與p2所指元素下標相減,求得兩元素間的下標差值
//此時p1指向的是a[1],p2指向的是a[0],則K = p1-p2 = 1-0 = 1