เข้าใจ sizeof ใน C++: ทำไม n จึงไม่เท่ากับ 8?

เมื่อทำงานกับอาร์เรย์ใน C++ คุณอาจพบผลลัพธ์ที่คาดไม่ถึงเกี่ยวกับตัวดำเนินการ sizeof โดยเฉพาะอย่างยิ่งเมื่อส่งอาร์เรย์ไปยังฟังก์ชัน ในบล็อกโพสต์นี้เราจะสำรวจความสับสนทั่วไปที่เกิดขึ้นเมื่อใช้ sizeof กับพารามิเตอร์ของฟังก์ชัน โดยเฉพาะการตอบคำถาม: ทำไม n จึงไม่เท่ากับ 8 ในฟังก์ชัน foo()?

ปัญหา

มาลองพิจารณาสองตัวอย่างโค้ดที่แสดงปัญหานี้:

ตัวอย่างที่ 1: ฟังก์ชัน foo()

void foo(char cvalue[8])
{
    int n = sizeof(cvalue);
}

ในตัวอย่างข้างต้น เมื่อต้องการเรียก sizeof(cvalue) คุณอาจคาดหวังว่า n จะเท่ากับ 8 เนื่องจากอาร์เรย์ถูกกำหนดขนาดไว้ที่ 8 แต่สถานการณ์นั้นไม่เป็นเช่นนั้น

ตัวอย่างที่ 2: ฟังก์ชัน bar()

void bar()
{
    char cvalue[8];
    int n = sizeof(cvalue);
}

ในตัวอย่างที่สอง sizeof(cvalue) จะมีค่าเท่ากับ 8 ดังนั้นทำไมถึงมีความแตกต่าง?

เข้าใจแนวคิด

เพื่อที่จะเข้าใจว่า sizeof(cvalue) คืนค่าแตกต่างกันในแต่ละฟังก์ชันได้อย่างไร เราต้องชี้แจงว่าอาร์เรย์ถูกปฏิบัติอย่างไรใน C และ C++

อาร์เรย์เป็นพารามิเตอร์ฟังก์ชัน

เมื่อคุณส่งอาร์เรย์ไปยังฟังก์ชันใน C หรือ C++ คุณไม่ได้ส่งอาร์เรย์จริง ๆ แต่ในความเป็นจริงคุณกำลังส่งพอยเตอร์ไปยังสมาชิกแรกของอาร์เรย์ สัญลักษณ์วงเล็บที่ใช้ในพารามิเตอร์ฟังก์ชันนั้นเพียงแค่เป็นการสังเคราะห์ซึ่งไม่ได้เปลี่ยนแปลงพฤติกรรม—การประกาศทั้งสองนี้เป็นสิ่งที่เทียบเท่ากัน:

  • void foo(char cvalue[8])
  • void foo(char cvalue[])
  • void foo(char *cvalue)

ในการประกาศเหล่านี้ทั้งหมด cvalue จะถูกตีความว่าเป็นพอยเตอร์ ดังนั้นเมื่อคุณเรียก sizeof(cvalue) ภายใน foo() มันจะคืนขนาดของพอยเตอร์ไม่ใช่ขนาดของอาร์เรย์ บนแพลตฟอร์มส่วนใหญ่ขนาดนี้มักจะเป็น 4 ไบต์ในระบบ 32 บิตและ 8 ไบต์ในระบบ 64 บิต ซึ่งเป็นเหตุผลที่ n ไม่เท่ากับ 8 ใน foo()

บริบทที่ถูกต้องใน bar()

ในทางกลับกัน ภายใน bar() cvalue ถูกกำหนดให้เป็นอาร์เรย์ท้องถิ่นขนาด 8 ดังนั้นเมื่อเรียกใช้ sizeof(cvalue) ที่นี่มันจะสะท้อนขนาดของอาร์เรย์ทั้งหมดอย่างถูกต้อง ทำให้ n เท่ากับ 8

ข้อคิดสำคัญ

  • เข้าใจพฤติกรรมของพอยเตอร์: เมื่อส่งอาร์เรย์เป็นพารามิเตอร์ คุณมักจะส่งพอยเตอร์ ซึ่งอาจนำไปสู่ค่าที่สับสนเมื่อใช้ sizeof
  • อาร์เรย์ท้องถิ่น: sizeof แสดงขนาดจริงของอาร์เรย์ท้องถิ่นที่กำหนดไว้ภายในฟังก์ชัน ทำให้ได้ผลลัพธ์ที่คาดหวัง
  • การเขียนที่เป็นโครงสร้าง: สัญลักษณ์วงเล็บในพารามิเตอร์ฟังก์ชันไม่ได้สร้างตัวแปรอาร์เรย์ แต่บ่งชี้ว่าคุณกำลังจัดการพอยเตอร์

สรุป

การจัดการอาร์เรย์ใน C และ C++ อาจเป็นเรื่องท้าทาย โดยเฉพาะสำหรับผู้ที่ใหม่ต่อภาษา ความเข้าใจความแตกต่างระหว่างพอยเตอร์และอาร์เรย์จึงมีความสำคัญต่อการคำนวณและการดีบักอย่างถูกต้อง จำไว้ว่าขณะที่คุณอยู่ภายในฟังก์ชัน sizeof ที่ใช้กับพารามิเตอร์ที่ถือว่าเป็นอาร์เรย์จะให้ขนาดของพอยเตอร์ ไม่ใช่ขนาดของอาร์เรย์ที่คุณตั้งใจจะส่ง

หวังว่าคำอธิบายนี้จะช่วยให้เข้าใจพฤติกรรมของตัวดำเนินการ sizeof เกี่ยวกับอาร์กิวเมนต์อาร์เรย์ในฟังก์ชัน และชี้แจงเหตุผลที่ทำให้ n ไม่เท่ากับ 8 ในฟังก์ชัน foo() แต่เท่าใน bar() จงจำหลักการเหล่านี้ขณะเขียนโค้ด!