簡體   English   中英

“int(*)[]”在函數參數中是否會衰減為“int **”?

[英]Does “int (*)[]” decay into “int **” in a function parameter?

我今天早些時候在programmers.stackexchange上發布了這個問題 我一直認為int (*)[] 衰變成int **函數參數,但我得到了我的疑問,認為它多次響應。

我在函數參數中使用了int (*)[] ,但現在我變得非常困惑。

當我使用gcc -std=c99 -pedantic -Wall編譯此函數時

void function(int (*a)[])
{
    sizeof(*a);
}

我收到此錯誤消息:

c99 -Wall -pedantic -c main.c -o main.o
main.c: In function ‘function’:
main.c:3:11: error: invalid application of ‘sizeof’ to incomplete type ‘int[]’ 
make: *** [main.o] Error 1

這表明*a的類型為int []而不是int *

有人可以解釋像int (*)[]這樣的東西在函數參數中衰變成int **並給我一些參考(可能來自標准文檔),這證明了為什么會這樣。

傳遞給函數時,只有數組類型轉換為指向其第一個元素的指針。 a指向int數組的類型指針 ,即它是指針類型,因此沒有轉換

對於原型

void foo(int a[][10]);

編譯器將其解釋為

void foo(int (*a)[10]);  

那是因為a[]是數組類型。 int a[][10]永遠不會轉換為int **a 也就是說, 答案中的第二段是錯誤的和誤導性的。

作為函數參數, int *a[]等效於int **這是因為a數組類型。

int (*)[]是指向int數組的指針。

在您的示例中, *a 可以衰減為int* sizeof(*a)不會腐爛; 它本質上是sizeof(int[]) ,無效。

a根本不能衰減(它是一個指針)。

N1256§6.7.5.3/ p7-8

7參數聲明為'' 類型數組''應調整為''限定指向類型 '',其中類型限定符(如果有)是在數組類型派生的[]中指定的那些。 如果關鍵字static也出現在數組類型派生的[]中,則對於每次對函數的調用,相應實際參數的值應提供對數組的第一個元素的訪問,其中至少有指定的元素數量。按大小表達式。

8參數聲明為''函數返回類型 ''應調整為''指向函數返回類型 ''的指針,如6.3.2.1所述。

int (*)[]是“指向int數組的指針”。 它是“ 類型的數組”? 不,這是一個指針。 是“功能返回 ”嗎? 不,這是一個指針。 因此它沒有得到調整。

int (*a)[]的情況下, sizeof *a由於一個原因不起作用:數組沒有元素計數。 如果沒有元素計數,則無法計算大小。

因此,對a任何指針算法都不起作用,因為它是根據對象的大小定義的。 由於數組的大小不確定,因此不能在指針本身上使用指針算法。 數組表示法是根據指針算法定義的,因此sizeof a[0][0] (或涉及a[n]任何表達式都不起作用,而sizeof (*a)[0]將起作用。

這實際上意味着你可以用指針做很少的事情。 唯一允許的是:

  • 使用一元*運算符取消引用指針
  • 將指針傳遞給另一個函數(函數參數的類型必須是數組數組或指向數組的指針)
  • 獲取指針的大小(以及對齊或類型,如果您的編譯器支持其中一個或兩個)
  • 將指針指定給兼容類型

如果您的編譯器支持可變長度數組(VLA),並且您知道大小,則可以通過在函數體的開頭添加一行來解決此問題,如

void
foo (int (*a0)[], size_t m, size_t n)
{
  int (*a)[n] = a0;
  ...
}

如果沒有VLA,您必須采取其他措施。

值得注意的是,動態分配不是int (*)[]一個因素。 數組數組衰減到指向數組的指針(就像我們在這里一樣),因此在將它們傳遞給函數時它們是可互換的( sizeof和任何_Alignoftypeof關鍵字是運算符,而不是函數)。 這意味着必須靜態分配指向的數組:一旦數組衰減到指針,就不會再發生衰減,所以你不能說指向數組的指針( int (*)[] )與指針相同指針( int ** )。 否則你的編譯器很樂意讓你把int [3][3]傳遞給一個接受int **的函數,而不是想要一個int (*)[]int (*)[n]int [][n] ,或int [m][n]

因此,即使您的編譯器不支持VLA,您也可以使用靜態分配的數組將其所有元素組合在一起的事實:

void foo (int (*a0)[], size_t m, size_t n)
{
  int *a = *a0;
  size_t i, j;

  for (i = 0; i < m; i++)
    {
      for (j = 0; j < n; j++)
        {
          // Do something with `a[i * n + j]`, which is `a0[i][j]`.
        }
    }
  ...
}

用作二維數組的動態分配的一維數組具有相同的屬性,因此這仍然有效。 僅當第二維被動態分配時,意味着類似於for (i = 0; i < m; i++) a[i] = malloc (n * sizeof *a[i]);的循環for (i = 0; i < m; i++) a[i] = malloc (n * sizeof *a[i]); 分別分配每個子數組,這個原則不起作用。 這是因為你有一個指針數組( int *[] ,或數組衰減后的int ** ),它指向內存中另一個位置的數組的第一個元素,而不是數組的數組,它保留所有這些物品在一起。

所以:

  • no, int (*p)[]int **q不能以相同的方式使用。 p是指向數組的指針,這意味着所有項目都是從p存儲的地址開始組合在一起的。 q是指向指針的指針,這意味着項目可能散布在q[0]q[1] ,..., q[m - 1]中存儲的不同地址。

  • sizeof *p不起作用,因為p指向具有未知數量元素的數組。 編譯器無法計算每個元素的大小,因此對p本身的操作非常有限。

暫無
暫無

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

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