二維數組和二級指針


對於如下程序

void fun(int **data,int row,int column)
{
    for(int i = 0;i < row; ++ i)
    {
        for(int j = 0;j < column;++ j)
            cout << data[i][j] << "\t";
        cout << endl;
    }
}
int main()
{
    int data[2][3] = {{3,8,4},{4,5,6}};
    fun(data,2,3);
    return 0;
}

編譯無法通過,提示“no known conversion from 'float [2][3]' to 'float **' for 1st argument”
如果在main函數中將data強制轉換成二級指針,編譯能通過,運行時發生段錯誤。
究其根本,是因為二維數組名,並不是一個二級指針。

二維數組

二維數組內存分配

一維數組名,數組首元素的地址,是一個指針。
二維數組是”數組的數組“,因而我們很容易產生二維數組名是一個二級指針的錯覺,實際上並不是這樣的。
屏幕快照 2016-09-04 下午5.29.19
如上圖所示,實際上,不管是一維還是多維數組,都是內存中一塊線性連續空間,因此在內存級別上,其實都只是一維。但是不同的定義使得表現形式不一樣,從而有多維數組的概念。

訪問數組元素其實非常簡單,原因就在於元素在內存中的線性排列,這樣對一維數組的訪問只需要arr1[index] = *(arr1+index*sizeof(T));對二維數組的訪問
arr2[i][j]=*(arr2+(i*col+j)*sizeof(T)),因此連續線性的數組訪問效率很高。多維類似。

二維數組與數組指針

對於二維數組int data[2][3],可看做特殊的一維數組data[2],包含兩個元素,每個元素的類型是int [3]。
無論如何,數組名總是代表數組首元素的地址,因此,二維數組名是一個數組指針,而非二級指針

那么到底什么是數組指針呢?

數組指針是一個指針,指向一個數組,數組指針的定義有如下形式

int data[2][3]
int (*ptr)[3]
ptr = data;//ptr指向data的第0行
ptr = &data[1];//ptr指向data的第1行

數組指針的聲明中,方括號中的維數指明了對應的指針變量偏移一個單位對應的內存偏移量。(如ptr + 1,ptr會向高地址移動3*4Byte)

上述聲明中,圓括號不能省略,因為[]具有更高的有銜接,int *var[3]聲明的是一個元素為int *的數組(指針數組)。

實際上,可用typedef 使得定義更簡單易懂

 typedef int int_array[3];
 int_array *ptr = data;

因此,文章開頭的程序中fun函數的定義改成如下形式才能夠將二維數組data做為實參傳入
void fun(int (*data)[3],int row,int column)void fun(int data[][3],int row,int column)

為什么不能將二維數組名強制轉換成二級指針

void fun(int **data,int row,int column)
{
    for(int i = 0;i < row; ++ i)
    {
        for(int j = 0;j < column;++ j)
            cout << data[i][j] << "\t";
        cout << endl;
    }
}
int main()
{
    int data[2][3] = {{3,8,4},{4,5,6}};
    int** ptr = (int **)data;
    printf("%p,%p\n",ptr,data);
    printf("%p\n",ptr[0]);
    return 0;
}

運行輸出如下結果
屏幕快照 2016-09-04 下午8.03.26
ptr和data本質上都是指針,在賦值后,他們指向了同一片內存空間,如下圖所示(每個數字為16進制中的一位,包含4bit,所使用測試機器為64位機器)
屏幕快照 2016-09-04 下午8.17.50
64位機器中,int占4個字節,int *占8個字節,因此ptr[0]就是data[0][0]和data[0][1]拼接起來的結果,故ptr[0]的值為0x800000003。可以看到,這個值並非data數組首元素的地址。因此當進行如下調用fun(ptr,2,3)時,試圖訪問的是0x800000003的未知空間,因此發生段錯誤。

二級指針和指針數組

對於如下程序

    int *ptr_arr[2];
    for(int i = 0;i < 2;++ i)
    {
        ptr_arr[i] = new int [3];
        for(int j = 0;j < 3;++ j)
            ptr_arr[i][j] = i + j;
    }
    fun(ptr_arr,2,3);

ptr_arr是一個元素為int *變量的數組(注意和數組指針聲明的區別),是一個指針數組。

無論如何,數組名總是代表數組中首元素的地址。因此ptr_arr實際上是&ptr_arr[0],ptr_arr[0]是一個int *變量,因此,ptr_arr是指針的指針,也就是二級指針,這也是能夠在fun函數中傳入ptr_arr的原因。
也就是說,指針數組的數組名等價於一個二級指針


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM