เพื่อให้เข้าใจอย่างถ่องแท้คุณต้องเข้าใจแนวคิดต่อไปนี้:
อาร์เรย์ไม่ใช่ตัวชี้!
ครั้งแรกของทั้งหมด (และจะได้รับเทศน์พอ), อาร์เรย์จะไม่ชี้ ในการใช้งานส่วนใหญ่พวกเขาจะ 'สลาย' ไปยังที่อยู่ไปยังองค์ประกอบแรกซึ่งสามารถกำหนดให้กับตัวชี้:
int a[] = {1, 2, 3};
int *p = a; // p now points to a[0]
ฉันคิดว่ามันทำงานในลักษณะนี้เพื่อให้สามารถเข้าถึงเนื้อหาของอาร์เรย์ได้โดยไม่ต้องคัดลอกทั้งหมด นั่นเป็นเพียงพฤติกรรมของประเภทอาร์เรย์และไม่ได้หมายถึงการบอกเป็นนัยว่าเป็นสิ่งเดียวกัน
อาร์เรย์หลายมิติ
อาร์เรย์หลายมิติเป็นเพียงวิธีหนึ่งในการ 'แบ่งพาร์ติชัน' หน่วยความจำในลักษณะที่คอมไพเลอร์ / เครื่องสามารถเข้าใจและดำเนินการได้
ตัวอย่างเช่นint a[4][3][5]
= อาร์เรย์ที่มี 4 * 3 * 5 (60) 'ชิ้นส่วน' ของหน่วยความจำขนาดจำนวนเต็ม
ข้อได้เปรียบของการใช้int a[4][3][5]
vs ธรรมดาint b[60]
คือตอนนี้พวกเขา 'แบ่งพาร์ติชัน' แล้ว (ทำงานกับ 'ชิ้นส่วน' ได้ง่ายขึ้นหากจำเป็น) และโปรแกรมสามารถทำการตรวจสอบแบบผูกมัดได้แล้ว
ในความเป็นจริงint a[4][3][5]
จะถูกเก็บไว้ว่าเหมือนint b[60]
ในความทรงจำ - เดอะเพียงความแตกต่างคือว่าโปรแกรมที่ตอนนี้จัดการมันราวกับว่าพวกเขากำลังแยกหน่วยงานที่มีขนาดบางอย่าง (โดยเฉพาะสี่กลุ่มสามกลุ่มห้า)
ข้อควรจำ: ทั้งสองอย่างint a[4][3][5]
และint b[60]
เหมือนกันในหน่วยความจำและความแตกต่างเพียงอย่างเดียวคือวิธีจัดการโดยแอปพลิเคชัน / คอมไพเลอร์
{
{1, 2, 3, 4, 5}
{6, 7, 8, 9, 10}
{11, 12, 13, 14, 15}
}
{
{16, 17, 18, 19, 20}
{21, 22, 23, 24, 25}
{26, 27, 28, 29, 30}
}
{
{31, 32, 33, 34, 35}
{36, 37, 38, 39, 40}
{41, 42, 43, 44, 45}
}
{
{46, 47, 48, 49, 50}
{51, 52, 53, 54, 55}
{56, 57, 58, 59, 60}
}
จากนี้จะเห็นได้ชัดเจนว่า "พาร์ติชั่น" แต่ละตัวเป็นเพียงอาร์เรย์ที่โปรแกรมติดตาม
วากยสัมพันธ์
ตอนนี้อาร์เรย์มีความแตกต่างทางวากยสัมพันธ์จากพอยน์เตอร์ โดยเฉพาะหมายความว่าคอมไพเลอร์ / เครื่องจะปฏิบัติแตกต่างกัน สิ่งนี้อาจดูเหมือนไม่ใช่เกมง่ายๆ แต่ลองดูสิ่งนี้:
int a[3][3];
printf("%p %p", a, a[0]);
ตัวอย่างข้างต้นพิมพ์ที่อยู่หน่วยความจำเดียวกันสองครั้งดังนี้:
0x7eb5a3b4 0x7eb5a3b4
อย่างไรก็ตามสามารถกำหนดเพียงตัวเดียวให้กับตัวชี้ได้โดยตรง :
int *p1 = a[0]; // RIGHT !
int *p2 = a; // WRONG !
เหตุใดจึงไม่ a
สามารถกำหนดให้กับตัวชี้ได้ แต่ a[0]
ทำได้?
นี่เป็นผลมาจากอาร์เรย์หลายมิติและฉันจะอธิบายว่าทำไม:
ในระดับ ' a
' เรายังคงเห็นว่าเรามี 'มิติ' อื่นที่จะมองไปข้างหน้า อย่างไรก็ตามที่ระดับ ' a[0]
' เราอยู่ในมิติด้านบนแล้วดังนั้นเท่าที่โปรแกรมเกี่ยวข้องเราแค่ดูอาร์เรย์ปกติ
คุณอาจจะถาม:
เหตุใดจึงมีความสำคัญหากอาร์เรย์มีหลายมิติเกี่ยวกับการสร้างตัวชี้
คิดอย่างนี้ดีที่สุด:
'การสลายตัว' จากอาร์เรย์หลายมิติไม่ใช่แค่แอดเดรส แต่เป็นแอดเดรสที่มีข้อมูลพาร์ติชัน (AKA ยังคงเข้าใจว่าข้อมูลพื้นฐานนั้นสร้างจากอาร์เรย์อื่น) ซึ่งประกอบด้วยขอบเขตที่อาร์เรย์กำหนดไว้นอกเหนือจากมิติแรก
ตรรกะ 'พาร์ติชัน' นี้ไม่สามารถมีอยู่ในตัวชี้ได้เว้นแต่เราจะระบุ:
int a[4][5][95][8];
int (*p)[5][95][8];
p = a; // p = *a[0] // p = a+0
มิฉะนั้นความหมายของคุณสมบัติการเรียงลำดับของอาร์เรย์จะหายไป
สังเกตการใช้วงเล็บรอบ ๆ ด้วย*p
: int (*p)[5][95][8]
- นั่นคือเพื่อระบุว่าเรากำลังสร้างตัวชี้ด้วยขอบเขตเหล่านี้ไม่ใช่อาร์เรย์ของพอยน์เตอร์ที่มีขอบเขตเหล่านี้:int *p[5][95][8]
ข้อสรุป
มาทบทวนกัน:
- อาร์เรย์จะสลายไปเป็นแอดเดรสหากไม่มีจุดประสงค์อื่นในบริบทที่ใช้
- อาร์เรย์หลายมิติเป็นเพียงอาร์เรย์ของอาร์เรย์ - ดังนั้นแอดเดรสที่ 'ผุพัง' จะรับภาระของ "ฉันมีมิติย่อย"
- ข้อมูลขนาดไม่สามารถอยู่ในตัวชี้จนกว่าคุณจะให้มันไป
โดยย่อ: อาร์เรย์หลายมิติสลายตัวเป็นที่อยู่ที่มีความสามารถในการทำความเข้าใจเนื้อหา