轉自:http://blog.csdn.net/haussuden/article/details/5965304html
指針與多維數組java
(主要指二維數組)程序員
int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};數組
換個角度看世界:函數
如首行同樣,將首行視爲一個元素,一個特殊的元素,這個「特殊的」元素是一個一維數組。那麼這個二維數組是由是由三個「特殊的」元素組成的一個「特殊的」一維數組。post
a是這個「特殊的」一維數組的名稱,也就是首地址,也就是第一個元素的地址,也就是第一行的首地址,是指首行一整行,並非指某個具體元素。那麼咱們稱之爲「行指針」。同理:a+0,a+1,a+2,都是行指針。性能
結論:學習
表示形式字體 |
含義url |
指針類型 |
a或者a+0 |
指向第0行 |
行指針 |
a+1 |
指向第1行 |
行指針 |
a+2 |
指向第2行 |
行指針 |
接下來,咱們來放大觀看首行,首行的元素分別是:a[0][0],a[0][1],a[0][2],a[0][3]。將其看做一個獨立的一維數組,那麼 a[0]就是這個數組的名稱,也就是這個數組的首地址,也就是第一個元素的地址,也就是a[0]+0。a[0]和a[0]+0都是指具體的元素,那麼咱們稱之爲「列指針」。
結論:(第0行視爲一維數組)
表示形式 |
含義 |
指針類型 |
a[0] |
是一維數組的名稱,也是它的首地址,並且是第1個元素的地址(a[0]+0) |
列指針 |
a[0]+1 |
第0行,第2個元素的地址 |
列指針 |
a[0]+2 |
第0行,第3個元素的地址 |
列指針 |
兩個重要概念:行指針和列指針。
行指針:指的是一整行,不指向具體元素。
列指針:指的是一行中某個具體元素。
能夠將列指針理解爲行指針的具體元素,行指針理解爲列指針的地址。
那麼兩個概念之間的具體轉換是:
*行指針----列指針
&列指針----行指針
根據以上轉換公式:
行指針 |
轉換成:列指針 |
列指針等價表示 |
內容 |
內容等價表示 |
含義 |
a或a+0 |
*a |
a[0] |
*a[0] |
*(*a) |
a[0][0] |
a+1 |
*(a+1) |
a[1] |
*a[1] |
*(*(a+1)) |
a[1][0] |
a+2 |
*(a+2) |
a[2] |
*a[2] |
*(*(a+2)) |
a[2][0] |
對於元素a[1][2],其地址用列指針表示爲a[1]+2,等價表示爲*(a+1)+2,那麼內容是*(*(a+1)+2);
列指針 |
行指針 |
等價表示 |
含義 |
a[0] |
&a[0] |
&a或&(a+0) |
第0行 |
a[1] |
&a[1] |
&(a+1) |
第1行 |
a[2] |
&a[2] |
&(a+2) |
第2行 |
示例1:用列指針輸出二維數組。
#include <stdio.h>
void main()
{
int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
int *p= a[0]; // 列指針的定義法
for(; p < a[0] + 12; p++)
{
printf("%d ",*p);
}
return;
}
示例2:用行指針輸出整個二維數組。
#include <stdio.h>
void main()
{
int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
int (*p)[4]= &a[0]; // 行指針定義法或者int (*p)[4]= a;
int i, j;
for(i = 0; i < 3; i++)
for(j = 0; j < 4; j++)
{
printf("%d ",*(*(p + i) + j));
}
return;
}
轉自:http://soft.chinabyte.com/database/339/12423339.shtml
最近在百度知道里面發現不少學習初學者搞不清楚行指針的具體概念,今天在這裏做下詳細的解釋分析。
行指針,顧名思義就是指向一行的指針。那麼哪裏會用到行指針呢,用的最多的,那就是二維指針了,你們都知道,咱們一般把二維指針當作一個行列式,可是它在內存中的排序倒是和一維指針同樣的。
好比組a[2][3]={{1,2,3}{4,5,6}},a是整個數組的首地址,同時也指向第一行元素,即a是一個行指針,它每加1,所指地址移動二維數組的一行,a+1指向第二行元素。
對a取*,即*a指向第一行第一個數,*(a+1)指向第二行第一個數,可見,對行指針取值就成了列指針,此時它仍是個指針。它每加1,所指地址移動一個元素,*(a+1)+1指向第二行第二個元素,也能夠寫成a[1]+1。
**a(也可寫成a[0][0])就是這個二維數組第一行的第一個元素,**(a+1)(也可寫成a[1][0])就是第二行的第一個元素,*(*(a+1)+1)(也可寫成a[1][1])是第二行的第二個元素。可見,對行指針取2次*就成了某個元素的值了,而再也不是地址。
有這樣一個公式a[i][j]=*(*(a+i)+j),應該就知道爲何了吧…
行指針還能夠這樣定義int (*p)[n],此處定義的p指針,每加1,移動n個地址位(針對不一樣二維數組定義不一樣的n值)好比下面的這段:
int main(void)
{
int a[2][3] = {{1,2,3},{4,5,6}};
int (*p)[3];
p = a;
p++;
printf("%d",**p);
}
此段代碼輸出結果爲4,p是個行指針,能夠直接將a這個行指針直接賦值給它,此時p也指向二維數組的起始地址,即第一行。p++就會移動3個元素,從而指向第二行。用法同二維數組名a。
轉自:http://www.cppblog.com/haosola/archive/2013/04/04/199089.html
二維數組使用通常有兩種狀況,一種是描述一個二維的事物。好比用1表示牆,用0表示通路,咱們能夠用二維數組來描述一個迷宮地圖;用1表示有通路,0表示沒有通路,咱們能夠用二維數組來描述幾個城市之間的交通狀況。還有一種是描述多個具備多項屬性的事物。好比有多個學生,每一個學生有語文、數學和英語三門成績,咱們就能夠用二維數組來描述。對二維數組使用過程當中的幾個問題進行探究。
關鍵詞:C++;二維數組;動態分配;參數;指針
C++程序中的new[]和delete[]做爲動態內存分配的重要手段在程序設計中有着普遍應用,尤爲應用在程序員自定義的類與結構的數組聲明上。但因爲C++程序語言中並無給出顯示的數組訪問限制[1],極易形成"數組越界"的錯誤。這種錯誤會引發對非程序數據段的修改,而使得程序崩潰。
1C++中二維數組的動態分配
在C++中動態分配二維數組能夠先申請一維的指針數組,而後該數組中的每一個指針再申請數組,這樣就至關於二維數組了,可是這種方法會致使每行可能不相鄰,從而訪問效率比較低。那麼什麼是真正的二維數組呢?C語言中的二維數組在內存組織形式是按行存儲的連續的內存區域。因此,必須保證數組元素是按行存儲的,並且也是最重要的是內存要連續http://www.wx-jr.com
因此,筆者設計以下的一個方法:
假定二維數組的元素變量類型是MyType;能夠是C語言接受的除void以外的任何類型,由於編譯器不曉得void類型的大小;例如int,float,double等等類型;
introw=2;/////暫假定行數是2,這個能夠在運行時刻決定;
intcolumn=3;/////暫假定列數是2,這個能夠在運行時刻決定;
void**ptdhead=NULL;//////////在後面說明爲何要用void**類型
void**ptdBody=NULL;//////////在後面說明爲何要用void**類型
ptdhead=(void**)malloc(sizeof(void*)*row+sizeof(MyType)*row*column);
if(!ptdhead)
returnFALSE;
ptdBody=ptdhead+row;
for(intncount=0;ncount<row;ncount++)
ptdhead[ncount]=ptdBody+ncount*column*sizeof(MyType)/sizeof(void*);
MyType**ptdheadRealse;
ptdheadRealse=(MyType**)ptdhead;///////////////////強制轉換爲本身程序須要的二維數組元素類型的指針
ptdhead=NULL;
for(inti=0;i<row;i++)
{
for(intj=0;j<column;j++)
{ptdheadRealse[i][j]=i+j;////////進行簡單的初始化;}
}
這樣的一種方法動態分配的二維數組,內存是連續的,是真正意義的C語言二維數組,知足全部二維數組訪問的方法,並且內存利用效率高,程序性能好。
2C++二維數組的傳遞
用二維數組做爲參數傳遞(用二維數組處理矩陣),可是但願接受傳遞二維數組參數的函數能夠處理任意維度的數組(但願矩陣的行數和列數都是不固定的)。但通常傳遞二維數組的基本規則好像是這樣的:能夠用二維數組名做爲實參或者形參,在被調用函數中對形參數組定義時能夠能夠指定全部維數的大小,也能夠省略第一維的大小說明。如http://www.sd-ju.com
voidFunc(intarray[3][10]);voidFunc(intarray[][10]);
兩者都是合法並且等價,可是不能把第二維或者更高維的大小省略,以下面的定義是不合法的:voidFunc(intarray[][]);將二維數組看成參數的時候,必須指明全部維數大小或者省略第一維的,可是不能省略第二維或者更高維的大小,這是由編譯器原理限制的。可是咱們在編寫程序的時候卻須要用到各個維數都不固定的二維數組做爲參數,這就難辦了,編譯器不能識別阿,怎麼辦呢?不要着急,編譯器雖然不能識別,可是咱們徹底能夠不把它看成一個二維數組,而是把它看成一個普通的指針,再另外加上兩個參數指明各個維數,而後咱們爲二維數組手工尋址,這樣就達到了將二維數組做爲函數的參數傳遞的目的,根據這個思想,咱們能夠把維數固定的參數變爲維數隨即的參數。
3C++中二維數組形參的傳遞
voidFunc(intarray[3][10]);voidFunc(intarray[][10]);能夠省略第一維的大小,錯誤的是voidFunc(intarray[][].這樣的用法只能在初始化時能夠用);這樣寫也是錯誤:voidFunc(constintm,constintn,intarray[m][n]);或voidFunc(intm,intn,intarray[m][n]);你們都知道數組的索引必須是個常量表達式,voidFunc(constintm,constintn,intarray[m][n]);若是constintm沒有初始化,那麼系統將m或n自動初始化爲0,因此這樣些是不對的,若是咱們採用這樣voidFunc(int**array,intm,intn)的形式,那麼在實際的函數調用是,咱們就要進行強制轉換才能夠用,咱們能夠這樣調用voidFunc((int**)array,intm,intn);在函數調用時,要把數組形式寫成指針形式如*((int*)array+n*i+j);直接寫intarray[i][j]會致使錯誤,編譯能夠經過,在VC編譯器中執行會出現異常,DEV編譯器會出現一個隨機值,緣由就在於若是寫成intarray[i][j],編譯器沒法正確的尋址,固然各類編譯器對它的處理結果是不同的。若是咱們的形參是數組,那麼咱們在函數體中能夠用指針也能夠用數組形式,可是若是咱們形參數中用的是指針,最好也用指針,有時用數組形式會出錯,二維數組就是這樣http://www.sd-ju.com
4二維數組中的指針問題
1)用指針表示二維數組元素。要用指針處理二維數組,首先要解決從存儲的角度對二維數組的認識問題。咱們知道,一個二維數組在計算機中存儲時,是按照先行後列的順序依次存儲的,當把每一行看做一個總體,即視爲一個大的數組元素時,這個存儲的二維數組也就變成了一個一維數組了。而每一個大數組元素對應二維數組的一行,咱們就稱之爲行數組元素,顯然每一個行數組元素都是一個一維數組。
2)用二維數組名做地址表示數組元素。咱們還能夠獲得二維數組元素的一種表示方法:對於二維數組a,其a[0]數組由a指向,a[1]數組則由a+1指向,a[2]數組由a+2指向,以此類推。所以,*a與a[0]等價、*(a+1)與a[1]等價、*(a+2)與a[2]等價,┅,即對於a[i]數組,由*(a+i)指向。由此,對於數組元素a[i][j],用數組名a的表示形式爲:*(*(a+i)+j)。指向該元素的指針爲:*(a+i)+j。數組名雖然是數組的地址,但它和指向數組的指針變量不徹底相同。指針變量的值能夠改變,即它能夠隨時指向不一樣的數組或同類型變量,而數組名自它定義時起就肯定下來,不能經過賦值的方式使該數組名指向另一個數組。
3)行數組指針。在上面的說明中咱們已經知道,二維數組名是指向行的,它不能對以下說明的指針變量p直接賦值:inta[3][4]={{10,11,12,13},{20,21,22,23},{30,31,32,33}},*p;其緣由就是p與a的對象性質不一樣,或者說兩者不是同一級指針。C語言能夠經過定義行數組指針的方法,使得一個指針變量與二維數組名具備相同的性質。行數組指針的定義方法以下:數據類型(*指針變量名)[二維數組列數];例如,對上述a數組,行數組指針定義以下:int(*p)[4];它表示,數組*p有4個int型元素,分別爲(*p)[0]、(*p)[1]、(*p)[2]、(*p)[3],亦即p指向的是有4個int型元素的一維數組,即p爲行指針此時,可用以下方式對指針p賦值:p=a;
下面說明一下,我碰到的問題,咱們定義了一下以下的函數:voidfunction(double**array,intwidth,intheight)。
而後咱們定義了一個二維數組doublep[3][3]={{1,2,3},{4,5,6},{7,8,9}};
當咱們調用function時,即function(p,3,3),編譯器會報錯:
errorC2664:'function':cannotconvertparameter1from'double[3][3]'to'double**'
參數傳遞其實是一個賦值的過程,爲了便於說明咱們底下都以賦值的方式加以說明。
咱們知道p是數組首地址,地址指向的是第一個行數組,在某種程度上來講能夠把二維數組名理解爲指針的指針,可是這二者是有區別的。
double*p[3]和double(*p)[3]
double*p[3]是一個指針數組,它是一個數組,裏面存放了3個指針;double(*p)[3]它是一個數組指針,它是一個指針,這個指針指向的是一個數組,它和二維數組有相同的性質,具體說明能夠看下分割線中紅色的字體所示的部分,由此咱們能夠知道以下的賦值是可行的:doublep[3][3]={{1,2,3},{4,5,6},{7,8,9}}http://www.wx-jr.com
double(*pp)[3]=p;
這裏實際上的話也是應該執行了一次上面所說的自動轉化,p轉化了一個指向行數組的指針,而後賦值給了數組指針變量pp;另外,咱們發現底下的賦值也是可行的:
double*p[3];
double**pp=p;
這裏實際上也是執行了一次上面所說的轉化,p轉化了一個指向指針變量的指針,而後賦值給了pp;這裏看下,上面兩次轉化後惟一的的區別於一個是指向數組的指針,一個是指向指針的指針,而C++不容許接下來的再次轉化,說明C++只支持數組到指針的一次轉化,而二次轉化沒有支持。
轉自:http://hi.baidu.com/zyaijava/item/eb55d0a3c9574a34030a4da1
指針數組:數組元素全爲指針的數組,(是數組,元素全爲指針)。
一維指針數組, int *ptr[5];
數組指針:數組首元素的指針,(是指針,保存數組首元素的地址)。
int (*ptr)[5];
賦值對比:
數組指針賦值
int a[4][5];
int (*ptr)[5]=a; // a爲二維數組名,至關於二級指針常量,ptr是指向一維數組(大小是5)的指針。
ptr是一個指針變量,它指向包含5個int元素的一維數組,此時ptr的增量以它所指向的一維數組長度爲單位;
*ptr+i是二維數組a[0][i]的地址;
*(ptr+2)+3表示a[2][3]地址(第一行爲0行,第一列爲0列),*(*(p+2)+3)表示a[2][3]的值
ptr = a = &a[0] = &a[0][0];//這些意思是相同的
*ptr = ptr[0] = &a[0][0];//因爲數組的特性:&a, a, &a[0], &a[0][0]都表示數組的首地址
【注意】:*ptr = ptr = ptr[0] = a = &a[0] = &a[0][0] 這裏不是手誤,數組指針中,確實是*ptr = ptr
解釋以下:
相似一維數組int b[5], b = &b = &b[0],一維數組名錶示整個數組的起始地址,跟首地址同樣
數組指針中,*ptr是 int[5]類型的,ptr是int[5]*, int[5]的地址是數組指針的首元素,故*ptr = ptr = ptr[0]
*(ptr+1) = ptr[1] = &a[1][0] = &a[5];
(*ptr)[0] = *(*ptr+0) = ptr[0][0] = a[0][0];
(*ptr)[1] = *(*ptr+1) = ptr[0][1] = a[0][1];
*(ptr+0)+1 = &ptr[0][1];
*(ptr+1)+1 = &ptr[1][1];
指針數組賦值(須要動態分配空間)
char *ptr[5] = {"one", "two", "three", "four","five"};//系統給ptr分配的空間不必定連續,
而且給ptr分配的空間取決於具體字符串的長度。
字符指針數組相比二維字符數組優勢:
一是:指針數組中每一個元素所指的字符串沒必要限制在相同的字符長度;
二是:訪問指針數組中的一個元素是用指針間接進行的,效率比下標方式要高。 可是二維字符數組卻能夠經過下標很方便的修改 某 一元素的值,而指針數組卻沒法這麼作。
指針數組,數組指針對比:
指針數組 是數組元素爲指針的數組,其本質爲數組
數組指針 是指向數組首元素的地址的指針,其本質是指針,(指針存放的是數組首地址的地址,至關於2級指針,這個指針不可移 動)
指針數組,二維數組對比:
二維數組:只要定義了一個二維數組(假設是二維字符數組),不管是否賦值,系統都會給他分配相應的空間,並且該空間必定是連續的, 其中每一個元素表示一個字符,能夠經過指定下標對每一個元素進行訪問和修改。
指針數組:系統分配指定大小的連續空間來存儲元素的地址,每一個元素是一個指向字符型數據的一個指針。
數組指針,二維數組對比在數組指針賦值裏面已經詳細說明了。
指針數組,數組指針,二維數組,二級指針的關係和區別:
二級指針:int **ptr;
指針數組: int *ptr[5];
數組指針: int (*ptr)[5];
二維數組: int ptr[3][5];
指針:本質是可變數組的首地址,這個可變數組,是指包含的內容的數量的可變性,指針另外是可動態申請和釋放的,對內存來講 是利用比較充分。
佔用空間:
int **ptr: sizeof(ptr) = 4
int *ptr[3]: sizeof(ptr) = 12
int (*ptr)[5]: sizeof(ptr) = 4
int ptr[3][5]: sizeof(ptr) = 3*5*4 =60
二級指針:
(1) int **ptr,須要兩次內存分配才能使用其最終內容,首先,ptr = ( int ** )malloc( sizeof(int *) * 3);此時就和
int *ptr[3]意義相同了,而後在對3個指針進行內存分配, ptr[0] = (int*)malloc(sizeof(int) *5);
【注】若是沒有ptr的第一次內存分配,則ptr是個野指針,是沒法使用,使用會出問題
若是沒有ptr[0]其餘元素的第二次內存分配,則ptr[0]等元素是野指針,使用也會出問題.
(2) int *ptr[3],這樣定義,編譯器已經爲ptr分配了3個指針的空間,至關於int **ptr二級指針的第一次內存分配
須要對ptr[0]對元素進行一次內存分配,不然是野指針。
(3) int (*ptr)[5],是一羣指針,每一個指針都是指向5個整數的數組,若是動態分配k個指針內存的話以下:
ptr = (int *)malloc(sizeof(int)*5 *k), ptr此時指向一片連續的空間,
ptr[0]指向下標是0的5個整數數組的首地址.ptr[1]指向下標是1的5個整數數組的首地址.
(4) int ptr[3][5],是二維數組,定義好,編譯器已經爲二維數組分配了3*5個指針的空間,而且是連續的。
能夠以下理解:
int **ptr <==> int ptr[x][y]; //上面第一次分配x=3,y=5
int *ptr[3] <==> int[3][y];//y的長度能夠每一個數組元素不一樣
int (*ptr)[5] <==> int[x][5]; //x的長度每一個元素必須同樣
int ptr[3][5] ;//