我首先為我的英語不好而感到抱歉。我在用 C 編碼時遇到了一個奇怪的問題。
using namespace std;
void Func(int a[2][3])
{
cout <<(int) &a;
}
int main()
{
int a[2][3] =
{
{1,2,3},
{4,5,6}
};
cout << (int)&a << endl;
Func(a);
return 0;
}
我很困惑 main() 和函式 Func() 中的 &a 回傳了不同的值。奇怪的是,它們之間的差異總是 212。誰能解釋一下?謝謝您的幫助。
P/s:謝謝大家的回答。我的老師說C 不允許按值傳遞陣列,因為如果陣列有100萬個元素,那么僅復制所有元素就會大大降低性能,所以他說只允許通過參考。這就是讓我認為這兩個 &a 應該相同的原因。現在明白了,謝謝大家!
uj5u.com熱心網友回復:
你的函式宣告
void Func(int a[2][3])
完全等效并可互換:
void Func(int (*a)[3]).
如您所見,您正在通過value傳遞一個指向三個 int 陣列的指標。因此,區域函式引數的地址與 main 中變數的地址不同,即使它們可能持有相同的值。
uj5u.com熱心網友回復:
您a按值傳遞引數,因此每個函式都有自己的副本(指標的副本,而不是陣列資料)。您看到的常數偏移來自兩個函式的堆疊幀之間的距離,這是常數。
如果您更改函式以獲取對陣列的參考(void Func(int (&a)[2][3])在兩種情況下您將獲得相同的值
uj5u.com熱心網友回復:
引數和區域變數是不同的物件,由于它們的生命周期重疊,它們必須具有不同的記憶體地址。
uj5u.com熱心網友回復:
請閱讀傳遞值和傳遞參考。所以這里發生的事情是:
- 你在
main函式中初始化了一個陣列。&a將參考 的地址a。 - 您作為傳值引數傳遞給另一個函式。創建 a 的副本以供使用
Func,&a并將參考a本地 to的記憶體位置Func。
我希望這個概念很清楚。
uj5u.com熱心網友回復:
使用以下語法通過 (const) 參考傳遞陣列: const int (&a)[2][3]
#include <iostream>
void func(const int (&a)[2][3])
{
for (const auto& row : a)
{
for(const auto& value : row )
{
std::cout << value << " ";
}
std::cout << "\n";
}
}
int main()
{
int a[2][3] =
{
{1,2,3},
{4,5,6}
};
func(a);
return 0;
}
uj5u.com熱心網友回復:
這是因為關于指標和陣列如何作業的 C 規則有點奇怪。您實際上是在獲取指向陣列的指標的地址,而不是陣列的實際地址。如果要獲取陣列的地址,則需要取第一個元素的地址:
&a[0]
uj5u.com熱心網友回復:
對于初學者來說,將地址轉換為 int 型別是一個壞主意,例如
cout << (int)&a << endl;
你可以寫
cout << static_cast<void *>( a ) << endl;
或者
cout << static_cast<void *>( &a ) << endl;
甚至喜歡
cout << a << endl;
cout << &a << endl;
雖然static_cast代碼看起來更具可讀性。
這兩個陳述句將輸出相同的值:陣列占用的記憶體范圍的地址。
在這個函式呼叫中
Func(a);
陣列指示符被隱式轉換為指向其第一個型別元素的指標int( * )[3]。
指標運算式的值被賦值給a函式的區域變數(引數)Func。
指標型別的函式引數a和amain中定義的陣列占用不同程度的記憶體。
如果重命名函式引數,例如
void Func(int b[2][3])
為了將它與 main 中定義的同名陣列區分開來,你可以想象函式呼叫如下
功能(a);
//...
void Func( /*int b[2][3] */ )
{
int ( *b )[3] = a;
cout << static_cast<void *>( &b );
}
注意宣告為陣列型別的函式引數會int[2][3]被編譯器隱式調整為指向陣列元素型別的指標int ( * )[3]。
所以你可以看到這個宣告
cout << static_cast<void *>( &b );
輸出區域變數(引數)的地址b。
如果你想a在函式中獲取陣列的地址,Func那么你應該寫
cout << static_cast<void *>( b );
在這種情況下, main 和 function 中輸出的地址將重合,因為引數b存盤陣列的第一個元素的地址a。
這是一個演示程式。
#include <iostream>
void Func( int a[2][3] )
{
std::cout << static_cast< void * >( a ) << '\n';
}
int main()
{
int a[2][3] =
{
{1,2,3},
{4,5,6}
};
std::cout << static_cast<void *>( a ) << '\n';
std::cout << static_cast<void *>( &a ) << '\n';
Func( a );
}
程式輸出可能看起來像
010FFD08
010FFD08
010FFD08
如您所見,這三個值彼此相等。
但是如果你會在函式中寫 Func
std::cout << static_cast< void * >( &a ) << '\n';
^^^^
您將獲得a函式的區域變數(引數)的地址。很明顯,這個地址與陣列占用的記憶體區的地址不同,因為對于引數 a 分配了一個單獨的記憶體區,其大小等于 tp 的值,sizeof( int( * )[3] )通常這個值等于4 或 8。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/397889.html
上一篇:編譯器看不到C 11識別符號
