เหตุใดจึงประกาศโครงสร้างที่มีอาร์เรย์ใน C เท่านั้น


131

ฉันเจอรหัสที่มีสิ่งต่อไปนี้:

struct ABC {
    unsigned long array[MAX];
} abc;

เมื่อใดจึงควรใช้คำประกาศเช่นนี้

คำตอบ:


184

ช่วยให้คุณสามารถส่งอาร์เรย์ไปยังฟังก์ชันตามค่าหรือส่งคืนเป็นค่าจากฟังก์ชัน

โครงสร้างสามารถส่งผ่านค่าได้ซึ่งแตกต่างจากอาร์เรย์ที่สลายตัวเป็นตัวชี้ในบริบทเหล่านี้


1
ระวังการทำเช่นนี้กับอาร์เรย์มากกว่า 16 หรือ 32 ไบต์สำหรับฟังก์ชันที่ไม่อยู่ในบรรทัด: การส่งผ่าน const-reference จะมีประสิทธิภาพมากขึ้นเว้นแต่ว่า callee ต้องการสำเนา tmp อยู่แล้วซึ่งสามารถทำลายได้ หากการโทร / การส่งคืนไม่ได้รับการปรับให้เหมาะสมอาร์เรย์ขนาดกลางถึงใหญ่ (หลายพันไบต์) เป็นสิ่งที่น่ากลัวที่จะส่งผ่านค่า
Peter Cordes

85

ข้อดีอีกประการหนึ่งคือมันแยกขนาดออกไปดังนั้นคุณจึงไม่ต้องใช้[MAX]โค้ดทั้งหมดของคุณในทุกที่ที่คุณประกาศวัตถุดังกล่าว สิ่งนี้สามารถทำได้ด้วย

typedef char ABC[MAX];

แต่คุณมีปัญหาที่ใหญ่กว่ามาก: คุณต้องระวังว่าABCเป็นประเภทอาร์เรย์ (แม้ว่าคุณจะไม่เห็นสิ่งนี้เมื่อคุณประกาศตัวแปรประเภทABC) มิฉะนั้นคุณจะถูกต่อยจากข้อเท็จจริงที่ว่าABCจะมีความหมายแตกต่างออกไป ในรายการอาร์กิวเมนต์ของฟังก์ชันเทียบกับการประกาศ / นิยามตัวแปร

ข้อดีอีกอย่างหนึ่งคือโครงสร้างช่วยให้คุณสามารถเพิ่มองค์ประกอบเพิ่มเติมได้ในภายหลังหากคุณต้องการโดยไม่ต้องเขียนโค้ดซ้ำ


45

คุณสามารถคัดลอกโครงสร้างและส่งคืนโครงสร้างจากฟังก์ชัน

คุณไม่สามารถทำได้ด้วยอาร์เรย์ - เว้นแต่จะเป็นส่วนหนึ่งของโครงสร้าง!


26

ลอกแบบนี้ก็ได้

struct ABC a, b;
........
a = b;

สำหรับอาร์เรย์คุณจะต้องใช้ฟังก์ชันmemcpyหรือลูปเพื่อกำหนดแต่ละองค์ประกอบ


6
(ดังนั้นจึงอนุญาตให้ใช้รหัสที่สะอาดกว่า - มันจะไม่สร้างความแตกต่างในความเร็ว ฯลฯ )
John Carter

3
มีประโยชน์ น่าเสียดายที่คุณทำไม่ได้ถ้า (a == b)!?! มันไม่สอดคล้องกันแค่ไหน สำหรับ C ++ จะมองหาตัวดำเนินการ == ในภาษา C ระบุว่า "ไม่ถูกต้องถูกดำเนินการกับไบนารี =="
Matt

11

คุณสามารถใช้ struct เพื่อให้เป็นชนิดใหม่ของข้อมูลเช่นสตริง คุณสามารถกำหนด:

struct String {
    char Char[MAX];
};

หรือคุณสามารถสร้างรายการข้อมูลที่คุณสามารถใช้โดยการโต้แย้งของฟังก์ชันหรือส่งคืนในวิธีการของคุณ โครงสร้างมีความยืดหยุ่นมากกว่าอาร์เรย์เนื่องจากสามารถรองรับตัวดำเนินการบางอย่างเช่น = และคุณสามารถกำหนดวิธีการบางอย่างได้

หวังว่าจะเป็นประโยชน์สำหรับคุณ :)


2
โดยพื้นฐานแล้ว C เป็นสิ่งที่ใกล้เคียงที่สุดในการสร้างคลาส ฉันชอบคำตอบนี้เพราะใกล้เคียงที่สุดที่จะชี้ให้เห็น
Nate CK

1
ไม่มีสิ่งที่เรียกว่าวิธีการใน C. โครงสร้างใน C เป็นข้อมูลเก่าธรรมดา มีตัวดำเนินการ = รองรับโดยค่าเริ่มต้น (ซึ่งคำตอบอื่น ๆ แสดงให้เห็นว่าเป็นเหตุผลในการทำเช่นนี้) แต่สิ่งนี้ทำให้เข้าใจผิดและส่วนใหญ่ใช้กับ C ++ ไม่ใช่ C
Jonathan Sternberg

3
@J Sternberg: "Method" เป็นเพียงวิธีคิดเกี่ยวกับรูทีนย่อยว่าเกี่ยวข้องกับข้อมูล "อ็อบเจ็กต์" ที่ส่งผลกระทบ คุณสามารถสร้าง "คลาส" ของ "ออบเจ็กต์" และ "วิธีการ" ที่ดำเนินการกับมันในภาษาซีได้อย่างแน่นอนภาษาไม่ได้กำหนดสิ่งดังกล่าวอย่างเป็นทางการ หากคุณต้องการสร้างสิ่งที่เป็นนามธรรมให้ดีขึ้นในภาษา C การใส่สิ่งต่างๆลงในโครงสร้างมักจะเป็นวิธีที่ดีที่สุด
Nate CK

นอกจากนี้หากคุณต้องการ "สร้าง" เมธอดใน C จริงๆคุณสามารถใช้ตัวชี้ฟังก์ชัน (ใช่ใช่ไวยากรณ์ที่ยุ่งยากไม่มีการปกป้องข้อมูล ฯลฯ ) เพื่อเชื่อมโยงฟังก์ชันกับข้อมูลที่ดำเนินการ คุณต้องส่ง "ตัวเอง" ในอาร์กิวเมนต์แรก (คุณสามารถตั้งชื่อมันว่า "นี่" ก็ได้ถ้าคุณต้องการ) เนื่องจากไม่มีการสร้างตัวชี้นี้โดยอัตโนมัติภายในฟังก์ชันใน C แน่นอนว่ามันเป็นยิมนาสติกทั้งหมดที่คุณได้รับ สิ่งนี้โดยค่าเริ่มต้นใน C ++ แม้ว่าจะเป็นเรื่องจริงที่อาจมีค่าใช้จ่ายซ่อนอยู่เป็นโบนัส ...
BenPen

2

ข้อดีอีกประการหนึ่งของการใช้ a ดังกล่าวstructคือการบังคับใช้ความปลอดภัยในทุกที่ที่ใช้เช่นstructนั้น โดยเฉพาะอย่างยิ่งถ้าคุณมีอาร์เรย์สองประเภทที่ประกอบด้วยอาร์เรย์ที่มีขนาดเท่ากันซึ่งใช้เพื่อวัตถุประสงค์ที่แตกต่างกันประเภทเหล่านี้จะช่วยให้คุณหลีกเลี่ยงการใช้อาร์เรย์อย่างไม่เหมาะสมโดยไม่ได้ตั้งใจ

หากคุณไม่รวมอาร์เรย์ไว้ใน a structคุณยังสามารถประกาศ a typedefได้ซึ่งมีข้อดีบางประการของstruct- •ประเภทจะถูกประกาศเพียงครั้งเดียวขนาดจะถูกต้องโดยอัตโนมัติ•เจตนาของรหัสจะชัดเจนขึ้น• และรหัสสามารถดูแลรักษาได้มากกว่า - แต่คุณสูญเสีย◦ความปลอดภัยของประเภทที่เข้มงวด◦ความสามารถในการคัดลอกและส่งคืนค่าของประเภทและ◦ความสามารถในการเพิ่มสมาชิกในภายหลังโดยไม่ทำลายส่วนที่เหลือของรหัส สองtypedefs สำหรับอาร์เรย์เปล่าของประเภทที่ระบุจะให้ผลเฉพาะประเภทที่แตกต่างกันหากมีขนาดต่างกัน ยิ่งไปกว่านั้นหากคุณใช้typedefโดยไม่มี*ในอาร์กิวเมนต์ฟังก์ชันจะเทียบเท่ากับchar *การลดความปลอดภัยของประเภทลงอย่างมาก

โดยสรุป :

typedef struct A_s_s { char m[113]; } A_s_t; // Full type safey, assignable
typedef char   A_c_t[113];                   // Partial type-safety, not assignable

A_s_t          v_s(void);     // Allowed
A_c_t          v_c(void);     // Forbidden

void           s__v(A_s_t);     // Type-safe, pass by value
void           sP_v(A_s_t *);   // Type-safe
void           c__v(A_c_t);     // UNSAFE, just means char * (GRRR!)
void           cP_v(A_c_t *);   // SEMI-safe, accepts any array of 113

1

โครงสร้างสามารถมีฟังก์ชันการเริ่มต้นอาร์เรย์คัดลอกและฟินิซึ่งเลียนแบบข้อดีบางประการของกระบวนทัศน์การจัดการหน่วยความจำ OOP ในความเป็นจริงมันง่ายมากที่จะขยายแนวคิดนี้ในการเขียนยูทิลิตี้การจัดการหน่วยความจำทั่วไป (โดยใช้โครงสร้าง sizeof () เพื่อให้ทราบว่ามีการจัดการกี่ไบต์) เพื่อจัดการโครงสร้างที่ผู้ใช้กำหนดเอง ฐานรหัสการผลิตอัจฉริยะจำนวนมากที่เขียนด้วย C ใช้สิ่งเหล่านี้อย่างหนักและโดยทั่วไปจะไม่ใช้อาร์เรย์เว้นแต่ขอบเขตจะอยู่ในพื้นที่มาก

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


สิ่งนี้ไม่ได้ตอบคำถามว่าเหตุใดจึงอาจใช้อาร์เรย์structที่มีเพียงอาร์เรย์
PJTraill
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.