[英]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
和任何_Alignof
或typeof
關鍵字是運算符,而不是函數)。 這意味着必須靜態分配指向的數組:一旦數組衰減到指針,就不會再發生衰減,所以你不能說指向數組的指針( 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.