有什么區別
int(*a)[5];
int b[5] = { 1, 2, 3, 4, 5 };
i = 0;
a = &b;
for (i = 0; i < 5; i )
printf("%d\n", *(*a i));
和
int b[5] = { 1, 2, 3, 4, 5 };
int *y = b;
for (i = 0; i < 5; i )
printf("%d\n", *y i);
這兩個片段產生相同的輸出,但我不明白初始化有什么區別?怎么
int *y = b;
不同于
int(*a)[5];
如何解釋這種取消參考?
printf("%d\n", *(*a i));
uj5u.com熱心網友回復:
來自 C 標準(6.3.2.1 左值、陣列和函式指示符)
3 除非它是 sizeof 運算子或一元 & 運算子的運算元,或者是用于初始化陣列的字串文字,否則型別為“型別陣列”的運算式將轉換為型別為“指標”的運算式to type'' 指向陣列物件的初始元素并且不是左值。如果陣列物件具有暫存器存盤類,則行為未定義。
在你的第二個代碼片段中
int b[5] = { 1, 2, 3, 4, 5 };
int *y = b;
在指標的宣告中,用作初始值設定項y的陣列指示符被隱式轉換為指向其第一個元素的指標。b上面的宣告等同于
int *y = &b[0];
取消參考指標y,您將獲得型別陣列的第一個元素int。
試試下面的演示程式。
#include <stdio.h>
int main( void )
{
int b[5] = { 1, 2, 3, 4, 5 };
int *y = b;
printf( "sizeof( *y ) = %zu, *y = %d\n", sizeof( *y ), *y );
}
它的輸出可能看起來像
sizeof( *y ) = 4, *y = 1
因此在這個for回圈中
for (i = 0; i < 5; i )
printf("%d\n", *y i);
您只需輸出陣列第一個元素的b值加上變數的值i。這實際上是回圈不輸出陣列的元素,b因為除了陣列的第一個元素之外,它們甚至沒有被訪問。
如果你想輸出你需要寫的陣列元素
for (i = 0; i < 5; i )
printf("%d\n", *( y i ));
這和寫是一樣的
for (i = 0; i < 5; i )
printf("%d\n", y[i] );
因為下標運算子的計算方式類似于(C 標準,6.5.2.1 陣列下標)
2 后綴運算式后跟方括號 [] 中的運算式是陣列物件元素的下標名稱。下標運算子 [] 的定義是 E1[E2] 等同于 (*((E1) (E2)))。由于適用于二元 運算子的轉換規則,如果 E1 是一個陣列物件(等效地,指向陣列物件的初始元素的指標)并且 E2 是一個整數,則 E1[E2] 指定的第 E2 個元素E1(從零開始計數)。
在您的第一個代碼片段中
int(*a)[5];
int b[5] = { 1, 2, 3, 4, 5 };
i = 0;
a = &b;
for (i = 0; i < 5; i )
printf("%d\n", *(*a i));
指標a被宣告為指向型別陣列的指標int[5]。所以取消參考指標你得到一個型別的陣列int[5]。
考慮以下演示程式,
#include <stdio.h>
int main( void )
{
int(*a)[5];
int b[5] = { 1, 2, 3, 4, 5 };
printf( "sizeof( *a ) = %zu\n", sizeof( *a ) );
}
它的輸出可能看起來像
sizeof( *a ) = 20
在這個for回圈中
for (i = 0; i < 5; i )
printf("%d\n", *(*a i));
運算式*a產生指標陣列b,運算式中使用的 指標陣列*a i被轉換為指向其第一個元素的指標。為了清楚起見,您可以按以下方式重寫 for 回圈
for (i = 0; i < 5; i )
{
int *p = *a;
printf("%d\n", *(p i));
}
這是在這個宣告中
int *p = *a;
根據 C 標準提供的第一個參考,通過取消參考指標獲得的陣列 a被隱式轉換為指向其第一個元素的指標。
再考慮一個例子。假設您有一個二維陣列,例如
int b[2][5] =
{
{ 1, 2, 3, 4, 5 },
{ 6, 7, 8, 9, 10 }
};
正如上面所指出的,運算式中使用的陣列在極少數情況下被轉換為指向其初始(第一個)元素的指標。陣列元素的型別是int[5]. 所以你可以宣告一個指標
int ( *a )[5] = b;
在這種情況下輸出你可以寫的陣列
for ( int i = 0; i < 2; i )
{
for ( int j = 0; j < 5; j )
{
printf( "%d\n", *( *a j ) );
}
a;
}
在這個宣告之后
a;
由于指標演算法,指標a將指向陣列的第二個元素,該元素b是該型別的第二個“行” int[5]。
再次宣告
int ( *a )[5] = b;
相當于
int ( *a )[5] = &b[0];
uj5u.com熱心網友回復:
幾乎是旁注,但有些代碼不正確。
參考下面的代碼...
請注意,我稱之為第一個片段foo是正確的。
但是,我將呼叫的第二個片段bar是不正確的。它只[偶然地]起作用,因為b陣列是1, 2, 3, 4, 5(即按排序順序)。
如果b陣列未排序,則bar不會列印正確的順序。這是因為*y i必須*(y i)
對于*y i,為所有回圈迭代獲取的值是b[0]我們添加的值i。要使用陣列/索引語法,我們正在做:y[0] i
我們想要的是獲取:b[0] b[1] ... b[4]
更正后的版本在baz. 所以,我們使用*(y i). 在陣列/索引語法中,這是y[i].
這是說明這一點的代碼:
#include <stdio.h>
#if SORTED
int b[5] = { 1, 2, 3, 4, 5 };
#else
int b[5] = { 5, 4, 1, 2, 3 };
#endif
void
foo(void)
{
int (*a)[5];
a = &b;
printf("\n");
for (int i = 0; i < 5; i )
printf("foo: %d\n", *(*a i));
}
void
bar(void)
{
int *y = b;
printf("\n");
// NOTE/BUG: "*y i" is incorrect -- see baz
for (int i = 0; i < 5; i )
printf("bar: %d\n", *y i);
}
void
baz(void)
{
int *y = b;
printf("\n");
// NOTE/FIX: correct fix for bar
for (int i = 0; i < 5; i )
printf("baz: %d\n", *(y i));
}
int
main(void)
{
foo();
bar();
baz();
return 0;
}
這是程式輸出:
foo: 5
foo: 4
foo: 1
foo: 2
foo: 3
bar: 5
bar: 6
bar: 7
bar: 8
bar: 9
baz: 5
baz: 4
baz: 1
baz: 2
baz: 3
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/537841.html
下一篇:C 中指標的靜態優先級佇列
