สิ่งที่คุณพูดในโพสต์ของคุณนั้นถูกต้องที่สุด ฉันจะบอกว่านักพัฒนา C ทุกคนได้รับการค้นพบที่เหมือนกันทุกประการและได้ข้อสรุปเหมือนกันทุกประการเมื่อ (ถ้า) พวกเขามีความเชี่ยวชาญในภาษา C ถึงระดับหนึ่ง
เมื่อข้อมูลจำเพาะของพื้นที่แอ็พพลิเคชันของคุณเรียกใช้อาร์เรย์ที่มีขนาดคงที่เฉพาะ (ขนาดอาร์เรย์เป็นค่าคงที่เวลาคอมไพล์) วิธีเดียวที่เหมาะสมในการส่งอาร์เรย์ดังกล่าวไปยังฟังก์ชันคือการใช้พารามิเตอร์ตัวชี้ไปยังอาร์เรย์
void foo(char (*p)[10]);
(ในภาษา C ++ สิ่งนี้ทำได้ด้วยการอ้างอิง
void foo(char (&p)[10]);
)
การดำเนินการนี้จะเปิดใช้งานการตรวจสอบประเภทระดับภาษาซึ่งจะทำให้แน่ใจว่าอาร์เรย์ที่มีขนาดที่ถูกต้องถูกระบุเป็นอาร์กิวเมนต์ ในความเป็นจริงในหลาย ๆ กรณีผู้คนใช้เทคนิคนี้โดยปริยายโดยไม่รู้ตัวด้วยซ้ำโดยซ่อนประเภทอาร์เรย์ไว้ด้านหลังชื่อ typedef
typedef int Vector3d[3];
void transform(Vector3d *vector);
/* equivalent to `void transform(int (*vector)[3])` */
...
Vector3d vec;
...
transform(&vec);
โปรดทราบว่ารหัสข้างต้นไม่แปรผันตามความสัมพันธ์กับVector3d
ประเภทที่เป็นอาร์เรย์หรือstruct
. คุณสามารถเปลี่ยนคำจำกัดความVector3d
จากอาร์เรย์เป็น a struct
และย้อนกลับได้ตลอดเวลาและคุณไม่ต้องเปลี่ยนการประกาศฟังก์ชัน ไม่ว่าในกรณีใดฟังก์ชันจะได้รับออบเจ็กต์รวม "โดยการอ้างอิง" (มีข้อยกเว้นสำหรับสิ่งนี้ แต่ในบริบทของการสนทนานี้เป็นจริง)
อย่างไรก็ตามคุณจะไม่เห็นวิธีการส่งผ่านอาร์เรย์นี้อย่างชัดเจนบ่อยเกินไปเพียงเพราะมีคนจำนวนมากสับสนกับไวยากรณ์ที่ค่อนข้างซับซ้อนและไม่สะดวกพอที่จะใช้คุณสมบัติดังกล่าวของภาษา C ได้อย่างเหมาะสม ด้วยเหตุนี้ในชีวิตจริงโดยเฉลี่ยแล้วการส่งอาร์เรย์เป็นตัวชี้ไปยังองค์ประกอบแรกจึงเป็นแนวทางที่ได้รับความนิยมมากกว่า มันดู "เรียบง่ายกว่า"
แต่ในความเป็นจริงการใช้ตัวชี้ไปยังองค์ประกอบแรกสำหรับการส่งผ่านอาร์เรย์เป็นเทคนิคที่เฉพาะเจาะจงมากซึ่งเป็นเคล็ดลับที่ตอบสนองวัตถุประสงค์ที่เฉพาะเจาะจงมากจุดประสงค์เดียวคือเพื่ออำนวยความสะดวกในการส่งอาร์เรย์ที่มีขนาดแตกต่างกัน (เช่นขนาดรันไทม์) . หากคุณจำเป็นต้องสามารถประมวลผลอาร์เรย์ที่มีขนาดรันไทม์ได้จริงๆวิธีที่เหมาะสมในการส่งอาร์เรย์ดังกล่าวคือตัวชี้ไปยังองค์ประกอบแรกที่มีขนาดคอนกรีตที่กำหนดโดยพารามิเตอร์เพิ่มเติม
void foo(char p[], unsigned plen);
จริงๆแล้วในหลาย ๆ กรณีการประมวลผลอาร์เรย์ที่มีขนาดรันไทม์ซึ่งมีประโยชน์มากซึ่งก่อให้เกิดความนิยมของวิธีนี้ด้วย นักพัฒนา C หลายคนไม่เคยพบ (หรือไม่เคยรับรู้) ถึงความจำเป็นในการประมวลผลอาร์เรย์ขนาดคงที่ดังนั้นจึงยังคงไม่สนใจเทคนิคขนาดคงที่ที่เหมาะสม
อย่างไรก็ตามหากขนาดอาร์เรย์คงที่จะส่งผ่านเป็นตัวชี้ไปยังองค์ประกอบ
void foo(char p[])
เป็นข้อผิดพลาดระดับเทคนิคที่สำคัญซึ่งน่าเสียดายที่แพร่หลายในปัจจุบัน เทคนิคตัวชี้ไปยังอาร์เรย์เป็นแนวทางที่ดีกว่ามากในกรณีเช่นนี้
อีกสาเหตุหนึ่งที่อาจขัดขวางการนำเทคนิคการส่งผ่านอาร์เรย์ขนาดคงที่มาใช้คือการครอบงำของวิธีการที่ไร้เดียงสาในการพิมพ์อาร์เรย์ที่จัดสรรแบบไดนามิก ตัวอย่างเช่นหากโปรแกรมเรียกใช้อาร์เรย์ประเภทคงที่char[10]
(ดังตัวอย่างของคุณ) นักพัฒนาทั่วไปจะเรียกmalloc
อาร์เรย์เป็น
char *p = malloc(10 * sizeof *p);
ไม่สามารถส่งอาร์เรย์นี้ไปยังฟังก์ชันที่ประกาศเป็น
void foo(char (*p)[10]);
ซึ่งสร้างความสับสนให้กับนักพัฒนาโดยเฉลี่ยและทำให้พวกเขาละทิ้งการประกาศพารามิเตอร์ขนาดคงที่โดยไม่คิดอะไรเพิ่มเติม ในความเป็นจริงแล้วต้นตอของปัญหาอยู่ที่malloc
วิธีการที่ไร้เดียงสา malloc
รูปแบบที่ปรากฏข้างต้นควรจะสงวนไว้สำหรับอาร์เรย์ขนาดเวลาทำงาน หากประเภทอาร์เรย์มีขนาดเวลาคอมไพล์วิธีที่ดีกว่าmalloc
จะมีลักษณะดังนี้
char (*p)[10] = malloc(sizeof *p);
แน่นอนสิ่งนี้สามารถส่งผ่านไปยังที่ระบุไว้ข้างต้นได้อย่างง่ายดาย foo
foo(p);
และคอมไพเลอร์จะทำการตรวจสอบประเภทที่เหมาะสม แต่อีกครั้งสิ่งนี้สร้างความสับสนให้กับนักพัฒนา C ที่ไม่ได้เตรียมตัวไว้มากเกินไปซึ่งเป็นสาเหตุที่คุณจะไม่เห็นมันบ่อยเกินไปในรหัสประจำวันโดยเฉลี่ย "ทั่วไป"
10
สามารถแทนที่ด้วยตัวแปรในขอบเขต