指針

指針

電腦鼠标指針
在計算機科學中,指針(Pointer)是編程語言中的一個對象,利用地址,它的值直接指向(points to)存在電腦存儲器中另一個地方的值。由于通過地址能找到所需的變量單元,可以說,地址指向該變量單元。因此,将地址形象化的稱為“指針”。意思是通過它能找到以它為地址的内存單元。 在高級語言中,指針有效地取代了在低級語言,如彙編語言與機器碼,直接使用通用暫存器的地方,但它可能隻适用于合法地址之中。指針參考了存儲器中某個地址,通過被稱為反參考指針的動作,可以取出在那個地址中存儲的值。作個比喻,假設将電腦存儲器當成一本書,一張内容記錄了某個頁碼加上行号的便利貼,可以被當成是一個指向特定頁面的指針;根據便利粘貼面的頁碼與行号,翻到那個頁面,把那個頁面的那一行文字讀出來,就相當于是對這個指針進行反參考的動作。 在信息工程中指針是一個用來指示一個内存地址的計算機語言的變量或中央處理器(CPU)中寄存器(Register)【用來指向該内存地址所對應的變量或數組】。指針一般出現在比較接近機器語言的語言,如彙編語言或C語言。面向對象的語言如Java一般避免用指針。指針一般指向一個函數或一個變量。在使用一個指針時,一個程序既可以直接使用這個指針所儲存的内存地址,又可以使用這個地址裡儲存的函數的值。另外,指針也指鐘表中用來指示對應時間的部件。[1]
    中文名:指針 外文名:pointer 别名: 英文名:pointer 類别:指示測量的數據的裝置 适用範圍:計算機 作用:通過它找到以它為地址的内存單元

基本介紹

在日常生活中指針是儀器或鐘表上的,用來指示測量的數據的裝置。在信息工程中指針是一個用來指示一個内存地址的計算機語言的變量或中央處理器(CPU)中寄存器。

指針介紹

指針

在信息工程中指針是一個用來指示一個内存地址的計算機語言的變量或中央處理器(CPU)中寄存器(Register)。指針一般出現在比較近機器語言的語言,如彙編語言或C語言。面向對象的語言如Java一般避免用指針。指針一般指向一個函數或一個變量。在使用一個指針時,一個程序既可以直接使用這個指針所儲存的内存地址,又可以使用這個地址裡儲存的變量或函數的值。

指針與C語言

大家都認為,c語言之所以強大,以及其自由性,很大部分體現在其靈活的指針運用上。因此,說指針是c語言的靈魂,一點都不為過。同時,這種說法也讓很多人産生誤解,似乎隻有C語言的指針才能算指針。basic不支持指針,在此不論。其實,pascal語言本身也是支持指針的。從最初的pascal發展至今的object pascal,可以說在指針運用上,絲毫不會遜色于c語言的指針。

内存分配表

計算機中的内存都是編址的,就像你家的地址一樣。在程序編譯或者運行的時候,系統(可以不關心具體是什麼,可能是編譯器,也可能是操作系統)開辟了一張表。每遇到一次聲明語句(包括函數的傳入參數的聲明)都會開辟一個内存空間,并在表中增加一行紀錄。記載着一些對應關系。(如圖1所示)

----------------------------------------------------

Declaration | ID Name Address Length

----------------------------------------------------

int nP; | 1 nP 2000 2B

char myChar; | 2 myChar 2002 1B

int *myPointer; | 3 myPointer 2003 2B

char *myPointer2; | 4 myPointer2 2005 2B

----------------------------------------------------

是一個整數

指針,是一個無符号整數(unsigned int),它是一個以當前系統尋址範圍為取值範圍的整數。32位系統下尋址能力(地址空間)是4G-byte(0~2^32-1)二進制表示長度為32bit(也就是4B)。

int類型也正好如此取值。

例證(一)

例證就是程序1得到的答案和程序2的答案一緻。(不同機器可能需要調整一下pT的取值。)

----------------------------------------------------

程序1

#include

main()

{

char *pT;

char t='h';

pT=&t;

putchar(*pT);

}

----------------------------------------------------

程序2

#include

main()

{

char *pT;

char t='h';

pT=(char *)1245048;

putchar(*pT);

}

----------------------------------------------------

加上(char *)是因為畢竟int 和char *不是一回事,需要強制轉換,否則會有個警告。因為char *聲明過的類型,一次訪問1個sizeof(char)長度,double *聲明過的類型,一次訪問1個sizeof(double)長度。

在彙編裡int 類型和指針就是一回事了。因為不論是整數還是指針,執行自增的時候,都是其值加一。如果上文聲明char *pT;,彙編語言中pT自增之後值為1245049,可是C語言中pT++之後pT值為1245049。如果32 位系統中, s 上文聲明int *pT;,彙編語言中pT 自增之後值為1245049,可是C 語言中pT++之後pT值為1245052。

為什麼DOS下面的Turbo C,和Windows下VC的int類型不一樣長。因為DOS是16位的,Windows是32位的,可以預見,在64位Windows 中編譯,上文聲明int *pT;,pT++之後pT值為1245056。

例證(二)

那麼,複雜的結構怎麼分配空間呢?C語言的結構體(彙編語言對應為Record類型)按順序分配空間。(如圖2所示)

----------------------------------------------------

int a;

----------------------------------------------------

typedef struct st

{

double val;

char c;

struct st *next;

} pst;

----------------------------------------------------

pst pT;

----------------------------------------------------

在32 位系統下,内存裡面做如下分配(單位:H,16 進制);(如圖3所示)

----------------------------------------------------

變量 2000 2001 2002 2003 2004 2005 2006 … 204C 204D 204E 204F

地址 a a … a

----------------------------------------------------

變量 2050 2051 … 2057 2058 2059 205A 205B 205C 205D 205E 205F

地址 pst.val pst.c pst.next 無效 無效 無效

----------------------------------------------------

這就說明了為什麼sizeof(pst)=16而不是8。編譯器把結構體的大小規定為結構體成員中大小最大的那個類型的整數倍。

至于pT的存儲,可以依例推得。總長為160,此不贅述。

有個問題,如果執行pT++,答案是什麼?是自增16,還是160?别忘了,pT 是常量,不能加減。

所以,我們就可以聲明:

----------------------------------------------------

typedef struct BinTree

{

int value;

struct BinTree *LeftChild;

struct BinTree *RightChild;

} BTree;

----------------------------------------------------

用一個整數,代表一棵樹的結點。把它賦給某個結點的LeftChild/RightChild 值,就形成了上下級關系。隻要無法找到一個路徑,使得A->LC/RC->LC/RC...->LC/RC==A,這就構成了一棵二叉樹。反之就成了圖。

指針的作用

指針可以用來有效地表示複雜的數據結構,可以用于函數參數傳遞并達到更加靈活使用函數的目的.使C語言程序的設計具有靈活、實用、高效的特點。

指針不僅僅是C語言的靈魂,運用得好更是事半功倍,讓你寫出的程序更簡潔!

指針網

一個專門用于圖書搜索的網站,指針圖書網。自稱全球最大中文圖書檢索網站。

鐘表的指針

在日常生活中指針是儀器或鐘表上的,可動的,一般狹長的,往往在一段尖的用來指示測量的數據的裝置。

指針法

指針是以手指按壓或爪切某些穴位,代替針刺治病的一種治療方法,具有疏通經絡、行氣活血、調和髒腑功能、開竅醒神、止痛等作用。常用于突發性病症,如虛脫、中暑、癔病及多種痛症。亦可用于一些内傷外感雜病的治療。

按值傳遞

C中函數調用是按值傳遞的,傳入參數在子函數中隻是一個初值相等的副本,無法對傳入參數作任何改動。但實際編程中,經常要改動傳入參數的值。這一點我們可以用傳入參數的地址而不是原參數本身,當對傳入參數(地址)取(*)運算時,就可以直接在内存中修改,從而改動原想作為傳入參數的參數值。

編程參數值

#include

voidinc(int*val)

{

(*val)++;

}

main()

{

inta=3;

inc(&a);

printf("%d",a);

}

在執行inc(&a);時,系統在内存分配表裡增加了一行“inc中的val”,其地址為新地址,值為&a。操作*val,即是在操作a了。

*和&運算

(*p)操作是這樣一種運算,返回p 的值作為地址的那個空間的取值。(&p)則是這樣一種運算,返回當時聲明p 時開辟的地址。顯然可以用賦值語句對内存地址賦值。我們假設有這麼兩段内存地址空間,他們取值如下:(單位:H,16 進制)(如圖4所示)

假設有這麼一段代碼:(假設開辟空間時p 被分配給了3001H、3002H 兩個位置)

int *p;

p=2003H;

*p=3000H

**p的值為多少?

**p=*(*(p))=*(*(2003H))=*(3000H)=3000H。

那麼&&p、*(&p)和&(*p)又等于多少?

&&p=&(&(p))=&(3001H),此時出錯了,3001H 是個常數怎麼可能有地址呢?

*&p=*(&(p))=*(3001H)=2003H,也就是*&p=p。

&*p=&(*p)=&(3000H)=2003H,之前有人認為這個是不成立的,實際上&(3000H)是求存儲3000H這個變量所在的内存地址,仍然是p的值。下面的代碼是個很簡單的例子:

輸出的結果為5

另類*和&

兩個地方要注意: 在程序聲明變量的時候的*,隻是表明“它是一個無符号整數,這個整數指向某個内存地址,一次訪問sizeof(type)長度”。這點不要和(*)操作符混淆;

在C++程序聲明變量的時候的&,隻是表明“它是一個引用,這個引用聲明時不開辟新空間,它在内存分配表加入新的一行,該行内存地址等于和調用時傳入的對應參數内存地址”。

這點不要和(*)聲明符,(&)操作符混淆。

雙級指針

對于一棵樹,我們通常用它的根節點地址來表示這棵樹。這就是“擒賊先擒王”。找到了樹的根,其每個節點都可以找到。但是有時候我們需要對樹進行删除節點,增加節點操作,往往考慮到删除根節點,增加的節點取代原來的根節點作為新根節點的情況。為了修改根節點這個“整數”,我們需要退一步,使用這個“整數”的内存地址,也就是指向這個“整數”的指針。在聲明時,我們用2個*号,聲明指向指針的指針。它的意思是“它是一個整數,這個整數指向某個内存地址,一次訪問sizeof(int)長度,其值是一個整數,那個整數值指向某個内存地址,一次訪問sizeof(BTree)長度。”。詳見<數據結構>有關“樹”的程序代碼。由于存放的指針變量的地址,因此是指向指針變量的指針變量,或稱二級指針變量。

指針的初始化

對指針進行初始化或賦值隻能使用以下四種類型的值

:

1. 0 值常量表達式,例如,在編譯時可獲得 0 值的整型 const對象或字面值常量 0。

2. 類型匹配的對象的地址。

3. 另一對象末的下一地址。

4. 同類型的另一個有效指針。

把 int 型變量賦給指針是非法的,盡管此 int 型變量的值可能為 0。但允

許把數值 0 或在編譯時可獲得 0 值的 const 量賦給指針:

int ival;

int zero = 0;

const int c_ival = 0;

int *pi = ival; // error: pi initialized from int value of ival

pi = zero;// error: pi assigned int value of zero

pi = c_ival;// ok: c_ival is a const with compile-time value of 0

pi = 0;// ok: directly initialize to literal constant 0

除了使用數值 0 或在編譯時值為 0 的 const 量外,還可以使用 C++ 語言從 C 語言中繼承下來的預處理器變量 NULL,該變量在 cstdlib頭文件中定義,其值為 0。如果在代碼中使用了這個預處理器變量,則編譯時會自動被數值 0 替換。因此,把指針初始化為 NULL 等效于初始化為 0 值

:

// cstdlib #defines NULL to 0

int *pi = NULL; // ok: equivalent to int *pi = 0;

與數組關系

指針數組:就是一個由指針組成的數組,那個數組的各個元素都是指針,指向某個内存地址。char *p;//p是一個指針數組

數組指針:數組名本身就是一個指針,指向數組的首地址。注意這是一個常數。

example:

char (*p)//p是一個數組指針

函數指針:本身是一個指針,指向一個函數入口地址,通過該指針可調用其指向的函數,使用函數指針可實現回調函數。

example:

#include

void inc(int *val)

{

(*val)++;

}

main()

{

void (*fun)(int *);

int a=3;

fun=inc;//fun是一個函數指針

(*fun)(&a);

printf("%d" , a);

}

指針函數:本身是一個函數,其返回值是一個指針。

example:

void * fun(void);//fun是一個指針函數

這個問題大家應該都碰到過,指針數組和數組指針,剛開始看時覺得還是能看懂,但是過些時又搞混了,最後發現還是沒有真正理解。

下面就簡單說說這兩個概念:一:指針數組,顧名思義,就是說的首先是一個數組吧,然後數組的元素是指針而已。說明形式為:type *pointer_array[constant1][constant2]...[constantn]; 例如:int *pai; 由于‘*’是自右向左結合,因此從右向左看,首先看到說明是一個數組,是一個包含4個元素的數組,然後看到‘*’,顯然是指針類型,由此可以看出數組中存放的是指針而不是一般的類型。同理,char *pac是包含有6個元素,每一個元素都是一個字符型指針。再來說說他們的初始化: int *pai;既然是一個包含4個整形指針的數組那麼其對應的将是一個二維整形數組,因為一個整形指針對應一個一維整形數組。那我就用一個二維整形數組來初始化它,事實上一般也都是這麼做的,這裡有一個二維數組,int arr={{1,2},{3,4},{5,6}},一個三行兩列的整形數組,注意這裡的行必須和你的指針數組的維數一緻,否則是不允許的,不信你可以試試。這個初始化有很多種選擇,以下隻列舉常見的兩種:第一種也是很好理解的: for(int i=0;i<3;i++) pai[i]=arr[i]; 顯然arr[i]是每一行的首地址,相當于一個一維數組的數組名,如是把它送給一個整形指針pai[i]是理所當然的了。

第二種方法:在說明數組指針時就初始化:int (*ap)={{1,2},{3,4},{5,6}};

注意:不能将二維數組的數組名賦給指針數組的數組名,pai=arr(錯),因為兩者的類型不一緻,二維數組名的類型是指向int[][]型的指針,而指針數組的的數組名是指向int *[]類型的指針。

在c/c++語言中,指針數組最常用的場合就是說明一個字符串數組。即說明一個數組,它的每個元素都是一個字符串。

二:數組指針:指向一個數組的指針。說明形式為:type (*pointer_array)[constant1][constant2]...[constantn]; 注意這裡的圓括号是必須就将這是由于方括号[],較指針說明符“*”的優先級高,若無此圓括号,編譯器将把上述說明解釋成成了一個數組指針。例如:int (*ap); 這樣就說明了一個指向包含有2個元素的整形數組的數組指針,聽起來确實有點别扭。不過仔細分析應該還是能理解的,就是說ap是一個指針,而它指向的對象是一個指針,注意不要将它和一個指向一個整形變量的指針搞混了。同樣以一個二維數組來說明其初始化問題, int arr={{1,2},{3,4},{5,6}};注意這裡的列數必須和數組指針所指的數組的列數相同。第一種方法: ap=arr; 為什麼這裡能這樣将二維數組名送給ap呢,你可以這樣理解,二維數組不就可以看成是一維數組的數組嗎,而一個數組指針它指向的内容就是一個一維數組,那麼你就可以把這個數組指針當做是一個數組名,隻不過這個數組裡的元素不是像int,char之類型的,而是一個數組,這樣你就可以把它和二維數組的數組名聯系在一起了。

第二種方法: ap=&arr; 這裡arr其實就是一維數組的數組名,将它的地址給ap是很自然的,因為ap本來就是指向一個一維數組的。注意這裡不能這樣初始化:int (*a)={{1,2},{3,4},{5,6}};大家可以想想為什麼。當然他們也可以動态賦值,由于篇幅就不探讨了。

與“引用”的區别

C++編程中指針與引用的區别

一、指針和引用的區别

(1)引用總是指向一個對象,沒有所謂的 null reference .所有當有可能指向一個對象也有可能不指向對象則必須使用 指針.

由于C++ 要求 reference 總是指向一個對象所以 reference要求有初值.

String & rs = string1;

由于沒有所謂的 null reference 所以在使用前不需要進行測試其是否有值,而使用指針則需要測試其的有效性.

(2)指針可以被重新賦值而reference則總是指向最初或地的對象.

(3)必須使用reference的場合. Operator[] 操作符 由于該操作符很特别地必須返回 [能夠被當做assignment 賦值對象] 的東西,所以需要給他返回一個 reference.

(4)其實引用在函數的參數中使用很經常.

void Get***(const int& a) //這樣使用了引用又可以保證不修改被引用的值

{

}

★ 相同點:

1. 都是地址的概念;

指針指向一塊内存,它的内容是所指内存的地址;引用是某塊内存的别名。

★ 區别:

1. 指針是一個實體,而引用僅是個别名;

2. 引用使用時無需解引用(*),指針需要解引用;

3. 引用隻能在定義時被初始化一次,之後不可變;指針可變;

引用“從一而終”

4. 引用沒有 const,指針有 const,const 的指針不可變;

5. 引用不能為空,指針可以為空;

6. “sizeof 引用”得到的是所指向的變量(對象)的大小,而“sizeof 指針”得到的是指針本身(所指向的變量或對象的地址)的大小;

typeid(T) == typeid(T&) 恒為真,sizeof(T) == sizeof(T&) 恒為真,

但是當引用作為成員時,其占用空間與指針相同(沒找到标準的規定)。

7. 指針和引用的自增(++)運算意義不一樣;

二、C++中指針傳遞與引用傳遞(進一步整理)

從概念上講。指針從本質上講就是存放變量地址的一個變量,在邏輯上是獨立的,它可以被改變,包括其所指向的地址的改變和其指向的地址中所存放的數據的改變。

而引用是一個别名,它在邏輯上不是獨立的,它的存在具有依附性,所以引用必須在一開始就被初始化,而且其引用的對象在其整個生命周期中是不能被改變的(自始至終隻能依附于同一個變量)。

在C++中,指針和引用經常用于函數的參數傳遞,然而,指針傳遞參數和引用傳遞參數是有本質上的不同的:

指針傳遞參數本質上是值傳遞的方式,它所傳遞的是一個地址值。值傳遞過程中,被調函數的形式參數作為被調函數的局部變量處理,即在棧中開辟了内存空間以存放由主調函數放進來的實參的值,從而成為了實參的一個副本。值傳遞的特點是被調函數對形式參數的任何操作都是作為局部變量進行,不會影響主調函數的實參變量的值。(這裡是在說實參指針本身的地址值不會變)

而在引用傳遞過程中,被調函數的形式參數雖然也作為局部變量在棧中開辟了内存空間,但是這時存放的是由主調函數放進來的實參變量的地址。被調函數對形參的任何操作都被處理成間接尋址,即通過棧中存放的地址訪問主調函數中的實參變量。正因為如此,被調函數對形參做的任何操作都影響了主調函數中的實參變量。

引用傳遞和指針傳遞是不同的,雖然它們都是在被調函數棧空間上的一個局部變量,但是任何對于引用參數的處理都會通過一個間接尋址的方式操作到主調函數中的相關變量。而對于指針傳遞的參數,如果改變被調函數中的指針地址,它将影響不到主調函數的相關變量。如果想通過指針參數傳遞來改變主調函數中的相關變量,那就得使用指向指針的指針,或者指針引用。

為了進一步加深大家對指針和引用的區别,下面我從編譯的角度來闡述它們之間的區别:

程序在編譯時分别将指針和引用添加到符号表上,符号表上記錄的是變量名及變量所對應地址。指針變量在符号表上對應的地址值為指針變量的地址值,而引用在符号表上對應的地址值為引用對象的地址值。符号表生成後就不會再改,因此指針可以改變其指向的對象(指針變量中的值可以改),而引用對象則不能修改。

最後,總結一下指針和引用的相同點和不同點:

★相同點:

●都是地址的概念;

指針指向一塊内存,它的内容是所指内存的地址;而引用則是某塊内存的别名。

★不同點:

●指針是一個實體,而引用僅是個别名;

●引用隻能在定義時被初始化一次,之後不可變;指針可變;引用“從一而終”,指針可以“見異思遷”;

●引用沒有const,指針有const,const的指針不可變;(具體指沒有int& const a這種形式,而const int& a是有 的, 前者指引用本身即别名不可以改變,這是當然的,所以不需要這種形式,後者指引用所指的值不可以改變)

●引用不能為空,指針可以為空;

●“sizeof 引用”得到的是所指向的變量(對象)的大小,而“sizeof 指針”得到的是指針本身的大小;

●指針和引用的自增(++)運算意義不一樣;

●引用是類型安全的,而指針不是(引用比指針多了類型檢查)

操作方法

指針的基本手法可分為揉、扪、切、捏、點5種。

1. 揉法:是用手指的尖端,輕按選下的穴位,作環形平揉的一種方法。揉動時手指的尖端不能離開所接觸的皮膚,手指連同皮膚及皮下組織,以穴位為中心,作一小圓形轉動,不要使手指與皮膚呈摩擦狀态。每次揉一小圓周為1次,每穴位一般以120~180次為标準,約2~3分鐘。次數的多少亦可視病情的輕重而定。常用拇拽和中指作揉法。本法在指針中應用較廣。施術時需要根據病人質強弱和病情輕重施以輕重不同的指力。本法可與扪法配合應用。

2. 扪法:是用手指扪按腧穴或身體一定部位的手法。将手指端深深按壓皮膚及皮下組織深部,同時根據病人體質強弱,施以輕重不同的指力,以感到酸麻脹痛為止。當指端按入時,應逐漸減輕指力,最後停止。每穴一般扪按3分鐘左右。扪法又分為單指法和雙指法2種。

(1)單指法:一般用拇指或中指指端按壓在穴位上。此法常用于胸腹部和四肢部的穴位,如氣海CV (RN)6 ,中脘CV (RN)12,曲池LI11 、足三裡ST36等(見圖)

(2)雙指法:即兩手指同時扪按兩個穴位。此法常用于頭面、頸項、腹部、背腹部的穴位,如風池GB20 、陽白GB14 、天樞ST25 等穴位。(見圖)

3. 切法:用拇指指甲切按腧穴。操作時可用脫脂棉少許,複于指甲 ,防止切傷皮膚。指切時用力需要輕而緩慢,特别是壓痛處更應注意,盡量避免切處劇烈疼痛。本法多用于狹窄部位的穴位,如人中GV (DU)26 、迎香LI20 、少商LU11 等(見圖)。

4. 捏法:是用兩個手指對稱捏壓穴位的手法,可用拇、食二指,也可用拇、中二指或拇指與其它各指,在上下方或左右方對稱相向用力。可捏壓一個或兩個穴位上。如果捏壓一個穴位,拇指在這個穴位上,另一指或其它各指則在對稱地方,此法常用于四肢、肩頸部等部位的穴位,如合谷LI4 、曲池LI11 、足三裡ST36 、三陰交SP6 等(見圖)。

5. 點法:是一指或二、三指點在痛點或穴位上,先輕後重。逐漸深透。本法常用于肩部、背部、臀部和大腿等部位的穴位。

适用範圍

由于指針療法不需要任何操作器械及穴位消毒,可以随時随地應用,因此可應用于多種急症的處理,如暈厥、劇烈疼痛等。又因指針療法具有疼痛小的特點,因此廣泛适用于年老體弱、兒童、懼怕針刺者及孕婦等。也可作為患者自我治療及預防疾病的一種方法。

注意事項

(1)施術者注意手的消毒,以免交叉感染;指甲宜常剪,以免切傷病人皮膚。

(2)指力的輕重以病人能耐受為宜。以免病人産生不适或暈針;對年老體弱者和兒童,施術時指力不可過重。

(3)指針的施術時間以1~3分鐘為标準,亦可根據病情增減。

(4)急性傳染病、皮膚病、腫瘤以及腹痛拒按的患者,不宜使用指針。

(5)小兒頭部的囟門區和孕婦的合谷LI4 、三陰交SP6 以及腹部穴位等,不宜用指針。

(6)過饑、過飽、酒醉、勞累過度時,不宜用指針。

上一篇:軟件架構

下一篇:W3C标準

相關詞條

相關搜索

其它詞條