พื้นหลัง
คำสั่งประกาศตัวแปรใน C ประกอบด้วยสามส่วนคือชื่อของตัวแปรมันพิมพ์ฐานและปรับปรุงประเภท (s)
การดัดแปลงประเภทมีสามประเภท:
- ตัวชี้
*
(คำนำหน้า) - Array
[N]
(postfix) - ฟังก์ชั่น
()
(postfix)- คุณสามารถระบุรายการอาร์กิวเมนต์ของฟังก์ชันภายใน parens แต่เพื่อความท้าทายนี้เราจะเพิกเฉยและลองใช้
()
(ซึ่งในทางเทคนิคหมายถึง "ฟังก์ชันสามารถใช้อาร์กิวเมนต์ชนิดใดก็ได้")
- คุณสามารถระบุรายการอาร์กิวเมนต์ของฟังก์ชันภายใน parens แต่เพื่อความท้าทายนี้เราจะเพิกเฉยและลองใช้
และวิธีในการอ่านเครื่องหมายเป็นดังนี้:
int i; // i is an int
float *f; // f is a pointer to a float
my_struct_t s[10]; // s is an array of 10 my_struct_t
int func(); // func is a function returning an int
สิ่งที่จับได้คือเราสามารถผสมสิ่งเหล่านี้เพื่อสร้างรูปแบบที่ซับซ้อนมากขึ้นเช่นอาร์เรย์ของอาร์เรย์หรืออาร์เรย์ของพอยน์เตอร์ของฟังก์ชันหรือตัวชี้ไปยังอาร์เรย์ของพอยน์เตอร์ :
int arr[3][4];
// arr is an array of 3 arrays of 4 ints
int (*fptrs[10])();
// fptrs is an array of 10 pointers to functions returning an int
float *(*p)[16];
// p is a pointer to an array of 16 pointers to float
ฉันอ่านข้อความที่ซับซ้อนเหล่านี้ได้อย่างไร
- เริ่มจากชื่อตัวแปร
(name) is ...
- เลือกตัวดัดแปลงที่มีลำดับความสำคัญสูงสุด
- อ่านมัน:
* -> pointer to ...
[N] -> array of N ...
() -> function returning ...
- ทำซ้ำ 2 และ 3 จนกระทั่งโมดิฟายเออร์หมด
- ในที่สุดอ่านประเภทฐาน
... (base type).
ใน C ตัวดำเนินการ postfix จะมีความสำคัญเหนือตัวดำเนินการส่วนนำหน้าและตัวดัดแปลงชนิดจะไม่มีข้อยกเว้น ดังนั้น[]
และผูกแรกแล้ว()
*
อะไรก็ตามที่อยู่ในคู่ของ parens (...)
(เพื่อไม่ให้สับสนกับโอเปอเรเตอร์ฟังก์ชั่น) จะผูกสิ่งแรกไว้ข้างนอก
ตัวอย่างที่แสดง:
int (*fptrs[10])();
fptrs fptrs is ...
[10] array of 10 ... // [] takes precedence over *
(* ) pointer to ...
() function returning ...
int int
งาน
ให้บรรทัดของคำแถลงการประกาศตัวแปรที่เขียนใน C เอาท์พุทนิพจน์ภาษาอังกฤษที่อธิบายบรรทัดโดยใช้วิธีการที่แสดงด้านบน
อินพุต
อินพุตเป็นคำสั่ง C เดียวที่มีชนิดฐานเดียวชื่อตัวแปรเดี่ยวตัวดัดแปลงชนิดศูนย์หรือมากกว่าและเซมิโคลอนลงท้าย คุณต้องใช้องค์ประกอบไวยากรณ์ทั้งหมดที่กล่าวถึงข้างต้นรวมถึง:
[A-Za-z_][A-Za-z0-9_]*
ทั้งพิมพ์ฐานและชื่อตัวแปรตรงกับการแสดงออกปกติ- ตามทฤษฎีแล้วโปรแกรมของคุณควรรองรับตัวดัดแปลงประเภทไม่ จำกัด จำนวน
คุณสามารถทำให้องค์ประกอบไวยากรณ์ C อื่น ๆ ง่ายขึ้นด้วยวิธีต่อไปนี้ (ยินดีต้อนรับการใช้งานอย่างเต็มรูปแบบ)
- ประเภทฐานอยู่เสมอคำเดียวเช่น
int
,float
, ,uint32_t
myStruct
บางอย่างเช่นunsigned long long
จะไม่ถูกทดสอบ - สำหรับโน้ตอาร์เรย์
[N]
จำนวนN
มักจะเป็นจำนวนเต็มบวกเดียวเขียนในฐาน 10. สิ่งที่ชอบint a[5+5]
,int a[SIZE]
หรือint a[0x0f]
จะไม่ได้รับการทดสอบ - สำหรับสัญกรณ์ฟังก์ชั่น
()
จะไม่มีการระบุพารามิเตอร์เลยตามที่กล่าวไว้ข้างต้น - สำหรับช่องว่าง
0x20
จะใช้อักขระช่องว่างเท่านั้น คุณสามารถ จำกัด โปรแกรมของคุณเฉพาะการใช้งานช่องว่างเช่น- ใช้เพียงหนึ่งช่องว่างหลังจากประเภทฐาน
- ใช้ช่องว่างทุกที่ระหว่างโทเค็น
- อย่างไรก็ตามคุณไม่สามารถใช้ช่องว่างต่อเนื่องตั้งแต่สองจุดขึ้นไปเพื่อถ่ายทอดข้อมูลมากกว่าการเป็นตัวคั่นโทเค็น
ตามไวยากรณ์ C ชุดค่าผสมสามชุดต่อไปนี้ไม่ถูกต้องและจะไม่ถูกทดสอบ:
f()()
ฟังก์ชันส่งคืนฟังก์ชันf()[]
ฟังก์ชันส่งคืนอาร์เรย์a[]()
ฟังก์ชัน Array of N
นักพัฒนา C ใช้แบบฟอร์มที่เทียบเท่าเหล่านี้แทน (และสิ่งเหล่านี้ครอบคลุมในกรณีทดสอบ):
(*f())()
ฟังก์ชันส่งคืนตัวชี้ไปยังฟังก์ชัน*f()
ฟังก์ชันส่งกลับตัวชี้ไปที่องค์ประกอบแรกของอาร์เรย์(*a[])()
Array of N พอยน์เตอร์ที่ใช้งานได้
เอาท์พุต
ผลลัพธ์เป็นประโยคภาษาอังกฤษเดียว คุณไม่จำเป็นต้อง (แต่คุณสามารถทำได้หากต้องการ) เคารพไวยากรณ์ภาษาอังกฤษเช่นการใช้a, an, the
แบบฟอร์มเอกพจน์ / พหูพจน์และจุดสิ้นสุด (จุด) แต่ละคำควรคั่นด้วยช่องว่างอย่างน้อยหนึ่งช่องว่าง (เว้นวรรคแท็บขึ้นบรรทัดใหม่) ดังนั้นผลลัพธ์จะอ่านได้โดยมนุษย์
อีกครั้งนี่คือกระบวนการแปลง:
- เริ่มจากชื่อตัวแปร
(name) is ...
- เลือกตัวดัดแปลงที่มีลำดับความสำคัญสูงสุด
- อ่านมัน:
* -> pointer to ...
[N] -> array of N ...
() -> function returning ...
- ทำซ้ำ 2 และ 3 จนกระทั่งโมดิฟายเออร์หมด
- ในที่สุดอ่านประเภทฐาน
... (base type).
กรณีทดสอบ
int i; // i is int
float *f; // f is pointer to float
my_struct_t s[10]; // s is array of 10 my_struct_t
int func(); // func is function returning int
int arr[3][4]; // arr is array of 3 array of 4 int
int (*fptrs[10])(); // fptrs is array of 10 pointer to function returning int
float *(*p)[16]; // p is pointer to array of 16 pointer to float
_RANdom_TYPE_123 (**(*_WTH_is_TH15)())[1234][567];
/* _WTH_is_TH15 is pointer to function returning pointer to pointer to array of
1234 array of 567 _RANdom_TYPE_123 */
uint32_t **(*(**(*(***p)[2])())[123])[4][5];
/* p is pointer to pointer to pointer to array of 2 pointer to function returning
pointer to pointer to array of 123 pointer to array of 4 array of 5 pointer to
pointer to uint32_t */
uint32_t (**((*(**(((*(((**(*p)))[2]))())))[123])[4])[5]);
// Same as above, just more redundant parens
some_type (*(*(*(*(*curried_func())())())())())();
/* curried_func is function returning pointer to function returning pointer to
function returning pointer to function returning pointer to
function returning pointer to function returning some_type */
เกณฑ์การให้คะแนนและการชนะ
นี่คือความท้าทายรหัส - กอล์ฟ โปรแกรมที่มีจำนวนไบต์น้อยที่สุดจะเป็นผู้ชนะ
int arr[3][4];
คือan array of 3 arrays of 4 ints
(ตามที่คุณพูด) หรือan array of 4 arrays of 3 ints
?
;
จุดสิ้นสุดของบรรทัดหรือไม่?