指針和數組
在本系列的第一篇文章中,我們談了一些有關的指針 。 在第二,我們談論的引用 。 今天我們討論的親密關係(牛耳!)在指針和數組(或數組)。
回顧陣列
一個數組,或矩陣,或安排,是一種數學抽象用來表示一組數據均勻,即同一類型(整型,浮點型,等等)。 這個抽象的組織表格式,行和列。 在矩陣中每個元素都有其獨特的坐標(行和列),這樣一個給定的元素e(i和j)是唯一的元素在“我行','j列”。
聲明數組的語法如下:
/ /一維數組或向量 10 ] ; // 10 elementos, do 0 ao 9 Ivet 詮釋 [10] / / 10的元素,從0-9 23 ] ; // 23 elementos, do 0 ao 22 Cvet 燒焦 [23] / / 23的元素,從0-22 / /二維數組 2 ] [ 3 ] ; // 2 linhas (0 a 1) e 3 colunas (0 a 2)海事研究院詮釋 [2] [3] / / 2線(0-1)和三列(0-2) 10 ] [ 2 ] ; // 10 linhas (0 a 9) e 2 colunas (0 a 1) DMAT 雙 [10] [2] / / 10線(0-9)和2列(0-1)
每個數組元素是獨立於他人,可訪問如下語法:
10 ] ; int imat [ 3 ] [ 4 ] ; // Alterando o quarto elemento do vetor ivet. // Lembre-se que começa-se a contar a partir do elemento zero ivet [ 3 ] = 13 ; // Lendo o segundo elemento do vetor ivet int num = ivet [ 1 ] ; // Alterando o elemento da primeira linha, segunda coluna de imat imat [ 0 ] [ 1 ] = 42 ; // Lendo o elemento na terceira linha, quarta coluna de imat int foo = imat [ 2 ] [ 3 ] ; Ivet 詮釋 [10];海事研究院詮釋 [3] [4] / /改變第四個元素的向量Ivet。/ /請記住,你開始計數從零元 Ivet [3] = 13 / /讀第二個元素的向量Ivet Ivet 詮釋數量= [1] / /改變元素的第一行,第二列海事研究院海事研究院[0] [1] = 42 / /讀的元素排在第三,第四欄海事研究院海事研究院詮釋富= [2] [3];
在這個後,我們將不討論矩陣的背景,我們只探討數組和指針之間的關係在一個相當直觀的。
大小的數組
由於數組是一個抽象的,它包含多個值相同的類型,它是多大? 佔用多少空間,它在內存?
考慮下面的代碼:
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 10 ] ; Ivet 詮釋 [10]; 13 ] ; Cvet 字元 [13]; 20 ] ; dvet 雙 [20]; 3 ] [ 4 ] ; CMAT 字符 [3] [4]; 5 ] [ 4 ] ;海事研究院詮釋 [5] [4]; "sizeof(int) = " << sizeof ( int ) << endl ; 法院 “”“表示sizeof(int)=”<< 表示sizeof(int)<< 恩德; "sizeof(char) = " << sizeof ( char ) << endl ; 法院 “”“大小 (字符 )=”<<大小 (char)的 <<恩德; "sizeof(double) = " << sizeof ( double ) << endl ; 法院 “”“大小 (雙 )=”<<大小 (雙)<< 恩德; "sizeof(ivet) = " << sizeof ( ivet ) << endl ; 法院 “”“大小(Ivet)=”<< 大小 (Ivet)<<恩德; "sizeof(cvet) = " << sizeof ( cvet ) << endl ; 法院 “”“大小(Cvet)=”<< 大小 (Cvet)<<恩德; "sizeof(dvet) = " << sizeof ( dvet ) << endl ; 法院 “”“大小(dvet)=”<< 大小 (dvet)<<恩德; "sizeof(cmat) = " << sizeof ( cmat ) << endl ; 法院 “”“大小(CMAT)=”<< 大小 (CMAT)<<恩德; "sizeof(imat) = " << sizeof ( imat ) << endl ; 法院 “”“大小 (研究院 )=”<<大小 (研究院 )<<恩德; |
其結果是相當合理的。 所佔用的空間相當於一個矩陣的元素的數量乘以大小的類型元素(行x列x大小(型))。 然而,如果每個元素是獨立的,它是假定每個單獨的地方佔有內存,否則一會覆蓋另一個元素。 那麼,每個元素都有它自己的內存地址?
數組和內存地址
為方便起見,我們將分析可能的地址的字符數組,其大小是只給一個字節:
15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 5 ; 例如:const int最大值= 5; max ] = { 'A' , 'B' , 'C' , 'D' , 'E' } ; Cvet 燒焦 [最大值] =('甲',' 乙'的'C','D'類, 用'E'); / /顯示的內容,數據值和地址。 "Índice \t Valor \t Endereço do elemento \n " ) ; 輸出 (“指數 \噸價值\噸元地址\ n”); int i = 0 ; i < max ; i ++ ) { 為(int i = 0;我<最大;我+ +)( "%d \t %c \t %p \n " , i, cvet [ i ] , & cvet [ i ] ) ; 輸出 (“%d個 \ t%的 ç \噸%p \ N”的,我Cvet [我],&Cvet [我]); ) / /顯示數組的地址 "Endereço da matriz: %p \n " , & cvet ) ; 輸出 (“地址的數組:%p \ ñ”,&Cvet); / /顯示數組的地址再次 "Endereço da matriz: %p \n " , cvet ) ; 輸出 (“地址的數組:%p \ N”的,Cvet); |
的地址元素是連續的,也就是說,每個元素存儲旁邊前者。 此外,還有兩個更有趣的事實:
- 該數組的地址(&Cvet),顯示 25行,是相同的第一個元素的數組;
- 非常變量 Cvet可以理解為一個指針,如下所示一致28;
在C + +中,數組是一個共同的連續塊的內存,其名稱可以被解釋(投)作為指針指向它的第一個元素。 此外,它是有效的,使指針指向一個指針數組,其中的目標是相同的類型,類型的數組元素。 在atrubuição數組的一個指針,編譯器使得一個隱式類型轉換。 目標指針,是被解釋為一個指針到內存佔用面積由數組。
一個不那麼明顯的後果是,在隱式轉換是丟失的信息,該地區是一個存儲陣列。 因此丟失信息的大小的數組。 從觀點的指針,它指向的開始,一個任意的內存塊,大小過於武斷。 退出並進入一個數組指針從一個抽象的概念,就失去了更嚴格和更高層的抽象較少限制和較低水平。
另一方面嘗試分配一個指針數組生成一個編譯錯誤不兼容的類型。 數組是一個內存塊的n個數據(字節),因為只有一個給定的指針,一個地址。 編譯器無法預先知道是否一個指針指向一個面積為 1,2或200個字節。
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 300 ; 例如:const int最大值= 300; max ] ; Cvet 燒焦 [最大]; pc = 0 ; 焦炭 *電腦= 0; " \n Antes da atribuição \n " ) ; 輸出 (“\ N先於轉讓的\ ñ”); "cvet = %p \n " , cvet ) ; 輸出 (“Cvet =%p \ N”的,Cvet); "pc = %p \n " , pc ) ; 輸出 (“個人電腦 =%p \ N”的, 電腦); "sizeof(cvet) = %lu \n " , sizeof ( cvet ) ) ; 輸出 (“大小 (Cvet)=%陸\ N”的, 大小 (Cvet)); "sizeof(pc) = %lu \n " , sizeof ( pc ) ) ; 輸出 (“大小 (件)=%陸\ N”的, 大小 (件)); 電腦= Cvet; " \n Depois da atribuição \n " ) ; 輸出 (“\ ñ後轉讓\ ñ”); "cvet = %p \n " , cvet ) ; 輸出 (“Cvet =%p \ N”的,Cvet); "pc = %p \n " , pc ) ; 輸出 (“個人電腦 =%p \ N”的, 電腦); "sizeof(cvet) = %lu \n " , sizeof ( cvet ) ) ; 輸出 (“大小 (Cvet)=%陸\ N”的, 大小 (Cvet)); "sizeof(pc) = %lu \n " , sizeof ( pc ) ) ; 輸出 (“大小 (件)=%陸\ N”的, 大小 (件)); |
請注意,在轉讓(行25) 個人電腦的指針。 是空的,因為它是啟動的。 已經表明,大小300字節的數組和指針只有8(我的機器是AMD 64)。 轉讓後均通過“點”到同一地區的內存,但不改變大小。 有一個隱含的轉換為char [300]為char *和指針在那場比賽的個人電腦無法知道大小的內存區域它所指向。 但是,數組Cvet仍然清楚知道他是沒有生存危機。
指針算術 - Vulgo,那又怎樣?
為什麼,如果我知道數據在數組並排排列,我可以使用一個指針,將跳轉到下一個地址和訪問的下一個元素。 這個名字本是算術指針。
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | 6 ; 例如:const int最大值= 6; max ] = { 'B' , 'L' , 'A' , 'B' , 'O' , 'S' } ; Cvet 燒焦 [最大值] =('乙',『L',' 甲','乙','澳','S'的); pc = cvet ; 焦炭 *電腦= Cvet; int i = 0 ; i < max ; i ++ ) { 為(int i = 0;我<最大;我+ +)( "%c" , * ( pc + i ) ) ; 輸出 (“%c”的,*( 電腦 + i)段); ) " \n " ) ; 輸出 (“\ ñ”); int i = 0 ; i < max ; i ++ ) { 為(int i = 0;我<最大;我+ +)( "%c" , * pc ++ ) ; 輸出 (“%c”的,*電腦+ +); ) " \n " ) ; 輸出 (“\ ñ”); / /現在的整數 max ] = { 1 , 2 , 3 , 4 , 5 , 6 } ; Ivet 詮釋 [最大值] =(1,2,3,4,5,6); pi = ivet ; 詮釋 *圓周率= Ivet; int i = 0 ; i < max ; i ++ ) { 為(int i = 0;我<最大;我+ +)( "%p = %d \n " , pi, * pi ++ ) ; 輸出 (“%P值%d行\ n”,圓周率*圓周率+ +); ) " \n " ) ; 輸出 (“\ ñ”); / /在兩個維度 2 ] [ 3 ] = { { 'B' , 'L' , 'A' } , { 'B' , 'O' , 'S' } } ; CMAT 燒焦 [2] [3] =(('乙',『L','一'),('乙',' 澳','S'的)); ppc ; 焦炭 * 每次點擊付費; char * ) cmat ;每次點擊付費=(char *)的 CMAT; int i = 0 ; i < 2 ; i ++ ) { 為(int i = 0;我<2;我+ +)( int j = 0 ; j < 3 ; j ++ ) { 為(int J = 0時,強 <3 j + +)( "%c" , * ( ppc + 3 * i + j ) ) ; 輸出 (“%c”的,*(3 *我的PPC + + j)段); ) " \n " ) ; 輸出 (“\ ñ”); ) " \n " ) ; 輸出 (“\ ñ”); |
在第18行的指針正指向電腦數組Cvet,因此它的第一個元素,字符'乙'。 在第21行的內容,個人電腦,這是它的地址中存儲的字符'乙',即增加然後去引用。 在第一遍我的價值是零,因此它的價值是間接引用的'乙'。 在下面的步驟,下面的地址已經被解除引用其他字符存儲在原始數組。 這是或多或少什麼編譯器內部當您使用語法 Cvet [我]。 抽象的數組為您提供了更加友好的方式處理與相鄰地區的內存*(電腦+我)。
但如果是簡單抽象的數組比使用指針算術?
一個答案是26行。 她做同樣的事情作為第21行,但快一點。 在語法的第21行,或類似,數組語法,訪問任何給定的數據大致可以概括為良好,命令:
- 以數組的基地址;
- 添加到地址的值的索引;
- 德引用新的地址;
已經與指針算術看起來像這樣:
- 德參照此地址;
該命令增量(或帳戶作出的地址)不會告訴,因為它是循環的一部分,雖然我+ +;快於1 = B + C的;。 現在想像這個小增益的66%應用於數據區域為 1 MB。 將有超過 200萬的命令少!
該技術使用一個指針來處理一個任意區域的內存通常是用在低層次的編程(接近機),操縱緩衝區和字符串,除其他骯髒的伎倆。 在腸子的電腦,掃描操作,大面積的記憶,往往表現的指針算術。 在這一層次, 達爾文至高無上,只有最準備才能生存下來。 從這裡開始的語言賦予的權力,只有純潔的心可以理解。
一個重要的注意的是,31和38線之間的經驗是多次與整數。 請注意,由於整數是4字節,自動遞增了4 4個字節,而不是1對 1,即增量自動計算表示sizeof(類型)。 遞增一個指針指到下一個地區訪問的內存類似實際數據,而不僅僅是下一個地址。 隨著規模的一個 char是一個字節,當 incremetamos一個指針為 char,只移動一個字節。 如果你增加一個指針雙,我們會提出8個字節,等等。
另一種看法是,一個二維數組可以是“線性”行40-52所示。 這是有用的,在適用情況下,為了更好地利用處理器緩存,例如。
*無效的pansexual指針
剛才我說,這是唯一可能分配一個數組的指針,這對於同一類型的數組數據。 我公然說謊! 原因是,有人誰辭職後這個話題之前,它是安全,他不能相信
!
有兩個例外的規則。 第一是當有一個明確的目標和指針類型轉換“認為”它指向正確的一種。 一個例子是第44行的前面的代碼。
二是案件指針無效。 一個無效的指針是一個指針,並沒有要求的類型的數據是在該地區,它的記憶點。 他是一個指針到一個通用的內存區,這是非常低的水平。
若要使用數據指針所指向作廢之前去引用它,我們必須作出明確的強制轉換為一個有效的類型,因為如果一個 int *是去參照一個 int和char *是去參照煤焦,猜測它是什麼去引用一個 void *?
15 16 17 18 19 20 21 22 23 24 25 26 27 | 6 ; 例如:const int最大值= 6; max ] = { 'B' , 'L' , 'A' , 'B' , 'O' , 'S' } ; Cvet 燒焦 [最大值] =('乙',『L',' 甲','乙','澳','S'的); pv = cvet ; *光伏= Cvet 無效 ; / /編譯錯誤。 / / *光伏 / /是多少大小(無效)? int i = 0 ; i < max ; i ++ ) { 為(int i = 0;我<最大;我+ +)( "%c" , * ( ( ( char * ) pv ) + i ) ) ; 輸出 (“%c”的 ,*(((char *)的光伏)+ i)段); ) " \n " ) ; 輸出 (“\ ñ”); |
無效的指針時使用一需要指向一個一般區域的存儲器,而無需有控制/ knowledge的type this方面的數據包含或functions不能製造的假設 about的類型及其參數,如在空氣污染指數lib中pthreads的 (聯繫任意)。
閉幕
我們越是深入研究的課題上的指針,我們更接近機器。 大部分的功率C和C + +由此獲得的,和很多的問題了。 越來越多的複雜性和風險太大。 對於許多潛藏的樂趣!
鏈接
- arrays.zip (所有來源的職位);
- 指針的cplusplus.com
- 指針在blabos.org
- 參照blabos.org
- 有罪


