簡體   English   中英

C將2D數組的地址分配給指針

[英]C assigning the address of a 2D array to a pointer

我正在閱讀一些講義,為了使指針引用2D數組,必須給出第一個元素的地址。

int a[10][10];
int *p = &a[0][0];

我從來沒有嘗試過這個,所以我很好奇為什么不足以將數組本身分配給指針,就像在1D情況下那樣。

int a[10][10];
int *p = a;

無論如何,數組都保存在不間斷的“內存”行中,而2D數組只有不同的類型,但結構與1D數組相同。

通過做這個

int *p = &a[0][0];

我沒有看到我們如何給指針提供更多信息而不是這樣做

int *p = a;

或者也許所有數組都不管它們的維數是否相同,唯一的區別是多維數組在第一個元素之前存儲它們的額外維度,我們需要跳過那些記住數組維度大小的內存空間?

首先,一些背景:

除了當它是的操作數sizeof或一元&運營商,或者是一個字符串被用來初始化一個聲明另一個數組,類型“的N元件陣列的表達 T將被轉換(“衰變”)”,以表達式“指向T指針”,表達式的值將是數組的第一個元素的地址。

鑒於聲明

int a[10][10];

表達 a具有類型“的10個元素的數組的10個元素的數組int ”。 除非此表達式是sizeof或一元&運算符的操作數,否則它將轉換為“指向10元素數組的int ”或int (*)[10]類型的表達式。

鑒於該聲明,以下所有情況均屬實:

    Expression    Type                Decays to
    ----------    ----                ---------
             a    int [10][10]        int (*)[10]      
            &a    int (*)[10][10]     
            *a    int [10]            int *
          a[i]    int [10]            int *
         &a[i]    int (*)[10]         
         *a[i]    int          
       a[i][j]    int
      &a[i][j]    int *

也,

    sizeof a        == sizeof (int) * 10 * 10
    sizeof &a       == sizeof (int (*)[10][10])
    sizeof *a       == sizeof (int) * 10
    sizeof a[i]     == sizeof (int) * 10
    sizeof &a[i]    == sizeof (int (*)[10] )
    sizeof *a[i]    == sizeif (int)
    sizeof a[i][j]  == sizeof (int)
    sizeof &a[i][j] == sizeof (int *)

請注意,不同的指針類型int (*)[10][10]int (*)[10]int *不必具有相同的大小或具有相同的表示,盡管在平台上我是熟悉他們。

數組的第一個元素的地址與數組本身的地址相同; 因此,所有a&aa[0]&a[0]&a[0][0]將產生相同的 ,但類型將不同(如上表所示)。

因此,假設我們添加以下聲明:

int           *p0 = &a[0][0]; // equivalent to int       *p0 = a[0];
int     (*p1)[10] = &a[0];    // equivalent to int (*p1)[10] = a;
int (*p2)[10][10] = &a;

所有p0p1p2最初都具有相同的值,這是a第一個元素的地址; 但是,由於指針類型不同,涉及指針運算的結果操作會有所不同。 表達式p0 + 1將產生下一個int對象的地址( &a[0][1] )。 表達式p1 + 1將產生下一個10元素 int&a[1][0] )的地址。 最后,表達式p2 + 1將產生10個元素int的下一個10元素數組的地址(實際上, &a[11][0] )。

注意p1p2的類型; 既不是簡單的int * ,因為用於初始化它們的表達式不是那種類型(參見第一個表)。

注意模式; 對於數組類型,表達式越簡單,相應類型就越復雜。 表達式a不引用單個int對象; 它指的是10x10的int對象數組,因此當它出現在表達式中時,它被視為指向整數數組的指針,而不是指向單個整數的指針。

編譯器知道“a”是指向十個整數的指針。 如果未聲明維度,則編譯器會將新指針視為指向未知數量的整數的指針。 這將適用於您的情況,但它會生成編譯器警告,因為編譯器將它們視為不兼容的指針。 您嘗試執行的操作的語法(不生成編譯器警告)是:

int a[10][10];
int *p1 = &a[0][0];
int (*p2)[10] = a;
printf("p1: %p p2: %p\n", p1, p2);

這很重要的一個原因是指針算術:

p1++; //move forward sizeof(int) bytes
p2++; //move forward sizeof(int) * 10 bytes

你的理解很接近,不同的是類型信息。 指針確實有它的類型。 例如int * p,指針類型是int *,如int a [10] [10],相應的指針類型是int * [10] [10]。

在您的示例中,p和a do指向相同的地址,但它們是不同的類型,這對它們執行算術運算很重要。

以下是此網址的示例

假設我們現在定義了三個指針:

char *mychar;
short *myshort;
long *mylong;

並且我們知道它們分別指向存儲器位置1000,2000和3000。

因此,如果我們寫:

++mychar;

++myshort;

++mylong;

正如人們所預料的那樣,mychar將包含值1001.但不是那么明顯,myshort將包含值2002,而mylong將包含3004,即使它們每個只增加一次。 原因是,當向指針添加一個指針時,指針指向相同類型的后續元素,因此,指向它的類型的字節大小將添加到指針。

你是對的,你可以將數組本身分配給指針:

int a[10][10] = {[0][0]=6,[0][1]=1,[1][0]=10,[1][1]=11};
int b[10][10][10] = {[0][0][0]=8,[0][0][1]=1,[0][1][0]=10,[1][0][0]=100};

int *p, *q, *r, *s;

p = &a[0][0];   
q = a;      // what you are saying  

r = &b[0][0][0];    
s = b;      // what you are saying


printf("p= %p,*p= %d\n",p,*p);
printf("q= %p,*q= %d\n",q,*q);

printf("r= %p,*r= %d\n",r,*r);
printf("s= %p,*s= %d\n",s,*s);

輸出是:

p= 0xbfdd2eb0,*p= 6
q= 0xbfdd2eb0,*q= 6
r= 0xbfdd3040,*r= 8
s= 0xbfdd3040,*s= 8

無論矩陣的大小如何,它們都指向相同的地址。 所以,你說的是對的。

在2D數組中, *aa的結果是相同的,它們都指向這個2D數組的第一個地址!

但是如果你想定義一個指向這個數組的指針,你可以使用int (*ptr)[10]

你是對的,1D和2D共享相同的結構,但2D對上面的指針有一些額外的操作。

總而言之,在2D數組中, a*a&a[0][0]打印相同的地址,但它們的用法可能會有所不同。

像這樣:

#include<stdio.h>

int main() {
  int a[10][10];
  int *pa1 = &a[0][0];
  int *pa2 = *a;
  printf("pa1 is %p\n", pa1);
  printf("pa2 is %p\n", pa2);
  printf("Address of a is %p\n", a);

  // pointer to array
  int (*pa3)[10];
  pa3 = a;
  printf("pa3 is %p\n", pa3);

  return 0;
}

他們打印相同的地址。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM