指針的指針

void FindCredit(int **);

main() { int vals[]={7,6,5,-4,3,2,1,0}; int *fp=vals; FindCredit(&fp); printf("%d\n",*fp); }

void FindCredit(int ** fpp){while(**fpp!=0)if(**fpp<0) break;else (*fpp)++;}

首先用一個數組的地址初始化指針fp,然後把該指針的地址作爲實參傳遞給函數FindCredit()。FindCredit()函數通過表達式 **fpp 間接地得到數組中的數據。爲遍歷數組以找到一個負值,FindCredit()函數進行自增運算的對象是調用者的指向數組的指針,而不是它自己的指向調用者指針的指針。語句(*fpp)++就是對形參指針指向的指針 進行自增運算。但是因爲*運算符高於++運算符,所以圓括號在這裏是必須的,如果沒有圓括號,那麼++運算符將作用於二重指針fpp上。

 

指向指針數組的指針 指針的指針另一用法處理指針數組。有些程序員喜歡用指針數組來代替多維數組,一個常見的用法就是處理字符串。

char *Names[]={"Bill","Sam","Jim","Paul","Charles",0};

          main(){char **nm=Names;while(*nm!=0) printf("%s\n",*nm++);}

先用 字符型指針數組Names的地址來初始化指針nm。每次printf()的調用都首先傳遞指針nm指向的字符型指針,然後對nm進行自增運算使其指向數組的下一個元素(還是指針)。注意完成上述認爲的語法爲*nm++,它首先取得指針指向的內容,然後使指針自增。 注意數組中的最後一個元素被初始化爲0,while循環以次來判斷是否到了數組末尾。具有零值的指針常常被用做循環數組的終止符。程序員稱零值指針爲空指針(NULL)。採用空指針作爲終止符,在樹種增刪元素時,就不必改動遍歷數組的代碼,因爲此時數組仍然以空指針作爲結束

指向指針的指針,很早以前在說指針的時候說過,但後來發現很多人還是比較難以理解,這一次我們再次仔細說一說指向指針的指針。先看下面的代碼,注意看代碼中的註解:

#include <iostream>  
#include <string>  
using namespace std;  
void print_char(char* array[],int len);  
//函數原形聲明 void main(void) {  
//-----------------------------段1----------  
char *a[]={"abc","cde","fgh"};//字符指針數組  
char* *b=a;  
//定義一個指向指針的指針,  
並賦予指針數組首地址所指向的第一個字符串的地址也就是abc\0字符串的首地址  
cout<<*b<<"|"<<*(b+1)<<"|"<<*(b+2)<<endl;  
  //-----------------------------段2----------  
  char* test[]={"abc","cde","fgh"};  
//注意這裏是引號,表示是字符串,以後的地址每加1就是加4位(在32位系統上)  
  int num=sizeof(test)/sizeof(char*);  
//計算字符串個數  
  print_char(test,num);  
  cin.get();  
    }  
void print_char(char* array[],int len)  
//當調用的時候傳遞進來的不是數組, 而是字符指針他每加1也就是加上sizeof(char*)的長度  
  {  
  for(int i=0;i<len;i++)  
  {  
  cout<<*array++<<endl;  
  }   }   下面我們來仔細說明一下字符指針數組和指向指針的指針,段1中的程序是下面的樣子:  
  char *a[]={"abc","cde","fgh"};  
  char* *b=a;  
  cout<<*b<<"|"<<*(b+1)<<"|"<<*(b+2)<<endl;  
  char *a[]定義了一個指針數組,注意不是char[],char[]是不能同時初始化爲三個字符的,定義以後的a[]其實內部有三個內存位置,分別存儲了abc\0,cde\0,fgh\0,三個字符串的起始地址,而這三個位置的內存地址卻不是這三個字符串的起始地址,在這個例子中a[]是存儲在棧空間內的,而三個字符串卻是存儲在靜態內存空間內的const區域中的,接下去我們看到了char* *b=a;這裏定義了一個指向指針的指針, 如果你寫成char *b=a;那麼是錯誤的,因爲編譯器會返回一個無法將char* *[3]轉換給char *的錯誤,b=a的賦值,實際上是把a的首地址賦給了b,由於b是一個指向指針的指針, 程序的輸出  
cout<<*b<<"|"<<*(b+1)<<"|"<<*(b+2)<<endl;  

 

結果是

 

abc cde fgh  

可以看出每一次內存地址的+1操作事實上是一次加sizeof(char*)的操作,我們在32位的系統中sizeof(char*)的長度是4,所以每加1也就是+4,實際上是*a[]內部三個位置的+1,所以*(b+1)的結果自然就是cde了,我們這時候可能會問,爲什麼輸出是cde而不是c一個呢?答案是這樣的,在c++中,輸出字符指針就是輸出字符串,程序會自動在遇到\0後停止。

我們最後分析一下段2中的代碼,段2中我們調用了print_array()這個函數,這個函數中形式參數是char *array[]和代碼中的char *test[]一樣,同爲字符指針,當你把參數傳遞過來的時候,事實上不是把數組內容傳遞過來,test的首地址傳遞了進來,由於array是指針,所以在內存中它在棧區,具有變量一樣的性質,可以爲左值,所以我們輸出寫成了:

 

cout<<*array++<<endl;  

當然我們也可以改寫爲:

 

cout<<array[i]<<endl  

這裏在循環中的每次加1操作和段1代碼總的道理是一樣的,注意看下面的圖!

到這裏這兩個非常重要的知識點我們都說完了,說歸說,要想透徹理解希望讀者多動手,多觀察,熟能生巧。下面是內存結構示意圖:

 

指針的指針,數組指針,指針數組 轉載 - 老人與海 - 我的博客

最近好像是跟指針卯上了,發現以前真的學得不好,太多的東西是模模糊糊的。可能是因爲S現在做的項目有太多地方使用到指針,而且有的時候用到複雜的指針,所以才覺得有必要好好的研究下,這樣可以減輕S的負擔,也爲我以後做準備吧。

要搞清一個指針首先必須搞清指針的四方面的內容

指針的類型,指針所指向的類型,指針的值或者叫指針所指向的內存區,還有指針本身所佔據的內存區(這裏只對int型進行說明,其他的類推)。

 

指針的類型:從語法的角度看,你只要把指針聲明語句裏的指針名字去掉,剩下的部分就是這個指針的類型,這是指針本身所具有的類型。例如: (1)int *ptr; //指針的類型是 int *  整型指針 (2)int **ptr; //指針的類型是 int **  指針的指針 (3)int (*ptr)[3]; //指針的類型是 int(*)[3] 數組指針 (4)int *ptr[3]; //指針的類型是 int*[3] 指針數組

 

指針所指向的類型: (1)int *ptr; //指針所指向的類型是 int 指向整型 (3)int **ptr; //指針所指向的的類型是 int * 指向整型指針 (4)int (*ptr)[3]; //指針所指向的的類型是 int()[3] 指向整型數組 (5)int *ptr[3];//指針所指向的類型是 int[] 指向指針數組的第一個單元

 

指針的值(又稱指針所指向的內存區或地址): 指針的值是指針本身存儲的數值,這個值將被編譯器當作一個地址,而不是一個一般的數值。在32位程序裏,所有類型的指針的值都是一個32位整數,因爲32位程序裏內存地址全都是32位長。指針所指向的內存區就是從指針的值所代表的那個內存地址開始,長度爲sizeof(指針所指向的類型)的一片內存區。以後,我們說一個指針的值是XX,就相當於說該指針指向了以爲首地址的一片內存區域;我們說一個指針指向了某塊內存區域,就相當於說該指針的值是這塊內存區域的首地址。

 

指針本身所佔據的內存區:指針類型本身佔據的內存空間,在32位平臺中,指針本身佔據4個字節的長度,可以使用sizeof(指針類型)來測試下指針佔據的存儲空間

以上是預備知識,接下來言歸正傳。

 

指針的指針:這個比較簡單,如下代碼1:指針pni指向整型變量ni,pni的值爲ni所在內存中的地址,指針的指針ppni指向一個整型指針,ppni的值爲指針pni所在的存儲單元的地址。

int ni=10; int* pni=&ni; int** ppni=&pni;

數組指針:顧名思義,指向數組的指針,這裏一定要區分指向數組首單元的指針和數組指針的區別

如下代碼2: int narr[3]; int *p=narr;

在以上代碼中,narr只是一個指代數組首地址的指針,而不是一個指向數組的指針。所以p只是一個指向數組首地址的指針。這個例子在《指針和數組名的區別》文章有詳細介紹。

數組指針的使用見下代碼3:

void main(){

          int array[2][3] = {{1,2,3},{4,5,6}};//二維數組看作是兩個一維數組           int (*pa)[3]; //申明一個數組指針,若(*pa)[3]中不爲3則出錯                         //array[0]指代二維數組中{1,2,3}的首地址,那麼&array[0]是數組指針型

                     //第三行定義的pa是指向一個3維數組的數組指針

          pa = &array[0];   //即(*pa)相當於array[0]。           cout<<pa[0]<<"|"<<pa[1]<<"|"<<pa[2]<<endl;           cout<<pa<<endl;           cout<<*pa<<endl;

          cout<<(*pa)[0]<<"|"<<(*pa)[1]<<"|"<<(*pa)[2]<<endl;           cout<<**pa<<endl;           cout<<*(*pa+2)<<endl;

          pa++;           cout<<pa[0]<<"|"<<pa[1]<<"|"<<pa[2]<<endl;           cout<<pa<<endl;           cout<<*pa<<endl;

          cout<<(*pa)[0]<<"|"<<(*pa)[1]<<"|"<<(*pa)[2]<<endl;           cout<<**pa<<endl;           cout<<*(*pa+2)<<endl;

} 輸出爲:

0012FF68|0012FF74|0012FF80

0012FF68

0012FF68

 

1|2|3

1

3

 

0012FF74|0012FF80|0012FF8C

0012FF74

0012FF74

 

4|5|6

4

6

 

以上代碼中第三行定義的pa是指向一個3維數組的數組指針。*pa就是一維數組的指針,自然可以使用

(*pa)[i]的方式訪問數組,而*pa+1則是(*pa)[1]這個元素的地址,所以自然得到第5,6,7行所註釋的輸出。經過pa++語句,由於pa是數組指針,後來pa中存放的地址應該是*pa+sizeof(array[0]),所以現在*pa就是一維數組{4,5,6}對應的首地址,同理得到第9,10,11行所註釋的輸出結果。

 

指針數組:也就是指針的數組,存放指針的數組,數組中的元素是指針。 例如:

int n1=10; int n2=20; int* np[2]={&n1,&n2}; cout<<*(np[0])<<endl; cout<<*(np[1]);//輸出20 上述代碼的第三行定義了一個指針數組,數組中含有兩個元素,分別是n1、n2的地址,np[0],np[1]就是對應的這兩個地址,所以*np[0],*np[1]分別是10,20

 

對於指針的指針、數組指針、指針數組,我們還可以給出更爲直觀的定義方法:

指針的指針: typedef int* intP; intP* p;

數組指針: typedef int intArray[2]; intArray* p;

指針數組: typedef int* intPtr; intPtr p[2]; 由於一些運算符優先級不同(*的優先級比[]低),所以在適當的時候使用typedef可以有效的避免迷惑性

這幾天的研究結束了我和S對指針的困惑,所以作此總結,希望對大家都有幫助。

數組指針與指針數組的區別
int (*p)[10]; 定義了一個數組指針它是個指針 這個指針與一般的指針沒有什麼區別,僅僅是這個指針指向一個數組。這裏我們把數組作爲了基本的元素處理。也就是說,將整個數組作爲一種類型,而數組名就是這個類型的一個具體變量。例如:

int a[10]; 一個數組類型,形狀就是這樣:int [10]; a就是新定義的一個變量。 int b[3]; 一個數組類型,形狀就是這樣:int [3];b就是新定義的一個變量。 因爲這兩個類型形狀不一樣,因此是兩個不同的類型,因此a,b就是不同類型的變量。這就好比int a和double b :a和b不一樣。不知道大家是否已經對數組類型有了基本的印象? 那麼把數組名作爲該數組類型的一個具體變量,我們就可以定義指向這個變量的指針,即數組指針。 對於數組類型:int [10],我們可以定義一個指針,int (*p) [10].注意這裏一定要加上小括弧。否則就會變成了指針數組。定義了指針之後,我們可以對該指針賦值,如p=&a;如果定義了一個二維數組,int c[3][10]。我們可以認爲定義了一個一維的數組,這個數組有三個int[10]的元素。因此和一般的數組一樣,我們可以將該數組名賦給指針,其實也就是第一個元素的地址付給指針。即: p=c;或者p=&c[0]。其餘情況以此類推。 --------------------------------------------------------------- 數組指針是指針類型,它指向一個數組,代表數組的首地址

指針數組首先是一個數組,只不過這個數組的元素是指針而己

 

數組指針是定義的一個指針,而指針 所指的對象是一個數組指針 指向該數組的首單元的地址它對數組的內部元素的屬性不瞭解,只是規定了首單元的地址,通過它可以找到該數組

指針數組指的是一個數組,它其中的所有元素都是指針類型,這裏所有指針都指向不同的地址,而所指地址的數據也不一定相同,但是必須屬於同一數據類型。 二者相差很多。 --------------------------------------------------------------- 下面的程序有錯誤嘛?爲什麼? #include<iostream.h> void main(){ int *p=new int [10]; int arr[10]; int (*ptr)[10]; ptr=p;//cannot convert from 'int *' to 'int (*)[10]' ptr=arr;//cannot convert from 'int [10]' to 'int (*)[10]' ptr=&arr;//正確 typedef int (*type)[10];//正確 type pa=&(new int[10]); int* pb; type pc=&(pb=new int[10]); type pd=(type)(new int[10]); }

數組指針是指向數組的, 如: int a[3][3],(*p)[3]; p=a; 這裏(*p)[3]用於告訴編譯系統,它是一個指針,指向一個長度爲3的整型數組。這樣在用指針訪問其所指向的內存單元的時候就可以用 *(*(p+i)+j) 來表示 a[i][j];

若:int a[3][3],*p; p=a; 就需用:*(p+3*i+j)來表示a[i][j].

指針數組是這樣一種特殊的數組:它的每一個數組元素都是一個指針。 如:int *p[3]; p[0],p[1],p[2]都是一個指針。

我看了你所說的有關指針問題的看法,我非常同意你所說的. 其實我也有一點看法:所謂指針數組嗎,其實就可以把他看成一個結構體指針,只是他裏面的元素都是相同的類型.

例如:int (*p)[10];p就是指向一個由10個整型單元構成的數組的指針.p必須是指向由10個整型單元構成的數組,就如一個結構體指針必須指向與它相同類型的一個結構體一樣
前言: 其實數組也就是一個邏輯上的擁有首地址的連續的內存空間。 1。我們常常用改變下標的方式來訪問數組,本質上和通過加減某種特定類型的 指針來實現在邏輯內存上的跳躍是相同的,其實數組的越界和程序員通過指針 強行訪問邏輯內存是一樣的原理,只是指針更加靈活,同時也帶來的大量的 安全性問題。 2。而對於諸如 int*(*p)[i] 這樣的問題,無非就是一個指針的指針,而後一指針表象上就是那個數組,所以如果我們要想訪問數組元素,就必須通過多加一個指針的方式來訪問,而且還需要注意的是,後一指針也就是表象上的數組的尋址或者是跳躍方式是按照每一個元素以sizeof(int)的空間來跳躍的,我們也可以讓這樣的int成爲其他的基本類型或者是擴展類型,只不過改變的跳躍的空間的大小或者是方式(這裏的方式可以認爲是某種具有嵌套關係的擴展類型)。

發佈了20 篇原創文章 · 獲贊 12 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章