C++中的指標和數組

來源:互聯網
上載者:User
 

-------------------------------------------Section 0 前言-------------------------------------------
寫個簡單的yuv讀取的庫,卡在多維陣列動態分配的問題上。唉,還是C基本功不紮實,於是花了一下午時間,算是給自己有了點交代。參考《C專家編程》。水平有限,歡迎看客指正。


-------------------------------------------Section 1 左值與右值-------------------------------------
編譯器為每個變數分配一個地址(左值),該地址在編譯時間可知,且變數在運行時一直存於該地址。存於該地址的變數的值(右值)只有在運行時可知。因此,編譯器如果需要一個地址來執行某種操作,它可以直接進行操作,如果需要一個變數的值,它需要發出指令從指定地址中讀入變數值並存於寄存器中。到這裡,可以理解作為一個指標變數,它本身的地址是左值,它變數的值(即指向的地址值)為右值。所以指標首先需要在運行時取得它的當前值,然後才能對它進行解除引用操作。

數組名是一個左值,即記憶體中的位置。但數組名是一個不可修改的左值,即不可被賦值。
           int main()
           {
            int a[3] = {0};
            int b    = 1;
            a = &b; //ERROR: “=” : 左運算元必須為 l 值。
            return 0;
           }

-----------------------------------------Section 2 數組與指標的不同---------------------------------
一個例子:
           int main()
           {
            char arr[4] = "abc";                       // Note 1
            //char arr[4] = {'a', 'b', 'c', '\0'};         // Note 2
            char *ptr   = "ABC";                       // Note 3

            //ptr+1 = &arr[2];                           // Note 4

            printf("arr: %x, %x, %x %x \n", &arr, &arr[0], &arr[1]);   //Note 5
            printf("ptr: %x, %x, %x %x \n", &ptr, &ptr[0], &ptr[1]);
            return 0;
           }
Note 1&2等價定義,其結構如下:
            a    b    c    \0
           [__] [__] [__] [__]
          12fed4 +1   +2   +3

Note 3結構如下
          42703c      A    B    C    \0
           [__]      [__] [__] [__] [__]
          12fec8    42703c +1   +2   +3

Note 4複習一下Section 1。顯然的錯誤,因為p+1首先需要知道p的值(右值),只有在運行時刻才能得到,編譯時間刻就希望對其所在的地址進行賦值顯然錯誤。

Note 5驗證Note1和3,運行結果如下:
           arr: 12fed4, 12fed4, 12fed5
           ptr: 12fec8, 42703c, 42703d
可以發現,arr的地址(左值)的結果與數組中首元素的地址一致,而ptr的變數值(右值)與數組的首元素地址一致。

因此對一個數組中的元素進行引用,c=arr[i]和c=ptr[i]都能夠取出相應數組中的第i個元素。但要注意這兩個操作的過程完全不同:
                         c = arr[i];                         c = ptr[i];
                                                      1:取地址12fec8的內容,即42703c
                   1 取出i的值與12fed4相加            2:取出i的值與42703c相加
                   2 取地址(12fed4+ i)的內容          3:取地址(42703c+i)的內容
                  
得到結論:儘管c=arr[i]和c=ptr[i]用同樣的形式完成了同樣的功能,但絕不可以混用。注意數組原始的聲明方式,如果原始聲明為數組式的,那麼對其元素的引用要使用數組形式,反之亦然。
檔案1中:
    int array[100];
檔案2中:
    extern int *array;
    array[50] = 3;  //知道這句為什麼錯了吧?

-----------------------------------------Section 3 數組與指標的相同----------------------------------
傳說有三種情況下,數組名會被當作指標。

1 “運算式中的數組名”就是指標
            int a[10], *p, i;
            p = a;  //here

2 數組下標就是指標的位移量
以下語句功能一致,但需注意實現的過程不一樣(Section 2):
            a[i] = 0;
            p[i] = 0;
            *(p+i) = 0;

3 函數形參中的數組名被當作指向第一個元素的指標
以下三種函式宣告的形式是等同的:
            my_function(int *p) {...}
            my_function(int p[]) {...}
            my_function(int p[100]) {...}
對my_function函數的調用,無論實參是數組還是指標,都是合法的。

----------------------------------------------Section 4 多維陣列-------------------------------------
首先理解一個簡單的多維陣列:
           int main()
           {
            int apricot[2][3][5];
            int (*p)[3][5] = apricot;  // 別忘記“運算式中的數組名”就是指標
            int (*r)[5]    = apricot[1];
            int *t         = apricot[1][2];
            int u          = apricot[1][2][3];
            return 0;
           }
根據數組下標規則不難理解,apricot[i][j][k]將被編譯器解析為(*(*(apricot+i)+j)+k)。而且多維陣列在記憶體中的布局是線性形式的,所以可以得到apricot[i][j][k]可以通過計算*(&apricot + i*3*5 + j*5 + k)得到。

另一種實現方法是使用指標數組或指標的指標。這種方式的特點是靈活,並且可以實現動態分配多維陣列。
           char *pea[4];
           char **pea;
仍然可以通過pea[i][j]來引用其中的變數以及上述的記憶體位置計算方法(注意是否滿足連續線性記憶體布局)。但這時需要注意的是對這種變數的初始化工作有一點技巧性,因為需要保證指標在後續的使用過程中都是合法的。常用方法是迴圈malloc
           for(j = 0; j < 4; j++)
            pea[j] = malloc[6];
或一次性malloc一整塊資料,然後用迴圈將指標指向各個地區:
           malloc(row * column * sizeof(char));

最後來兩個我的yuvlib裡的子程式,看懂了指標就過關了。
            ************************************************************************
            * \brief
            *    Allocate 2D memory array -> unsigned char array2D[rows][columns]
            *
            * \par Output:
            *    memory size in bytes
            ************************************************************************/
           int get_mem2D(byte ***array2D, int rows, int columns)
           {
            int i;
          
            if((*array2D      = (byte**)malloc(rows*sizeof(byte*))) == NULL)
             exit(2);
            if(((*array2D)[0] = (byte* )malloc(columns*rows*sizeof(byte ))) == NULL)
             exit(2);
          
            for(i=1;i<rows;i++)
             (*array2D)[i] = (*array2D)[i-1] + columns ;
          
            return rows*columns;
           }
          
           /*!
            ************************************************************************
            * \brief
            *    free 2D memory array
            *    which was alocated with get_mem2D()
            ************************************************************************
            */
           void free_mem2D(byte **array2D)
           {
             if (array2D)
             {
               if (array2D[0])
                 free (array2D[0]);
               else exit(6);
          
               free (array2D);
             } else
             {
               exit(6);
             }
           }

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.