ไม่เข้าใจวิธีคำนวณกำลังสองของตัวเลขแบบนี้

ฉันพบฟังก์ชันที่คำนวณกำลังสองของตัวเลขแล้ว:

int p(int n) {
    int a[n]; //works on C99 and above
    return (&a)[n] - a;
}

ส่งกลับค่า n2 คำถามคือ มันทำแบบนั้นได้อย่างไร? หลังจากการทดสอบเล็กน้อย ฉันพบว่าระหว่าง (&a)[k] ถึง (&a)[k+1] คือ sizeof(a)/sizeof(int) ทำไมเป็นอย่างนั้น?


person Emanuel    schedule 07.01.2015    source แหล่งที่มา
comment
คุณมีลิงก์ไปยังที่ที่คุณพบข้อมูลนี้หรือไม่?   -  person R Sahu    schedule 08.01.2015
comment
int p(n)? นั่นมันคอมไพล์ด้วยเหรอ?   -  person barak manos    schedule 08.01.2015
comment
@barakmanos ครับ ideone.com/QRHvxf   -  person Paul Roub    schedule 08.01.2015
comment
@barakmanos มันคอมไพล์ได้ดีใน gcc   -  person lurker    schedule 08.01.2015
comment
เยี่ยมมาก ตอนนี้อย่าใช้มันอีกและใช้ n*n แทน...   -  person    schedule 08.01.2015
comment
หรือดีกว่า: int q(int n) { return sizeof (char [n][n]); }   -  person ouah    schedule 08.01.2015
comment
@ouah - นั่นเป็นคำตอบเดียวกับที่ฉันโพสต์ใน code Golf เมื่อปีที่แล้ว (codegolf.stackexchange.com/a/18283 /14485)   -  person Mark Lakata    schedule 08.01.2015
comment
ภาษา C สะท้อนถึงคุณสมบัติมากมายของ PDP-11 เช่น ตัวดำเนินการ ++/-- ตรงกับโหมดการกำหนดที่อยู่ ใน PDP และ [โดยเฉพาะ] VAX การดำเนินการทางคณิตศาสตร์ทุกประเภทสามารถดำเนินการได้โดยใช้โหมดการกำหนดแอดเดรส จึงเป็นที่มาของทริคแบบนี้   -  person user3344003    schedule 08.01.2015
comment
ดูเหมือนว่าจะมาจากการประกวดโค้ด C ที่เป็นความลับ ไม่เคยทำสิ่งนั้นในโค้ดที่ใช้งานจริง!   -  person Arne Burmeister    schedule 08.01.2015
comment
@ouah สมมติว่าคำถามนี้อ้างถึง codegolf.stackexchange.com/a/43262/967 เหตุผลที่ฉันไม่ทำ ใช้ sizeof คือการบันทึกอักขระ คนอื่นๆ: นี่เป็นโค้ดที่คลุมเครือโดยเจตนา มันเป็นพฤติกรรมที่ไม่ได้กำหนดไว้ คำตอบของ @ouah นั้นถูกต้อง   -  person ecatmur    schedule 08.01.2015
comment
เลขคณิตของพอยน์เตอร์ในโค้ดนี้เรียกใช้พฤติกรรมที่ไม่ได้กำหนดไว้   -  person Rufflewind    schedule 08.01.2015
comment
มันจะมีโอกาสล้นน้อยลงเล็กน้อยหากอาร์เรย์เป็นประเภท char แทนที่จะเป็น int   -  person Adrian McCarthy    schedule 08.01.2015
comment
นี่คือมังกร: การได้รับพอยน์เตอร์นอกขอบเขตอาเรย์ (ยกเว้นหนึ่งตำแหน่งหลังจากสุดท้าย) ถือเป็น พฤติกรรมที่ไม่ได้กำหนด แม้ว่าคุณจะไม่ได้ปฏิบัติตามก็ตาม   -  person bolov    schedule 09.01.2015
comment
สิ่งนี้จะไม่กินหน่วยความจำเมื่อคุณใช้ค่า n จำนวนมากแม้ว่าจะเพียงชั่วขณะหนึ่งก็ตาม   -  person Octopus    schedule 09.01.2015
comment
ดี. A O(n^2) เพื่อคำนวณ n^2   -  person Khaled.K    schedule 14.01.2015


คำตอบ (5)


แน่นอนว่าเป็นการแฮ็ก... แต่เป็นวิธีการยกกำลังสองตัวเลขโดยไม่ใช้ตัวดำเนินการ * (นี่คือข้อกำหนดของการแข่งขันเขียนโค้ด)

(&a)[n] 

เทียบเท่ากับตัวชี้ไปที่ int ที่ตำแหน่ง

(a + sizeof(a[n])*n)

และด้วยเหตุนี้สำนวนทั้งหมดจึงเป็นเช่นนั้น

  (&a)[n] -a 

= (a + sizeof(a[n])*n -a) /sizeof(int)

= sizeof(a[n])*n / sizeof(int)
= sizeof(int) * n * n / sizeof(int)
= n * n
person Mark Lakata    schedule 07.01.2015
comment
และตามที่คุณบอกเป็นนัยอย่างชัดเจน แต่ฉันรู้สึกว่าจำเป็นต้องทำให้ชัดเจน มันเป็นการแฮ็กไวยากรณ์ที่ดีที่สุด การดำเนินการทวีคูณจะยังคงอยู่ด้านล่าง เป็นเพียงผู้ดำเนินการที่ถูกหลีกเลี่ยง - person Tommy; 08.01.2015
comment
ฉันได้รับสิ่งที่เกิดขึ้นเบื้องหลัง แต่คำถามที่แท้จริงของฉันคือทำไม (&a)[k] ถึงอยู่เดียวกันกับ a + k * sizeof(a) / sizeof(int) - person Emanuel; 08.01.2015
comment
ในฐานะผู้เขียนโค้ดเก่า ฉันรู้สึกประหลาดใจกับความจริงที่ว่าคอมไพเลอร์สามารถถือว่า (&a) เป็นตัวชี้ไปยังอ็อบเจ็กต์ n*sizeof(int) เมื่อ n ไม่เป็นที่รู้จักในเวลาคอมไพล์ C เคยเป็นภาษา ง่าย... - person Floris; 08.01.2015
comment
นั่นเป็นแฮ็คที่ฉลาดทีเดียว แต่เป็นสิ่งที่คุณคงไม่เห็นในโค้ดที่ใช้งานจริง (หวังว่า) - person John Odom; 08.01.2015
comment
นอกจากนั้น ยังเป็น UB อีกด้วย เนื่องจากจะเพิ่มตัวชี้เพื่อไม่ให้ชี้ไปที่องค์ประกอบของอาร์เรย์ที่อยู่ภายใต้หรือเพิ่งผ่านไป - person Deduplicator; 08.01.2015
comment
@Floris: แน่นอนและสิ่งนี้ (อีกสองสามอย่าง) ทำให้มีเหตุผลที่ชัดเจนมากว่าทำไมผู้คนจำนวนมากยังคงยึดติดกับ C90 แม้กระทั่งทุกวันนี้ - person alecov; 08.01.2015
comment
@haccks - สิ่งนี้นำมาจากความท้าทายของ codegolf ในการเขียนฟังก์ชันที่ยกกำลังสองตัวเลขโดยไม่ต้องใช้สัญลักษณ์ * ในโค้ด คุณสามารถตัดสินใจได้ว่านั่นหมายความว่าอย่างไร มันเป็นความท้าทายที่โง่เขลา - person Mark Lakata; 09.01.2015
comment
@MarkLakata; ตัวดำเนินการ * มีมากกว่าหนึ่งความหมายในภาษา C คุณควรระบุเฉพาะเกี่ยวกับตัวดำเนินการ การคูณ เมื่อมองแวบแรก ฉันคิดว่าคุณกำลังพูดถึงตัวดำเนินการทางอ้อมแต่ก็เข้าใจเมื่อเข้าไปที่ลิงก์ - person haccks; 09.01.2015
comment
และที่สำคัญกว่านั้น มันไม่ได้กำจัดการคูณ แต่เพียงทำให้คอมไพเลอร์ซ่อนมันจากคุณ วิธีแก้ปัญหาที่ตรงไปตรงมามากกว่าคือการเขียนฟังก์ชันที่จำลองเลขฐานสองที่ง่ายที่สุดคูณด้วย shift และเพิ่ม - person ddyer; 14.01.2015

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

เมื่อลบพอยน์เตอร์ตัวหนึ่งออกจากอีกพอยน์เตอร์ ผลลัพธ์ที่ได้คือระยะห่าง (วัดในองค์ประกอบอาร์เรย์) ระหว่างพอยน์เตอร์เหล่านั้น ดังนั้น หาก p ชี้ไปที่ a[i] และ q ชี้ไปที่ a[j] ดังนั้น p - q จะเท่ากับ i - j

C11: 6.5.6 ตัวดำเนินการบวก (p9):

เมื่อลบพอยน์เตอร์สองตัว ทั้งสองจะชี้ไปที่องค์ประกอบของออบเจ็กต์อาร์เรย์เดียวกัน หรือหนึ่งตัวเลยองค์ประกอบสุดท้ายของออบเจ็กต์อาร์เรย์ ผลลัพธ์คือความแตกต่างของตัวห้อยขององค์ประกอบอาร์เรย์ทั้งสอง [...].
กล่าวอีกนัยหนึ่ง หากนิพจน์ P และ Q ชี้ไปที่องค์ประกอบ i-th และ j-th ของออบเจ็กต์อาร์เรย์ ตามลำดับ นิพจน์ (P)-(Q) จะมีค่า i−j โดยให้ค่าพอดีกับวัตถุประเภท ptrdiff_t

ตอนนี้ฉันคาดหวังว่าคุณจะทราบถึงการแปลงชื่ออาร์เรย์เป็นตัวชี้ a แปลงเป็นตัวชี้เป็นองค์ประกอบแรกของอาร์เรย์ a &a คือที่อยู่ของบล็อกหน่วยความจำทั้งหมด กล่าวคือ เป็นที่อยู่ของอาร์เรย์ a รูปด้านล่างจะช่วยให้คุณเข้าใจ (อ่าน คำตอบนี้ สำหรับคำอธิบายโดยละเอียด):

ป้อนคำอธิบายรูปภาพที่นี่

นี่จะช่วยให้คุณเข้าใจว่าเหตุใด a และ &a จึงมีที่อยู่เดียวกัน และ (&a)[i] เป็นที่อยู่ของอาร์เรย์ที่ ith อย่างไร (ที่มีขนาดเท่ากับของ a)

ดังนั้นแถลงการณ์

return (&a)[n] - a; 

เทียบเท่ากับ

return (&a)[n] - (&a)[0];  

และความแตกต่างนี้จะให้จำนวนองค์ประกอบระหว่างพอยน์เตอร์ (&a)[n] และ (&a)[0] ซึ่งเป็นอาร์เรย์ n แต่ละองค์ประกอบจาก n int องค์ประกอบ ดังนั้น องค์ประกอบอาร์เรย์ทั้งหมดคือ n*n = n2


หมายเหตุ:

C11: 6.5.6 ตัวดำเนินการบวก (p9):

เมื่อลบพอยน์เตอร์สองตัว ทั้งสองจะต้องชี้ไปที่องค์ประกอบของออบเจ็กต์อาร์เรย์เดียวกัน หรือหนึ่งตัวเลยองค์ประกอบสุดท้ายของออบเจ็กต์อาร์เรย์; ผลลัพธ์คือความแตกต่างของตัวห้อยขององค์ประกอบอาร์เรย์ทั้งสอง ขนาดของผลลัพธ์เป็นแบบกำหนดการใช้งาน และประเภทของผลลัพธ์ (ประเภทจำนวนเต็มที่ลงนาม) คือ ptrdiff_t ที่กำหนดไว้ในส่วนหัว <stddef.h> หากผลลัพธ์ไม่สามารถแสดงในออบเจ็กต์ประเภทนั้นได้ แสดงว่าพฤติกรรมนั้นไม่ได้ถูกกำหนดไว้

เนื่องจาก (&a)[n] ไม่ได้ชี้ไปที่องค์ประกอบของออบเจ็กต์อาร์เรย์เดียวกันหรือไม่ได้ชี้ไปที่องค์ประกอบสุดท้ายของออบเจ็กต์อาร์เรย์ (&a)[n] - a จะเรียกใช้ พฤติกรรมที่ไม่ได้กำหนด

โปรดทราบว่าควรเปลี่ยนประเภทการส่งคืนของฟังก์ชัน p เป็น ptrdiff_t จะดีกว่า

person haccks    schedule 07.01.2015
comment
ทั้งสองจะชี้ไปที่องค์ประกอบของวัตถุอาเรย์เดียวกัน - ซึ่งทำให้เกิดคำถามสำหรับฉันว่าแฮ็คนี้ไม่ใช่ UB หรือไม่ นิพจน์ทางคณิตศาสตร์ของตัวชี้หมายถึงจุดสิ้นสุดสมมุติของวัตถุที่ไม่มีอยู่จริง: สิ่งนี้ได้รับอนุญาตด้วยซ้ำหรือไม่ - person Martin Ba; 08.01.2015
comment
โดยสรุป a คือที่อยู่ของอาร์เรย์ขององค์ประกอบ n ดังนั้น &a[0] จึงเป็นที่อยู่ขององค์ประกอบแรกในอาร์เรย์นี้ ซึ่งเหมือนกับ a; นอกจากนี้ &a[k] จะถือเป็นที่อยู่ของอาร์เรย์ขององค์ประกอบ n เสมอ โดยไม่คำนึงถึง k และเนื่องจาก &a[1..n] ก็เป็นเวกเตอร์เช่นกัน ตำแหน่งขององค์ประกอบจะต่อเนื่องกัน ซึ่งหมายถึงองค์ประกอบแรก อยู่ที่ตำแหน่ง x อันดับสองอยู่ที่ตำแหน่ง x + (จำนวนองค์ประกอบของเวกเตอร์ a ซึ่งก็คือ n) และอื่นๆ ฉันถูกไหม? นอกจากนี้ นี่คือพื้นที่ฮีป หมายความว่าถ้าฉันจัดสรรเวกเตอร์ใหม่ขององค์ประกอบ n เดียวกัน ที่อยู่ของมันจะเหมือนกับ (&a)[1] - person Emanuel; 08.01.2015
comment
@เอ็มมานูเอล; &a[k] เป็นที่อยู่ขององค์ประกอบที่ k ของอาร์เรย์ a (&a)[k] จะถือเป็นที่อยู่ของอาร์เรย์ขององค์ประกอบ k เสมอ ดังนั้น องค์ประกอบแรกอยู่ที่ตำแหน่ง a (หรือ &a) องค์ประกอบที่สองอยู่ที่ตำแหน่ง a + (จำนวนองค์ประกอบของอาร์เรย์ a ซึ่งก็คือ n)*(ขนาดขององค์ประกอบอาร์เรย์) และอื่นๆ และโปรดทราบว่าหน่วยความจำสำหรับอาร์เรย์ที่มีความยาวผันแปรได้จะถูกจัดสรรบนสแต็ก ไม่ใช่บนฮีป - person haccks; 08.01.2015
comment
@มาร์ตินบา; สิ่งนี้ได้รับอนุญาตด้วยซ้ำ ไม่ มันไม่ได้รับอนุญาต ยูบีของมัน ดูการแก้ไข - person haccks; 08.01.2015
comment
ดังนั้น (&a)[n]-(&a)[0] จะเป็นวิธีที่ถูกต้องในการทำเช่นนี้หรือไม่ - person Floris; 08.01.2015
comment
@ฟลอริส; หมายเลข (&a)[n] กำลังละเมิดกฎที่มาตรฐานระบุว่า: ทั้งคู่จะต้องชี้ไปที่องค์ประกอบของออบเจ็กต์อาร์เรย์เดียวกัน หรือหนึ่งรายการที่อยู่เลยองค์ประกอบสุดท้ายของออบเจ็กต์อาร์เรย์ คุณสามารถทำได้ในวิธีที่ถูกต้องโดยเปลี่ยนเนื้อหาของฟังก์ชันเป็น return sizeof (char [n][n]); ตามที่แนะนำใน ความคิดเห็นนี้ - person haccks; 08.01.2015
comment
@haccks เป็นความบังเอิญที่ดีระหว่างธรรมชาติของคำถามและชื่อเล่นของคุณ - person Dimitar Tsonev; 14.01.2015
comment
@DimitarTsonev; โอ้! ใช่ :) - person haccks; 14.01.2015
comment
ฉันคิดว่าฉันไม่เข้าใจว่าทำไมคุณถึงบอกว่าเรามีคุณสมบัติไม่ตรง ในกรณีนี้เรา ผ่านองค์ประกอบสุดท้ายของวัตถุอาร์เรย์ (องค์ประกอบสุดท้ายคือ (&a)[n-1] และเรากำลังถาม (&a)[n] ดังนั้นองค์ประกอบสุดท้ายคือ (&a)[n-1] ) - person Falanwe; 14.01.2015
comment
@ฟาลันเว; องค์ประกอบสุดท้ายคือ a[n-1] a[n] เป็นหนึ่งในองค์ประกอบสุดท้ายของอาร์เรย์ (&a)[1] เป็นตัวชี้ไปยังองค์ประกอบสุดท้าย (อาร์เรย์ของ n int) ของอาร์เรย์ - person haccks; 14.01.2015

a เป็นอาร์เรย์ (ตัวแปร) ของ n int

&a เป็นตัวชี้ไปยังอาร์เรย์ (ตัวแปร) ของ n int

(&a)[1] เป็นตัวชี้ของ int หนึ่ง int ที่ผ่านมาองค์ประกอบอาร์เรย์สุดท้าย ตัวชี้นี้คือ n int องค์ประกอบหลัง &a[0]

(&a)[2] เป็นตัวชี้ของ int หนึ่ง int ที่ผ่านมาองค์ประกอบอาร์เรย์สุดท้ายของสองอาร์เรย์ ตัวชี้นี้คือองค์ประกอบ 2 * n int หลัง &a[0]

(&a)[n] เป็นตัวชี้ของ int หนึ่ง int ที่ผ่านมาองค์ประกอบอาร์เรย์สุดท้ายของอาร์เรย์ n ตัวชี้นี้คือ n * n int องค์ประกอบหลัง &a[0] เพียงลบ &a[0] หรือ a แล้วคุณจะได้ n

แน่นอนว่านี่เป็นพฤติกรรมที่ไม่ได้กำหนดในทางเทคนิคแม้ว่าจะทำงานบนเครื่องของคุณเนื่องจาก (&a)[n] ไม่ได้ชี้ภายในอาร์เรย์หรือหนึ่งจุดผ่านองค์ประกอบอาร์เรย์สุดท้าย (ตามที่กำหนดโดยกฎ C ของเลขคณิตของตัวชี้)

person ouah    schedule 07.01.2015
comment
ฉันเข้าใจแล้ว แต่ทำไมสิ่งนี้ถึงเกิดขึ้นใน C? เหตุผลเบื้องหลังเรื่องนี้คืออะไร? - person Emanuel; 08.01.2015
comment
@Emanuel ไม่มีคำตอบที่เข้มงวดไปกว่านั้นจริง ๆ แล้วเลขคณิตของตัวชี้นั้นมีประโยชน์สำหรับการวัดระยะทาง (โดยปกติจะอยู่ในอาร์เรย์) [n] ไวยากรณ์จะประกาศอาร์เรย์และอาร์เรย์จะสลายตัวเป็นพอยน์เตอร์ ประโยชน์สามประการที่แยกจากกันพร้อมกับผลที่ตามมานี้ - person Tommy; 08.01.2015
comment
@Emanuel หากคุณถาม ทำไม บางคนถึงทำเช่นนี้ มีเหตุผลเพียงเล็กน้อยและทุกเหตุผลที่ ไม่ เนื่องจากลักษณะของการกระทำของ UB และเป็นที่น่าสังเกตว่า (&a)[n] เป็นประเภท int[n] และ นั้น แสดงเป็น int* เนื่องจากอาร์เรย์แสดงเป็นที่อยู่ขององค์ประกอบแรก ในกรณีที่คำอธิบายไม่ชัดเจน - person WhozCraig; 08.01.2015
comment
ไม่ ฉันไม่ได้หมายความว่าทำไมบางคนถึงทำเช่นนี้ ฉันหมายถึงว่าทำไมมาตรฐาน C ถึงมีพฤติกรรมเช่นนี้ในสถานการณ์เช่นนี้ - person Emanuel; 08.01.2015
comment
@Emanuel Pointer Arithmetic (และในกรณีนี้คือบทย่อยของหัวข้อนั้น: ความแตกต่างของตัวชี้) มันคุ้มค่าที่จะลองอ่านคำถามและคำตอบบนเว็บไซต์นี้ มีคุณประโยชน์มากมายและมีการกำหนดไว้อย่างเป็นรูปธรรมในมาตรฐานเมื่อใช้อย่างเหมาะสม เพื่อที่จะเข้าใจอย่างถ่องแท้ คุณ มี ที่จะเข้าใจว่า ประเภท ในโค้ดที่คุณระบุไว้นั้นถูกสร้างขึ้นมาอย่างไร - person WhozCraig; 08.01.2015

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

int a[10];

int *p1 = &a[1];
int *p2 = &a[3];

printf( "%d\n", p2 - p1 ); 

ตอนนี้ให้พิจารณาการแสดงออก

(&a)[n] - a;

ในนิพจน์นี้ a มีประเภท int * และชี้ไปที่องค์ประกอบแรก

นิพจน์ &a มีประเภท int ( * )[n] และชี้ไปที่แถวแรกของอาร์เรย์สองมิติที่อิมเมจ ค่าของมันตรงกับค่าของ a แม้ว่าประเภทจะแตกต่างกันก็ตาม

( &a )[n]

เป็นองค์ประกอบที่ n ของอาร์เรย์สองมิติที่ทำอิมเมจนี้ และมีประเภท int[n] นั่นคือแถวที่ n ของอาร์เรย์อิมเมจ ในนิพจน์ (&a)[n] - a จะถูกแปลงเป็นที่อยู่ขององค์ประกอบแรกและมีประเภท `int *

ดังนั้นระหว่าง (&a)[n] ถึง a จะมี n แถวที่มี n องค์ประกอบ ดังนั้นผลต่างจะเท่ากับ n * n

person Vlad from Moscow    schedule 07.01.2015
comment
ดังนั้นด้านหลังทุกอาร์เรย์จะมีเมทริกซ์ขนาด n*n ใช่ไหม? - person Emanuel; 08.01.2015
comment
@Emanuel ระหว่างพอยน์เตอร์สองตัวนี้มีเมทริกซ์ขององค์ประกอบ n xn และความแตกต่างของพอยน์เตอร์ให้ค่าเท่ากับ n * n นั่นคือจำนวนองค์ประกอบที่อยู่ระหว่างพอยน์เตอร์ - person Vlad from Moscow; 08.01.2015
comment
แต่ทำไมเมทริกซ์ขนาด n*n นี้ถึงอยู่ข้างหลัง? มันมีประโยชน์ในภาษา C หรือไม่? ฉันหมายความว่ามันเหมือนกับว่า C จัดสรรอาร์เรย์ขนาด n มากขึ้นโดยที่ฉันไม่รู้เหรอ? ถ้าเป็นเช่นนั้น ฉันสามารถใช้มันได้หรือไม่? มิฉะนั้น เหตุใดเมทริกซ์นี้จึงถูกสร้างขึ้น (ฉันหมายถึง มันต้องมีจุดประสงค์เพื่อให้มันอยู่ที่นั่น) - person Emanuel; 08.01.2015
comment
@Emanuel - เมทริกซ์นี้เป็นเพียงคำอธิบายว่าเลขคณิตของตัวชี้ทำงานอย่างไรในกรณีนี้ เมทริกซ์นี้ไม่ได้รับการจัดสรรและคุณไม่สามารถใช้งานได้ เช่นเดียวกับที่กล่าวไว้แล้วสองสามครั้ง 1) ข้อมูลโค้ดนี้เป็นแฮ็กที่ไม่มีการใช้งานจริง; 2) คุณต้องเรียนรู้ว่าเลขคณิตของพอยน์เตอร์ทำงานอย่างไรเพื่อที่จะเข้าใจแฮ็คนี้ - person void_ptr; 08.01.2015
comment
@Emanuel สิ่งนี้จะอธิบายเลขคณิตของพอยน์เตอร์ Expresion ( &a )[n] เป็นตัวชี้ไปยังองค์ประกอบของ n- ของอาร์เรย์สองมิติที่ถ่ายภาพเนื่องจากเลขคณิตของตัวชี้ - person Vlad from Moscow; 08.01.2015

Expression     | Value                | Explanation
a              | a                    | point to array of int elements
a[n]           | a + n*sizeof(int)    | refer to n-th element in array of int elements
-------------------------------------------------------------------------------------------------
&a             | a                    | point to array of (n int elements array)
(&a)[n]        | a + n*sizeof(int[n]) | refer to n-th element in array of (n int elements array)
-------------------------------------------------------------------------------------------------
sizeof(int[n]) | n * sizeof(int)      | int[n] is a type of n-int-element array

ดังนั้น,

  1. ประเภท (&a)[n] คือตัวชี้ int[n]
  2. ประเภท a คือตัวชี้ int

ตอนนี้นิพจน์ (&a)[n]-a ทำการลบตัวชี้:

  (&a)[n]-a
= ((a + n*sizeof(int[n])) - a) / sizeof(int)
= (n * sizeof(int[n])) / sizeof(int)
= (n * n * sizeof(int)) / sizeof(int)
= n * n
person onlyice    schedule 14.01.2015