C++中的指針和數組

 

-------------------------------------------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);
             }
           }

發佈了20 篇原創文章 · 獲贊 20 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章