อาเรย์ต่อตัวชี้เสื่อมคืออะไร?


384

อาเรย์ต่อตัวชี้เสื่อมคืออะไร? มีความสัมพันธ์กับพอยน์เตอร์ของอาร์เรย์หรือไม่?


73
ไม่ค่อยมีใครรู้จัก: ตัวดำเนินการยูนารีบวกสามารถใช้เป็น "ตัวดำเนินการสลาย": ได้รับint a[10]; int b(void);จากนั้น+aเป็นตัวชี้ int และ+bเป็นตัวชี้ฟังก์ชั่น มีประโยชน์หากคุณต้องการส่งต่อให้แม่แบบที่ยอมรับการอ้างอิง
Johannes Schaub - litb

3
@litb - parens จะทำเช่นเดียวกัน (เช่น (a) ควรเป็นนิพจน์ที่ประเมินเป็นตัวชี้) ใช่ไหม
Michael Burr

21
std::decayจาก C ++ 14 จะเป็นวิธีที่คลุมเครือน้อยลงในการสลายอาร์เรย์ให้กับ +
ตำนาน 2k

21
@ JohannesSchaub-litb เนื่องจากคำถามนี้ติดแท็กทั้ง C และ C ++ ฉันต้องการชี้แจงว่าถึงแม้ว่า+aและ+bถูกกฎหมายใน C ++ มันผิดกฎหมายใน C (C11 6.5.3.3/1 "ตัวถูกดำเนินการของผู้ประกอบการ+หรือ-ผู้ประกอบการต้องมี ประเภทคณิตศาสตร์ ")
MM

5
@lege ด้านขวา แต่ฉันคิดว่านั่นไม่เป็นที่รู้จักกันน้อยเหมือนกลอุบายกับ unary + เหตุผลที่ฉันพูดถึงมันไม่เพียงเพราะมันสลายตัว แต่เพราะมันเป็นเรื่องสนุกที่จะเล่นด้วย)
โยฮันเนส Schaub - litb

คำตอบ:


283

มันบอกว่าอาร์เรย์ "สลาย" เป็นตัวชี้ อาร์เรย์ C ++ ที่ประกาศเป็นint numbers [5]ไม่สามารถชี้ซ้ำได้เช่นคุณไม่สามารถพูดnumbers = 0x5a5aff23ได้ ที่สำคัญกว่าคำว่าการสลายตัวหมายถึงการสูญเสียประเภทและขนาด; numbersสลายไปint*โดยการสูญเสียข้อมูลมิติ (นับ 5) และประเภทไม่ได้int [5]อีกต่อไป ดูที่นี่สำหรับกรณีที่มีการสลายตัวไม่ได้เกิดขึ้น

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

สามวิธีในการส่งผ่านอาร์เรย์1 :

void by_value(const T* array)   // const T array[] means the same
void by_pointer(const T (*array)[U])
void by_reference(const T (&array)[U])

สองคนสุดท้ายจะให้sizeofข้อมูลที่เหมาะสมในขณะที่คนแรกจะไม่ได้เนื่องจากอาร์กิวเมนต์อาร์เรย์ได้สลายตัวที่จะได้รับมอบหมายให้พารามิเตอร์

1 ควรทราบค่าคงที่ของ U ณ เวลารวบรวม


8
การผ่านคุณค่าครั้งแรกเป็นอย่างไร
rlbond

10
by_value กำลังส่งตัวชี้ไปยังองค์ประกอบแรกของอาร์เรย์ ในบริบทของพารามิเตอร์ฟังก์ชั่นที่เป็นเหมือนT a[] T *aby_pointer กำลังผ่านสิ่งเดียวกันยกเว้นค่าตัวชี้ตอนนี้ผ่านการรับรองconstแล้ว หากคุณต้องการที่จะผ่านตัวชี้ไปยังอาร์เรย์ (เมื่อเทียบกับตัวชี้ไปยังองค์ประกอบแรกของอาร์เรย์) T (*array)[U]ไวยากรณ์คือ
John Bode

4
"ด้วยตัวชี้ที่ชัดเจนไปยังอาร์เรย์นั้น" - สิ่งนี้ไม่ถูกต้อง ถ้าaเป็นอาร์เรย์ของcharแล้วaเป็นประเภทchar[N]และจะสลายตัวไปchar*; แต่&aเป็นประเภทchar(*)[N]และจะไม่สลายตัว
Pavel Minaev

5
@ FredOverflow: ดังนั้นหากUการเปลี่ยนแปลงคุณไม่จำเป็นต้องจำไว้ว่าต้องเปลี่ยนมันในสองที่หรือเสี่ยงต่อข้อผิดพลาดเงียบ ... อิสระ!
การแข่งขัน Lightness ใน Orbit

4
"ถ้าคุณผ่านอาร์เรย์ตามค่าสิ่งที่คุณกำลังทำจริง ๆ คือการคัดลอกตัวชี้" ซึ่งไม่สมเหตุสมผลเพราะอาร์เรย์ไม่สามารถผ่านค่าตามช่วงเวลาได้
juanchopanza

103

โดยทั่วไปอาร์เรย์จะเหมือนกับตัวชี้ใน C / C ++ แต่ไม่มากนัก เมื่อคุณแปลงอาร์เรย์:

const int a[] = { 2, 3, 5, 7, 11 };

เป็นตัวชี้ (ซึ่งทำงานโดยไม่ต้องร่ายและดังนั้นจึงสามารถเกิดขึ้นโดยไม่คาดคิดในบางกรณี):

const int* p = a;

คุณสูญเสียความสามารถของsizeofโอเปอเรเตอร์ในการนับองค์ประกอบในอาร์เรย์:

assert( sizeof(p) != sizeof(a) );  // sizes are not equal

ความสามารถที่หายไปนี้เรียกว่า "ผุ"

สำหรับรายละเอียดเพิ่มเติมลองอ่านบทความนี้เกี่ยวกับการสลายตัวของอาเรย์


51
อาร์เรย์นั้นไม่เหมือนกับพอยน์เตอร์ พวกมันเป็นสัตว์ที่แตกต่างกันโดยสิ้นเชิง ในบริบทส่วนใหญ่อาร์เรย์สามารถได้รับการปฏิบัติเสมือนเป็นตัวชี้และตัวชี้สามารถได้รับการปฏิบัติเสมือนเป็นอาร์เรย์ แต่ใกล้เคียงกับที่พวกเขาได้รับ
John Bode

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

"ทำงานโดยไม่ต้องร่าย" หมายความว่า "เกิดขึ้นโดยปริยาย" เมื่อพูดถึงการแปลงประเภท
MM

47

นี่คือสิ่งที่มาตรฐานพูด (C99 6.3.2.1/3 - ตัวถูกดำเนินการอื่น - ค่าอาร์เรย์และผู้ออกแบบฟังก์ชั่น):

ยกเว้นเมื่อเป็นตัวถูกดำเนินการของตัวดำเนินการ sizeof หรือ unary & ตัวดำเนินการหรือเป็นสตริงตัวอักษรที่ใช้ในการเริ่มต้นอาร์เรย์นิพจน์ที่มีประเภท '' อาร์เรย์ประเภท '' ถูกแปลงเป็นนิพจน์ที่มีตัวชี้ชนิด '' เป็น พิมพ์ '' ที่ชี้ไปที่องค์ประกอบเริ่มต้นของวัตถุอาร์เรย์และไม่ใช่ค่า lvalue

ซึ่งหมายความว่าทุกครั้งที่มีการใช้ชื่ออาเรย์ในนิพจน์มันจะถูกแปลงเป็นตัวชี้ไปยังรายการที่ 1 ในอาเรย์โดยอัตโนมัติ

โปรดทราบว่าชื่อฟังก์ชั่นทำหน้าที่ในลักษณะที่คล้ายกัน แต่พอยน์เตอร์ของฟังก์ชั่นจะใช้งานน้อยกว่าและในแบบพิเศษที่ไม่ทำให้เกิดความสับสนมากเท่ากับการแปลงชื่ออาเรย์เป็นพอยน์เตอร์อัตโนมัติ

มาตรฐาน C ++ (การแปลง Array-to-pointer) จะทำให้ข้อกำหนดการแปลงเป็น (เหมืองที่เน้น)

ค่า lvalue หรือ rvalue ของประเภท "อาร์เรย์ของ NT" หรือ "อาร์เรย์ของขอบเขตที่ไม่รู้จักของ T" สามารถแปลงเป็นค่า rvalue ของประเภท "ตัวชี้ไปที่ต."

ดังนั้นการแปลงจึงไม่ต้องเกิดขึ้นเหมือนที่เคยทำใน C (ซึ่งจะทำให้ฟังก์ชั่นโอเวอร์โหลดหรือเทมเพลตตรงกันกับประเภทอาเรย์)

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


2
บรรทัดตัวอย่างของโค้ดคืออะไรซึ่งนิพจน์ "ที่มีประเภท 'array of type'" คือ "สตริงตัวอักษรที่ใช้ในการเริ่มต้นอาร์เรย์"
Garrett

4
char x[] = "Hello";@Garrett อาเรย์ของ 6 องค์ประกอบ"Hello"ไม่สลายตัว แทนที่จะxได้รับขนาดและองค์ประกอบของมันจะเริ่มต้นจากองค์ประกอบของ6 "Hello"
MM

30

"Decay" หมายถึงการแปลงโดยนัยของนิพจน์จากประเภทอาเรย์เป็นประเภทพอยน์เตอร์ ในบริบทส่วนใหญ่เมื่อคอมไพเลอร์เห็นการแสดงออกของอาร์เรย์มันจะแปลงประเภทของการแสดงออกจาก "อาร์เรย์องค์ประกอบ N ของ T" เป็น "ตัวชี้ไปที่ T" และตั้งค่าของการแสดงออกไปยังที่อยู่ขององค์ประกอบแรกของอาร์เรย์ . ข้อยกเว้นของกฎนี้คือเมื่ออาร์เรย์เป็นตัวถูกดำเนินการของsizeofหรือ&ตัวดำเนินการหรืออาร์เรย์เป็นตัวอักษรสตริงที่ใช้เป็นตัวเริ่มต้นในการประกาศ

สมมติว่ารหัสต่อไปนี้:

char a[80];
strcpy(a, "This is a test");

การแสดงออกaเป็นประเภท "อาร์เรย์ 80 องค์ประกอบของถ่าน" และการแสดงออก "นี่คือการทดสอบ" เป็นประเภท "อาร์เรย์ 16 องค์ประกอบของถ่าน" (ใน C; ในตัวอักษร C สตริงสตริง C ++ เป็นอาร์เรย์ของ const ถ่าน) อย่างไรก็ตามในการเรียกไปยังstrcpy()นิพจน์ไม่ได้เป็นตัวถูกดำเนินการของsizeofหรือ&ดังนั้นประเภทของพวกเขาจะถูกแปลงโดยปริยายเป็น "ตัวชี้ไปยังถ่าน" และค่าของพวกเขาจะถูกตั้งค่าเป็นที่อยู่ขององค์ประกอบแรกในแต่ละ สิ่งที่strcpy()ได้รับไม่ใช่อาร์เรย์ แต่เป็นพอยน์เตอร์ดังที่เห็นในต้นแบบ:

char *strcpy(char *dest, const char *src);

สิ่งนี้ไม่เหมือนกับตัวชี้อาร์เรย์ ตัวอย่างเช่น:

char a[80];
char *ptr_to_first_element = a;
char (*ptr_to_array)[80] = &a;

ทั้งสองptr_to_first_elementและptr_to_arrayมีเดียวกันค่า ; ที่อยู่ฐานของ อย่างไรก็ตามมีหลายประเภทและได้รับการปฏิบัติต่างกันดังที่แสดงด้านล่าง:

a[i] == ptr_to_first_element[i] == (*ptr_to_array)[i] != *ptr_to_array[i] != ptr_to_array[i]

โปรดจำไว้ว่านิพจน์a[i]นั้นถูกตีความว่าเป็น*(a+i)(ซึ่งใช้ได้เฉพาะถ้าประเภทอาเรย์ถูกแปลงเป็นประเภทพอยน์เตอร์) ดังนั้นทั้งสองa[i]และptr_to_first_element[i]ทำงานเหมือนกัน การแสดงออกถูกตีความว่าเป็น(*ptr_to_array)[i] *(*a+i)การแสดงออก*ptr_to_array[i]และptr_to_array[i]อาจนำไปสู่คำเตือนหรือข้อผิดพลาดคอมไพเลอร์ขึ้นอยู่กับบริบท; a[i]แน่นอนพวกเขาจะทำในสิ่งที่ผิดถ้าคุณคาดหวังว่าพวกเขาจะประเมิน

sizeof a == sizeof *ptr_to_array == 80

อีกครั้งเมื่ออาร์เรย์เป็นตัวถูกดำเนินการsizeofจะไม่ถูกแปลงเป็นประเภทตัวชี้

sizeof *ptr_to_first_element == sizeof (char) == 1
sizeof ptr_to_first_element == sizeof (char *) == whatever the pointer size
                                                  is on your platform

ptr_to_first_element เป็นตัวชี้ง่าย ๆ ที่จะถ่าน


1
ไม่? (ความยาว 14 + 1 สำหรับ \ 0)"This is a test" is of type "16-element array of char""15-element array of char"
chux - Reinstate Monica

16

อาร์เรย์ใน C ไม่มีค่า

เมื่อใดก็ตามที่มีมูลค่าของวัตถุคาดว่า pointer to (type of array elements)แต่วัตถุที่เป็นอาร์เรย์ที่อยู่ขององค์ประกอบแรกของมันถูกนำมาใช้แทนมีประเภท

ในฟังก์ชั่นพารามิเตอร์ทั้งหมดจะถูกส่งผ่านโดยค่า (อาร์เรย์จะไม่มีข้อยกเว้น) เมื่อคุณผ่านอาร์เรย์ในฟังก์ชั่นมันจะ "สลายตัวเป็นพอยน์เตอร์" (sic); เมื่อคุณเปรียบเทียบอาร์เรย์กับสิ่งอื่น ๆ อีกครั้งมัน "สลายตัวเป็นตัวชี้" (sic); ...

void foo(int arr[]);

ฟังก์ชัน foo ต้องการค่าของอาร์เรย์ แต่ใน C อาร์เรย์ไม่มีค่า! ดังนั้นfooแทนที่จะได้รับที่อยู่ขององค์ประกอบแรกของอาร์เรย์

int arr[5];
int *ip = &(arr[1]);
if (arr == ip) { /* something; */ }

ในการเปรียบเทียบด้านบนarrไม่มีค่าดังนั้นมันจึงกลายเป็นตัวชี้ มันจะกลายเป็นตัวชี้ไปยัง int ตัวชี้นั้นสามารถเปรียบเทียบกับตัวแปรipได้

ในไวยากรณ์การจัดทำดัชนีอาร์เรย์ที่คุณเคยเห็นอีกครั้ง arr คือ 'decayed to ตัวชี้'

arr[42];
/* same as *(arr + 42); */
/* same as *(&(arr[0]) + 42); */

ครั้งเดียวที่อาร์เรย์ไม่สลายตัวลงในตัวชี้คือเมื่อเป็นตัวถูกดำเนินการของตัวดำเนินการ sizeof หรือตัวดำเนินการ & (ตัวดำเนินการ 'address of') หรือเป็นตัวอักษรสตริงที่ใช้ในการเริ่มต้นอาร์เรย์ตัวอักษร


5
"อาร์เรย์ไม่มีค่า" - สิ่งที่ควรจะหมายถึงอะไร ของอาร์เรย์แน่นอนมีค่า ... พวกเขากำลังวัตถุคุณสามารถมีคำแนะนำและใน C ++ อ้างอิงถึงพวกเขา ฯลฯ
พาเวล Minaev

2
ฉันเชื่ออย่างเคร่งครัดว่า "คุณค่า" ถูกกำหนดใน C เป็นการตีความบิตของวัตถุตามประเภท ฉันมีช่วงเวลาที่ยากลำบากในการหาความหมายที่เป็นประโยชน์ของสิ่งนั้นด้วยประเภทอาเรย์ คุณสามารถพูดได้ว่าคุณแปลงเป็นพอยน์เตอร์ แต่นั่นไม่ใช่การตีความเนื้อหาของอาเรย์มันเพิ่งจะได้ตำแหน่งของมัน สิ่งที่คุณได้รับคือค่าของตัวชี้ (และเป็นที่อยู่) ไม่ใช่ค่าของอาร์เรย์ (นี่คือ "ลำดับของค่าของรายการที่มีอยู่" ตามที่ใช้ในการกำหนด "string") ที่กล่าวว่าฉันคิดว่ามันยุติธรรมที่จะพูดว่า "มูลค่าของอาร์เรย์" เมื่อหนึ่งหมายความว่าตัวชี้ได้รับ
Johannes Schaub - litb

อย่างไรก็ตามฉันคิดว่ามีความคลุมเครือเล็กน้อย: ค่าของวัตถุและค่าของการแสดงออก (เช่นใน "rvalue") หากตีความวิธีหลังสุดแล้วนิพจน์อาร์เรย์มีค่าแน่นอน: มันเป็นผลลัพธ์ที่เกิดจากการสลายตัวให้เป็นค่า rvalue และเป็นนิพจน์ตัวชี้ แต่ถ้าตีความทางเดิมแล้วแน่นอนว่าไม่มีความหมายที่มีประโยชน์สำหรับวัตถุอาร์เรย์
Johannes Schaub - litb

1
+1 สำหรับวลีที่มีการแก้ไขเล็กน้อย สำหรับอาร์เรย์มันไม่ได้เป็น triplet เพียงเป็นคู่ [ตำแหน่งประเภท] คุณมีอย่างอื่นในใจสำหรับตำแหน่งที่สามในกรณีของอาร์เรย์หรือไม่ ฉันไม่สามารถคิดอะไรได้
legends2k

1
@ legends2k: ฉันคิดว่าฉันใช้ตำแหน่งที่สามในอาร์เรย์เพื่อหลีกเลี่ยงการทำให้เป็นกรณีพิเศษของการมีคู่เท่านั้น บางที [ตำแหน่ง, ประเภท, โมฆะ ] น่าจะดีกว่านี้
pmg

8

มันคือเมื่ออาร์เรย์ rots และถูกชี้ไปที่ ;-)

ที่จริงแล้วมันแค่นั้นถ้าคุณต้องการผ่านอาร์เรย์ที่ไหนสักแห่ง แต่ตัวชี้ถูกส่งแทน (เพราะผู้ที่จะผ่านอาร์เรย์ทั้งหมดสำหรับคุณ) ผู้คนบอกว่าอาร์เรย์ที่ไม่ดีผุพังไปยังตัวชี้


อย่างกล่าวว่า สิ่งที่จะเป็นอาร์เรย์ที่ดีที่ไม่สลายตัวไปยังตัวชี้หรือหนึ่งที่ถูกป้องกันจากการสลายตัว? คุณยกตัวอย่างใน C ได้ไหม? ขอบคุณ
Unheilig

@ Unheilig แน่นอนหนึ่งสามารถแพ็คสูญญากาศอาร์เรย์เป็น struct และผ่าน struct
Michael Krelin - แฮกเกอร์

ฉันไม่แน่ใจว่าคุณหมายถึงอะไรโดย "งาน" ไม่ได้รับอนุญาตให้เข้าถึงผ่านอาร์เรย์แม้ว่ามันจะทำงานได้ตามที่คาดไว้หากคุณคาดหวังว่าจะเกิดอะไรขึ้น พฤติกรรมนั้น (แม้ว่าอีกครั้งไม่ได้กำหนดอย่างเป็นทางการ) จะถูกรักษาไว้
Michael Krelin - แฮ็กเกอร์

การสลายตัวเกิดขึ้นในหลาย ๆ สถานการณ์ที่ไม่ได้ผ่านอาร์เรย์ไปทุกที่ (ตามที่อธิบายโดยคำตอบอื่น ๆ ) ตัวอย่างเช่นa + 1.
MM

3

Aray decaying หมายความว่าเมื่ออาเรย์ถูกส่งผ่านเป็นพารามิเตอร์ไปยังฟังก์ชันมันจะได้รับการปฏิบัติเหมือนกันกับ ("decays to") ตัวชี้

void do_something(int *array) {
  // We don't know how big array is here, because it's decayed to a pointer.
  printf("%i\n", sizeof(array));  // always prints 4 on a 32-bit machine
}

int main (int argc, char **argv) {
    int a[10];
    int b[20];
    int *c;
    printf("%zu\n", sizeof(a)); //prints 40 on a 32-bit machine
    printf("%zu\n", sizeof(b)); //prints 80 on a 32-bit machine
    printf("%zu\n", sizeof(c)); //prints 4 on a 32-bit machine
    do_something(a);
    do_something(b);
    do_something(c);
}

มีสองภาวะแทรกซ้อนหรือข้อยกเว้นข้างต้น

ก่อนเมื่อจัดการกับอาร์เรย์หลายมิติใน C และ C ++ เฉพาะมิติแรกเท่านั้นที่หายไป นี่เป็นเพราะอาร์เรย์ถูกจัดวางอย่างต่อเนื่องในหน่วยความจำดังนั้นคอมไพเลอร์ต้องรู้ทั้งหมดยกเว้นมิติแรกที่สามารถคำนวณ offsets ในบล็อกของหน่วยความจำนั้นได้

void do_something(int array[][10])
{
    // We don't know how big the first dimension is.
}

int main(int argc, char *argv[]) {
    int a[5][10];
    int b[20][10];
    do_something(a);
    do_something(b);
    return 0;
}

ประการที่สองใน C ++ คุณสามารถใช้เทมเพลตเพื่ออนุมานขนาดของอาร์เรย์ Microsoft ใช้สิ่งนี้สำหรับฟังก์ชั่น Secure CRT รุ่น C ++ เช่นstrcpy_sและคุณสามารถใช้เคล็ดลับที่คล้ายกันเพื่อให้ได้จำนวนองค์ประกอบในอาร์เรย์ที่เชื่อถือได้


1
การสลายตัวเกิดขึ้นในหลาย ๆ สถานการณ์ไม่ใช่แค่ส่งอาร์เรย์ไปยังฟังก์ชัน
MM

0

tl; dr: เมื่อคุณใช้อาร์เรย์ที่คุณกำหนดคุณจะใช้ตัวชี้ไปยังองค์ประกอบแรก

ดังนั้น:

  • เมื่อคุณเขียนarr[idx]คุณจริงๆเพียง *(arr + idx)แต่พูดว่า
  • ฟังก์ชั่นไม่เคยใช้อาร์เรย์เป็นพารามิเตอร์เพียงตัวชี้แม้เมื่อคุณระบุพารามิเตอร์อาร์เรย์

จัดเรียงข้อยกเว้นสำหรับกฎนี้:

  • structคุณสามารถส่งผ่านอาร์เรย์ความยาวคงที่ฟังก์ชั่นภายใน
  • sizeof() ให้ขนาดที่ถูกใช้โดยอาร์เรย์ไม่ใช่ขนาดของตัวชี้

0

ฉันอาจกล้าที่จะคิดว่ามีสี่ (4) วิธีในการส่งผ่านอาร์เรย์เป็นอาร์กิวเมนต์ของฟังก์ชัน นี่คือรหัสสั้น ๆ แต่ใช้งานได้สำหรับการตรวจของคุณ

#include <iostream>
#include <string>
#include <vector>
#include <cassert>

using namespace std;

// test data
// notice native array init with no copy aka "="
// not possible in C
 const char* specimen[]{ __TIME__, __DATE__, __TIMESTAMP__ };

// ONE
// simple, dangerous and useless
template<typename T>
void as_pointer(const T* array) { 
    // a pointer
    assert(array != nullptr); 
} ;

// TWO
// for above const T array[] means the same
// but and also , minimum array size indication might be given too
// this also does not stop the array decay into T *
// thus size information is lost
template<typename T>
void by_value_no_size(const T array[0xFF]) { 
    // decayed to a pointer
    assert( array != nullptr ); 
}

// THREE
// size information is preserved
// but pointer is asked for
template<typename T, size_t N>
void pointer_to_array(const T (*array)[N])
{
   // dealing with native pointer 
    assert( array != nullptr ); 
}

// FOUR
// no C equivalent
// array by reference
// size is preserved
template<typename T, size_t N>
void reference_to_array(const T (&array)[N])
{
    // array is not a pointer here
    // it is (almost) a container
    // most of the std:: lib algorithms 
    // do work on array reference, for example
    // range for requires std::begin() and std::end()
    // on the type passed as range to iterate over
    for (auto && elem : array )
    {
        cout << endl << elem ;
    }
}

int main()
{
     // ONE
     as_pointer(specimen);
     // TWO
     by_value_no_size(specimen);
     // THREE
     pointer_to_array(&specimen);
     // FOUR
     reference_to_array( specimen ) ;
}

ฉันอาจจะคิดว่าสิ่งนี้แสดงให้เห็นถึงความเหนือกว่าของ C ++ vs C อย่างน้อยก็ในการอ้างอิง (การตั้งใจเล่น) ของการส่งผ่านอาร์เรย์โดยการอ้างอิง

แน่นอนว่ามีโครงการที่เข้มงวดมากโดยไม่มีการจัดสรรฮีปไม่มีข้อยกเว้นและไม่มี std :: lib การจัดการอาเรย์เนทีฟแบบ C ++ เป็นภารกิจสำคัญทางภาษา

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