一、指針簡介
1、什么是指針?
指針是一個變量,其值為另一個變量的地址,即內存地址的直接地址。做個比喻,假設將你比作變量,那么你身份證上的住址就是指針,根據你身份證上的地址可以找到你,即指針存的內容是你身份證上的住址。
指針有兩種含義,一是作為數據類型,二是作為實體。
指針作為實體,是一個用來保存一個內存地址的計算機語言中的變量。指針一般出現在比較底層的程序設計語言中,如C語言。高級語言如Java一般避免用指針,而是引用。指針作為數據類型,可以從一個函數類型、一個對象類型或者一個不完備類型中導出。從中導出的數據類型稱之為被引用類型(referenced type)。指針類型描述了一種對象,其值為對被引用類型的實體的引用。
指針可以用來有效地表示復雜的數據結構,可以用于函數參數傳遞并達到更加靈活使用函數的目的。使C語言程序的設計具有靈活、實用、高效的特點。
2、*與&操作符
取地址運算符(&):取變量的地址,即返回操作數的內存地址。&var 讀作"var 的地址"。
間接尋址運算符(*):返回操作數所指定地址的變量的值。
3、如何使用指針?
使用指針時會頻繁進行以下幾個操作:
- 定義一個指針變量;
- 把變量地址賦值給指針;
- 訪問指針變量中可用地址的值。
這些是通過使用一元運算符 * 來返回位于操作數所指定地址的變量的值。
#include <stdio.h>
int main (){
int var = 20; /* 實際變量的聲明 */
int *ip;/* 指針變量的聲明 */
ip = &var; /* 在指針變量中存儲 var 的地址 */
printf("Address of var variable: %x\n", &var );
/* 在指針變量中存儲的地址 */
printf("Address stored in ip variable: %x\n", ip );
/* 使用指針訪問值 */
printf("Value of *ip variable: %d\n", *ip );
return 0;
}
當上面的代碼被編譯和執行時,它會產生下列結果:
Address of var variable: bffd8b3c
Address stored in ip variable: bffd8b3c
Value of *ip variable: 20
4、指針運算符
C 指針是一個用數值表示的地址。因此,您可以對指針執行算術運算。可以對指針進行四種算術運算:++、--、+、-。
假設 ptr 是一個指向地址 1000 的整型指針,是一個 32 位的整數,讓我們對該指針執行下列的算術運算:
ptr++
在執行完上述的運算之后,ptr 將指向位置 1004,因為 ptr 每增加一次,它都將指向下一個整數位置,即當前位置往后移 4 個字節。這個運算會在不影響內存位置中實際值的情況下,移動指針到下一個內存位置。如果 ptr 指向一個地址為 1000 的字符,上面的運算會導致指針指向位置 1001,因為下一個字符位置是在 1001。
5、NULL 指針
在變量聲明的時候,如果沒有確切的地址可以賦值,為指針變量賦一個 NULL 值是一個良好的編程習慣。賦為 NULL 值的指針被稱為空指針。NULL 指針是一個定義在標準庫中的值為零的常量。請看下面的程序:
#include <stdio.h>
int main (){
int *ptr = NULL;
printf("ptr 的值是 %x\n", ptr );
return 0;
}
當上面的代碼被編譯和執行時,它會產生下列結果:
ptr 的值是 0
二、指針與數組
1、區別
C++/C程序中,指針和數組在不少地方可以相互替換著用,讓人產生一種錯覺,以為兩者是等價的。數組是連續分配一串單元,數目開始定義的時候就必須固定下來,看起來整潔,但是寫的程序是死程序,容易浪費內存。指針是存放一個地址值,表示指向某一個單元,可以用指針來索引單元。數組可以完成棧,堆,樹等等的操作,它在編程時候的好處是非常的靈活,在構建思路的時候有很大的靈活性。
2、指針數組與數組指針
指針數組:array of pointers,即用于存儲指針的數組,也就是數組元素都是指針。
數組指針:a pointer to an array,數組名本身就是一個指針,指向數組的首地址,即指向數組的指針。
int* a[4] ; /* 指針數組
表示:數組a中的元素都為int型指針
元素表示:*a[i] *(a[i])是一樣的,因為[]優先級高于*/
int (*a)[4] ;/* 數組指針
表示:指向數組a的指針
元素表示:(*a)[i] */
#include <stdio.h>
int main(void)
{
int c[4]={1,2,3,4};
int *a[4]; //指針數組
int (*b)[4]; //數組指針
b=&c;
//將數組c中元素賦給數組a
for(int i=0;i<4;i++)
{
a[i]=&c[i];
}
//輸出看下結果
printf("%d",*a[1]);//輸出2就對
printf("%d",(*b)[2]);//輸出3就對
return 0;
}
三、指針與字符串
C語言中沒有特定的字符串類型,我們通常是將字符串放在一個字符數組中。字符數組歸根結底還是一個數組,使用指針的方式來輸出字符串:
#include <stdio.h>
int main(){
char str[] = "http://www.lxweimin.com/";
char *pstr = str;
int len = strlen(str), i;
//使用*(pstr+i)
for(i=0; i<len; i++){
printf("%c", *(pstr+i));
}
printf("\n");
//使用pstr[i]
for(i=0; i<len; i++){
printf("%c", pstr[i]);
}
printf("\n");
//使用*(str+i)
for(i=0; i<len; i++){
printf("%c", *(str+i));
}
printf("\n");
return 0;
}
四、指針與函數
函數指針:本身是一個指針,指向一個函數入口地址,通過該指針可調用其指向的函數,使用函數指針可實現回調函數。
#include <stdio.h>
void inc(int *val)
{
(*val)++;
}
int main(void)
{
void (*fun)(int *);
int a=3;
fun=inc;//fun是一個函數指針
(*fun)(&a);
printf("%d" , a);
}
指針函數:本身是一個函數,其返回值是一個指針。
#include <stdio.h>
float *find(float(*pionter)[4],int n);//函數聲明
int main(void)
{
static float score[][4]={{60,70,80,90},{56,89,34,45},{34,23,56,45}};
float *p;
int i,m;
printf("Enter the number to be found:");
scanf("%d",&m);
printf("the score of NO.%d are:\n",m);
p=find(score,m-1);
for(i=0;i<4;i++)
printf("%5.2f\t",*(p+i));
return 0;
}
float *find(float(*pionter)[4],int n)/*定義指針函數*/
{
float *pt;
pt=*(pionter+n);
return(pt);
}
五、指針與引用
- 引用總是指向一個對象,沒有所謂的 null reference 。所有當有可能指向一個對象也有可能不指向對象則必須使用指針。由于C++ 要求 reference 總是指向一個對象所以 reference要求有初值.由于沒有所謂的 null reference 所以在使用前不需要進行測試其是否有值,而使用指針則需要測試其的有效性。
- 指針可以被重新賦值而reference則總是指向最初或地的對象。
- 必須使用reference的場合.Operator[]操作符由于該操作符很特別地必須返回 [能夠被當做ssignment 賦值對象] 的東西,所以需要給他返回一個 reference。
- 其實引用在函數的參數中使用很經常。格式如下:
void Get***(const int& a){} //這樣使用了引用又可以保證不修改被引用的值
區別:
- 指針是一個實體指向一塊內存,它的內容是所指內存的地址;引用是某塊內存的別名;
- 引用使用時無需解引用(*),指針需要解引用;
- 引用只能在定義時被初始化一次,之后不可變;指針可變;
- 引用“從一而終”;
- 引用沒有 const,指針有 const,const 的指針不可變;
- 引用不能為空,指針可以為空;
- sizeof 引用”得到的是所指向的變量(對象)的大小,而“sizeof 指針”得到的是指針本身(所指向的變量或對象的地址)的大小;typeid(T) == typeid(T&) 恒為真,sizeof(T) == sizeof(T&) 恒為真,但是當引用作為成員時,其占用空間與指針相同(沒找到標準的規定);
- 指針和引用的自增(++)運算意義不一樣。