您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關c++中數組與指針是什么,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
1.數組
數組大小(元素個數)一般在編譯時決定,也有少部分編譯器可以運行時動態決定數組大小,比如icpc(Intel C++編譯器)。
1.1數組名的意義
數組名的本質是一個文字常量,代表數組第一個元素的地址和數組的首地址。數組名本身不是一個變量,不可以尋址,且不允許為數組名賦值。假設定義數組:
int A[10];
那么再定義一個引用:
int* &r=A;
這是錯誤的寫法,因為變量A是一個文字常量,不可尋址。如果要建立數組A的引用,應該這樣定義:
int* const &r=A;
此時,現在數據區開辟一個無名臨時變量,將數組A代表的地址常量拷貝到該變量中,再將常引用r與此變量進行綁定。此外,定義一個數組A,則A、&A[0]、A+0是等價的。
在sizeof()運算中,數組名代表的是全體數組元素,而不是某個單個元素。例如,定義int A[5],生成Win32的程序,sizeof(A)就等于5*sizeof(int)=5*4=20。示例程序如下。
#include <iostream> using namespace std; int main() { int A[4]={1,2,3,4}; int B[4]={5,6,7,8}; int (&rA)[4]=A; //建立數組A的引用 cout<<"A:"<<A<<endl; cout<<"&A:"<<&A<<endl; cout<<"A+1:"<<A+1<<endl; cout<<"&A+1:"<<&A+1<<endl; cout<<"B:"<<B<<endl; cout<<"rA:"<<rA<<endl; cout<<"&rA:"<<&rA<<endl; }
運行結果:
A:0013F76C
&A:0013F76C
A+1:0013F770
&A+1:0013F77C
B:0013F754
rA:0013F76C
&rA:0013F76C
閱讀以上程序,注意如下幾點。
(1)A與&A的結果在數值上是一樣的,但是A與&A的數據類型卻不同。A的類型是int[4],&A的類型則是int(*)[4]。它們在概念上是不一樣的,這就直接導致A+1與&A+1的結果完全不一樣。
(2)為變量建立引用的語法格式是type& ref,因為數組A的類型是int[4],因此為A建立引用的是int (&rA)[4]=A;
1.2數組的初始化
定義數組的時候,為數組元素賦初值,叫作數組的初始化。可以為一維數組指定初值,也可以為多維數組指定初值。例如。
Int A[5]={}; //定義長度為5的數組,所有數組元素的值都為0 int A[]={1,2,3}; //定義長度為3的數組,數組元素分別為1,2,3 int A[5]={1,2}; //定義長度為5的數組,A[0],A[1]分別為1,2,其他值均為0 int A[][2]={{1,2},{3,4},{5,6}}; //定義一個類型為int[3][2]的二維數組 int A[][2]={{1},{1},{1}}; //定義一個類型為int[3][2]的二維數組,A[0][0]、A[1][0]、A[2][0]三個元素的值為1,其他元素的值均為0 //以下是幾種錯誤的初始化方法 int A[3]={1,2,3,4}; //初始化項的個數超過數組的長度 int A[3]={1,,3}; //不允許中間跳過某項
2.指針
2.1指針的定義
指針是用來存放地址值的變量,相應的數據類型成為指針類型。在32位平臺上,任何指針類型所占用的空間都是都是4字節。比如sizeof(int*)、sizeof(double*)、sizeof(float*)等的值都為4。
2.2定義指針的形式
定義指針的形式是:type* p,其中type是指針所指向對象的數據類型,而*則是指針的標志,p是指針變量的名字。由于C++中允許定義復合數據類型,因此指向復合數據類型對象的指針的定義方式可能較為復雜。理解指針,關鍵是理解指針的類型和指針所指向數據的類型。例如:
int (*p)[5]; //指針p的類型是int(*)[5],指針所指向的數據類型是int[5] int* p[5]; //p是有5個分量的指針數組,每個分量的類型都是int*(指向int的指針) int** p; //指針p的類型是int**,p指向的類型是int*,p是指向指針的指針
2.3指針的初始化
定義指針變量之后,指針變量的值一般是隨機值,這樣的值不是合法訪問的地址。指針變量值的合法化途徑通常有兩個,
一是顯示置空,二是讓指針指向一個已經存在的變量,三是為指針動態申請內存空間。如下:
//顯示置空 int *p=NULL; //將指針指向某個變量 int i; int *p=&i; //動態申請內存空間 int* p=new int[10];
2.4指針可以參與的運算
由于指針是一個變量,所以指針可以參與一些運算。假設定義指針int* p,指針p能夠參與的運算有:
(1)解引用運算,即獲取指針所指的內存地址處的數據,表達式為*p,如果指針指向的是一個結構或者類的對象,那么訪問對象成員有兩種方式:(*p).mem或p->mem。
(2)取地址運算,即獲取指針變量的地址,表達式為&p,其數據類型為int**;
(3)指針與整數相加減。表達式p+i(或者p-i),實際上是讓指針遞增或遞減地移動i個int型變量的距離。
(4)兩個指針相減,如p-q,其結果是兩個指針所存儲的地址之間的int型數據的個數。
2.5注意指針的有效性
使用指針的關鍵就是讓指針變量指向一個它可以合法訪問的內存地址,如果不知道它指向何處,請置為空指針NULL或者((void*)0)。
在某些情況下,指針的值開始是合法的,以后隨著某些操作的進行,它變成了非法的值。考察如下程序。
#include <iostream> using namespace std; int* pPointer; void SomeFunction() { int nNumber=25; pPointer=&nNumber; //將指針pPointer指向nNumber } void UseStack() { int arr[100]={}; } int main() { SomeFunction(); UseStack(); cout<<"value of *pPointer:"<<*pPointer<<endl; }
輸出結果是0,并非想象中的25。原因是函數SomeFunction()運行結束之后,局部變量nNumber已經被清空,其占有的空間在離開函數后歸還給系統,之后又分配給函數UseStack()中的局部變量arr。因此指針pNumber的解引用后的值變成了0。所以,要想正確的使用指針,必須保證指針所指向單元的有效性。
3.數組與指針的關系
數組名代表數組的首地址,而數組A的某個元素A[i]可以解釋成*(A+i),所以數組名本身可以理解為一個指針(地址),一個指針常量。所以,在很多情況下,數組與指針的用法是相同的,但是數組與指針本質上存在一些重要的區別。
(1)數組空間是靜態分配的,編譯時決定大小。而指針在定義時,可以沒有合法訪問的地址空間,也就是野指針。
(2)數組名代表一個指針常量,企圖改變數組名所代表的地址的操作都是非法的。例如如下代碼:
int arr[5]={0,1,2,3,4}; arr++; //編譯錯誤
(3)函數形參中的數組被解釋為指針。考察如下程序:
void show0(int A[]) { A++; cout<<A[0]<<endl; } void show1(int A[5]) { A++; cout<<A[0]<<endl; } int main() { int d[5]={1,2,3,4,5}; show0(d); show1(d); }
以上程序編譯通過并輸出2和2。程序中形參數組A可以進行自增運算,改變了自身的值,這個說明了形參數組A被當作指針看待。之所以這樣處理,原因有兩個,一是C++語言不對數組的下標作越界檢查,因此可以忽略形參數組的長度;二是數組作整體進行傳遞時,會有較大的運行時開銷,為了提高程序運行效率,將數組退化成了指針。
(4)如果函數的形參是數組的引用,那么數組的長度將被作為類型的一部分。實際上,對數組建立引用,就是對數組的首地址建立一個常引用。由于引用是C++引入的新機制,所以在處理引用時使用了一些與傳統C語言不同的規范。在傳統的C語言中,對數組的下標是不做越界檢查,因此在函數的參數說明中,int[5]和int[6]都被理解為int[](也就是int*),C++語言也沿用了這種處理方式。但是,int(&)[5]與int(&)[6]被認為是不同的數據類型,在實參與形參的匹配過程作嚴格檢查。考察如下程序。
#include <iostream> using namespace std; void show(int(&A)[5]) { cout<<"type is int(&)[5]"<<endl; } void show(int(&A)[6]) { cout<<"type is int(&)[5]"<<endl; } int main() { int d[5]={1,2,3,4,5}; show(d); }
程序結果:
type is int(&)[5]
(5)在概念上,指針同一維數組相對應。多維數組是存儲在連續的存儲空間,而將多維數組當做一維數據看待時,可以有不同的分解方式。考察如下程序。
#include <iostream> using namespace std; void show1(int A[],int n) { for(int i=0;i<n;++i) cout<<A[i]<<" "; } void show2(int A[][5],int n) { for(int i=0;i<n;++i) show1(A[i],5); } void show3(int A[][4][5],int n) { for(int i=0;i<n;++i) show2(A[i],4); } int main() { int d[3][4][5]; int i,j,k,m=0; for(int i=0;i<3;++i) for(int j=0;j<4;++j) for(int k=0;k<5;++k) d[i][j][k]=m++; show1((int*)d,3*4*5); cout<<endl; show2((int(*)[5])d,3*4); cout<<endl; show3(d,3); }
程序運行結果可以看出,以下三條輸出語句的數據結果是相同的。
show1((int *)d,3*4*5); show2((int(*)[5])d,3*4); show3(d,3);
它們的輸出結果完全一樣,即從0到59。這說明把3維數組d當作一維數組看待,至少可以有以下3中不同的分解方式:
a.數據類型為int,元素個數為3*4*5=60;
b.數據類型為int[5],元素個數為3*4=12;
c.數據類型為int[4][5],元素個數為3。
所以,可以將多維數組看做“數組的數組”。在將多為數組轉換為指針的時候,一定要注意多為數組的分解方式,以便進行正確的類型轉換。
(6)字符數組與字符指針的區別。
字符數組字符指針在形式上很接近,但在內存空間的分配和使用上還是有重大的差別。如前所述,數組名并不是一個運行實體,它本身不能被尋址。而指針是一個變量(運行時實體),可以被尋址,它所指向的空間是否合法要在運行時決定。錯誤地使用指針將導致對內存空間的非法訪問。考察如下程序。
#include <iostream> using namespace std; int main() { char s[]="abc"; //s是字符數組,空間分配在棧上。對字符數組元素的修改是合法的 char *p="abc"; s[0]='x'; cout<<s<<endl; //p[0]='x'; //此句編譯出錯,指針指向常量區的字符串,對字符串常量的修改是非法的 cout<<p<<endl; }
程序輸出結果:
xbc
abc
關于c++中數組與指針是什么就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。