ตัวชี้ C คืออะไรถ้าไม่ใช่ที่อยู่หน่วยความจำ


206

ในแหล่งข้อมูลที่น่าเชื่อถือเกี่ยวกับ C ข้อมูลต่อไปนี้จะได้รับหลังจากพูดคุยกับ&ผู้ดำเนินการ:

... มันค่อนข้างโชคร้ายที่คำศัพท์[ที่อยู่ของ]ยังคงอยู่เพราะมันทำให้คนที่ไม่รู้ว่ากำลังพูดถึงเรื่องอะไรอยู่และทำให้คนที่หลงทางเข้าใจผิด: การคิดถึงพอยน์เตอร์ราวกับว่าพวกเขามักจะนำไปสู่ความเศร้าโศก ... .

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

ตอนนี้ผมกำลังสับสนเล็กน้อย - สิ่งที่ว่าเป็นตัวชี้แล้วหากไม่ได้อยู่หน่วยความจำ?

PS

ผู้เขียนกล่าวในภายหลังว่า: ... ฉันจะใช้คำว่า 'ที่อยู่' ต่อไปเนื่องจากการคิดค้นคำ [คำศัพท์] ที่ต่างออกไปจะยิ่งแย่กว่าเดิม


118
ตัวชี้เป็นตัวแปรที่เก็บที่อยู่ นอกจากนี้ยังมีที่อยู่ของตัวเอง นี่คือความแตกต่างพื้นฐานระหว่างตัวชี้และอาร์เรย์ อาร์เรย์มีประสิทธิภาพคือที่อยู่ (และโดยนัยแล้วที่อยู่ของมันคือตัวมันเอง )
WhozCraig

7
"แหล่งข้อมูลที่มีชื่อเสียง" ของคุณในการอ้างอิงคืออะไร
Cornstalks

22
แหล่งที่มาที่มีชื่อเสียงที่สุดคือมาตรฐานภาษาและไม่ใช่หนังสือกึ่งมาจากมันและกึ่งดึงจากผู้เขียน ฉันเรียนรู้วิธีที่ยากทำผิดพลาดเกือบทุกครั้งที่ฉันทำได้และค่อยๆสร้างแบบจำลองทางจิตของ C ค่อนข้างใกล้เคียงกับที่อธิบายไว้ในมาตรฐานและจากนั้นในที่สุดก็แทนที่แบบจำลองดังกล่าวด้วยแบบจำลองมาตรฐาน
Alexey Frunze

9
@thang ผู้คนคิดว่าตัวชี้ = จำนวนเต็มเพราะบ่อยครั้ง (x86 Linux และ Windows "สอน" เราว่า) เพราะคนชอบ generalizing เพราะคนไม่รู้จักมาตรฐานภาษาดีและเพราะพวกเขามีประสบการณ์แตกต่างกันเล็กน้อย แพลตฟอร์ม คนเดียวกันเหล่านั้นมีแนวโน้มที่จะสมมติว่าตัวชี้ไปยังข้อมูลและตัวชี้ไปยังฟังก์ชันสามารถแปลงเป็นอีกแบบหนึ่งและข้อมูลสามารถถูกเรียกใช้งานได้เนื่องจากรหัสและรหัสสามารถเข้าถึงได้เป็นข้อมูล แม้ว่าสิ่งนี้อาจเป็นจริงในสถาปัตยกรรม von Neuman (ด้วยพื้นที่ 1 ที่อยู่) แต่ไม่จำเป็นต้องเป็นจริงในสถาปัตยกรรม Harvard (w / โค้ดและพื้นที่ข้อมูล)
Alexey Frunze

6
@exebook มาตรฐานไม่ใช่สำหรับมือใหม่ (โดยเฉพาะอย่างยิ่งฉบับสมบูรณ์) พวกเขาไม่ควรให้คำแนะนำที่อ่อนโยนและตัวอย่างมากมาย พวกเขากำหนดสิ่งที่เป็นทางการเพื่อให้ผู้เชี่ยวชาญสามารถนำไปปฏิบัติได้อย่างถูกต้อง
Alexey Frunze

คำตอบ:


148

มาตรฐาน C ไม่ได้กำหนดสิ่งที่ตัวชี้คือภายในและวิธีการทำงานภายใน สิ่งนี้เป็นเจตนาเพื่อไม่ให้ จำกัด จำนวนแพลตฟอร์มซึ่ง C สามารถนำไปใช้เป็นภาษาที่รวบรวมหรือตีความได้

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


34
มีไม่มากที่จะอธิบาย ตัวแปรทุกตัวมีที่อยู่ในหน่วยความจำ แต่คุณไม่จำเป็นต้องเก็บที่อยู่ไว้ในพอยน์เตอร์ คุณสามารถกำหนดจำนวนตัวแปรจาก 1 เป็นค่าใดก็ได้และเก็บหมายเลขนั้นไว้ในตัวชี้ นั่นเป็นสิ่งที่ถูกกฎหมายอย่างสมบูรณ์ตามมาตรฐานภาษาตราบใดที่การใช้งานรู้วิธีแปลงตัวเลขเหล่านั้นเป็นที่อยู่และวิธีการคำนวณทางคณิตศาสตร์ด้วยตัวเลขเหล่านั้นและสิ่งอื่น ๆ ที่จำเป็นตามมาตรฐาน
Alexey Frunze

4
ฉันต้องการเพิ่มที่ x86 ที่อยู่หน่วยความจำประกอบด้วยตัวเลือกเซ็กเมนต์และออฟเซ็ตดังนั้นจึงแสดงถึงตัวชี้เป็นเซกเมนต์: ออฟเซ็ตยังคงใช้ที่อยู่หน่วยความจำ
Thang

6
@Lundin ฉันไม่มีปัญหาในการเพิกเฉยต่อลักษณะทั่วไปของมาตรฐานและไม่เหมาะสมเมื่อฉันรู้ว่าแพลตฟอร์มและคอมไพเลอร์ของฉัน อย่างไรก็ตามคำถามดั้งเดิมนั้นเป็นคำถามทั่วไปดังนั้นคุณจึงไม่สามารถเพิกเฉยต่อมาตรฐานเมื่อตอบคำถามได้
Alexey Frunze

8
@Lundin คุณไม่จำเป็นต้องเป็นนักปฏิวัติหรือนักวิทยาศาสตร์ สมมติว่าคุณต้องการเลียนแบบเครื่อง 32 บิตบนเครื่องจริง 16 บิตและคุณขยาย RAM 64KB ของคุณเป็น 4GB สูงสุดโดยใช้ที่เก็บข้อมูลดิสก์และใช้ตัวชี้ 32 บิตเป็นออฟเซ็ตเป็นไฟล์ขนาดใหญ่ พอยน์เตอร์เหล่านั้นไม่ใช่ที่อยู่หน่วยความจำจริง
Alexey Frunze

6
ตัวอย่างที่ดีที่สุดที่ฉันเคยเห็นคือการใช้งาน C สำหรับ Symbolics Lisp Machines (ประมาณปี 1990) แต่ละวัตถุ C ถูกนำมาใช้เป็นอาร์เรย์เสียงกระเพื่อมและตัวชี้ถูกนำมาใช้เป็นคู่ของอาร์เรย์และดัชนี เนื่องจากการตรวจสอบขอบเขตของ LISP ทำให้คุณไม่สามารถโอเวอร์โฟลว์จากวัตถุหนึ่งไปอีกวัตถุหนึ่งได้
Barmar

62

ฉันไม่แน่ใจเกี่ยวกับแหล่งที่มาของคุณ แต่ประเภทของภาษาที่คุณอธิบายมาจากมาตรฐาน C:

6.5.3.2 ที่อยู่และตัวดำเนินการทางอ้อม
[... ]
3. ผู้ดำเนินการ unary & ให้ผลตอบแทนที่อยู่ของตัวถูกดำเนินการ [ ... ]

ดังนั้น ... ใช่พอยน์เตอร์ชี้ไปยังที่อยู่หน่วยความจำ อย่างน้อยนั่นคือวิธีที่มาตรฐาน C แนะนำให้หมายความว่า

หากต้องการพูดให้ชัดเจนยิ่งขึ้นตัวชี้คือตัวแปรที่เก็บค่าที่อยู่บางแห่ง ที่อยู่ของวัตถุ (ซึ่งอาจถูกเก็บไว้ในตัวชี้) จะถูกส่งคืนพร้อม&ผู้ประกอบการเอก

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

แก้ไข:ฉันต้องการขยายความคิดเห็นของ Alexey Frunze

ตัวชี้คืออะไร ลองดูที่มาตรฐาน C:

6.2.5 ประเภท
[ ... ]
20 [ ... ] ประเภทตัวชี้อาจจะมาจากประเภทฟังก์ชั่นหรือชนิดของวัตถุที่เรียกว่าประเภทอ้างอิง ประเภทตัวชี้อธิบายวัตถุที่มีค่าให้การอ้างอิงไปยังเอนทิตีของประเภทอ้างอิง ชนิดตัวชี้ที่ได้มาจากชนิดที่อ้างอิง T บางครั้งเรียกว่า '' ตัวชี้ไปยัง T '' การสร้างประเภทตัวชี้จากประเภทที่อ้างอิงนั้นเรียกว่า '' pointer type pointer '' ประเภทตัวชี้เป็นประเภทวัตถุที่สมบูรณ์

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

6.3.2.3 พอยน์เตอร์
[... ]
5. จำนวนเต็มอาจถูกแปลงเป็นประเภทพอยน์เตอร์ใด ๆ ยกเว้นตามที่ระบุไว้ก่อนหน้านี้ผลที่ได้คือการใช้งานที่กำหนดไว้อาจไม่ได้รับการจัดตำแหน่งอย่างถูกต้องอาจไม่ชี้ไปที่เอนทิตีของประเภทที่อ้างอิงและอาจเป็นการแสดงกับดัก

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

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

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

ซึ่งจบลงด้วยความยาวกว่าที่ฉันคิดว่ามันจะเป็น ...


3
ในล่าม C ตัวชี้อาจเก็บ ID / หมายเลขอ้างอิง / ที่อยู่ที่ไม่ใช่ที่อยู่
Alexey Frunze

4
@exebook มาตรฐานไม่ได้ จำกัด อยู่ที่การรวบรวม C.
Alexey Frunze

7
@Lundin Bravo! มาเพิกเฉยต่อมาตรฐานมากขึ้น! ราวกับว่าเราไม่ได้เพิกเฉยมันเพียงพอแล้วและยังไม่ได้ผลิตซอฟต์แวร์พกพาที่ไม่ดีและไม่ดีเพราะมัน นอกจากนี้โปรดอย่าว่าคำถามดั้งเดิมนั้นเป็นคำถามทั่วไปและต้องการคำตอบทั่วไป
Alexey Frunze

3
เมื่อผู้อื่นพูดว่าตัวชี้อาจเป็นจุดจับหรืออย่างอื่นนอกเหนือจากที่อยู่ตัวชี้ไม่ได้หมายความว่าคุณสามารถบีบอัดข้อมูลลงในตัวชี้โดยการส่งจำนวนเต็มไปยังตัวชี้ ซึ่งหมายความว่าคอมไพเลอร์อาจใช้อย่างอื่นนอกเหนือจากที่อยู่หน่วยความจำเพื่อนำพอยน์เตอร์ไปใช้ บนโปรเซสเซอร์อัลฟ่าที่มี ABI ของ DEC ตัวชี้ฟังก์ชันไม่ใช่ที่อยู่ของฟังก์ชัน แต่เป็นที่อยู่ของตัวบ่งชี้ของฟังก์ชันและตัวอธิบายมีที่อยู่ของฟังก์ชันและข้อมูลบางอย่างเกี่ยวกับพารามิเตอร์ของฟังก์ชัน ประเด็นคือมาตรฐาน C มีความยืดหยุ่นมาก
Eric Postpischil

5
@Lundin: การยืนยันว่าตัวชี้ถูกนำไปใช้เป็นที่อยู่จำนวนเต็ม 100% ของระบบคอมพิวเตอร์ที่มีอยู่ในโลกแห่งความจริงเป็นเท็จ คอมพิวเตอร์มีอยู่ด้วยการกำหนดที่อยู่ของคำและการกำหนดที่อยู่ในส่วนออฟเซ็ต คอมไพเลอร์ยังคงมีอยู่ด้วยการสนับสนุนตัวชี้ใกล้และไกล มีคอมพิวเตอร์ PDP-11 พร้อม RSX-11 และตัวสร้างงานและการซ้อนทับซึ่งตัวชี้ต้องระบุข้อมูลที่จำเป็นในการโหลดฟังก์ชันจากดิสก์ ตัวชี้ไม่สามารถมีที่อยู่หน่วยความจำของวัตถุได้หากวัตถุไม่ได้อยู่ในหน่วยความจำ!
Eric Postpischil

39

ตัวชี้ vs ตัวแปร

ในรูปนี้,

pointer_p เป็นตัวชี้ซึ่งอยู่ที่ 0x12345 และชี้ไปที่ตัวแปร variable_v ที่ 0x34567


16
สิ่งนี้ไม่เพียง แต่ไม่ได้จัดการกับความคิดของที่อยู่ตรงข้ามกับตัวชี้เท่านั้น แต่ยังขาดจุดรวมที่อยู่ไม่ได้เป็นเพียงจำนวนเต็ม
Gilles 'SO- หยุดความชั่วร้าย'

19
-1 นี่แค่อธิบายว่าตัวชี้คืออะไร นั่นคือไม่ได้คำถามของและคุณกำลังผลักดันกันทุกซับซ้อนที่คำถามที่เป็นเรื่องเกี่ยวกับ
alexis

34

ที่จะคิดว่าตัวชี้เป็นที่อยู่เป็นประมาณ เช่นเดียวกับการประมาณทุกอย่างมันดีพอที่จะมีประโยชน์ในบางครั้ง แต่ก็ไม่แน่นอนซึ่งหมายความว่าการพึ่งพาอาศัยมันจะทำให้เกิดปัญหา

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

  • ที่อยู่ของวัตถุซึ่งสามารถอ้างอิงได้ (ถ้าpมีที่อยู่xแล้วนิพจน์*pจะมีค่าเหมือนกันx)
  • ชี้โมฆะซึ่งNULLเป็นตัวอย่าง;
  • เนื้อหาที่ไม่ถูกต้องซึ่งไม่ได้ชี้ไปที่วัตถุ (หากpไม่ถือค่าที่ถูกต้องจากนั้นก็*pสามารถทำอะไรก็ได้ (“ พฤติกรรมที่ไม่ได้กำหนด”) โดยทำให้โปรแกรมมีความเป็นไปได้ค่อนข้างธรรมดา

ยิ่งไปกว่านั้นมันจะมีความแม่นยำมากกว่าที่จะบอกว่าตัวชี้ (ถ้าถูกต้องและไม่เป็นโมฆะ) มีที่อยู่: ตัวชี้จะระบุตำแหน่งที่จะค้นหาวัตถุ แต่มีข้อมูลเพิ่มเติมผูกอยู่กับมัน

โดยเฉพาะอย่างยิ่งตัวชี้มีประเภท บนแพลตฟอร์มส่วนใหญ่ชนิดของตัวชี้จะไม่มีผลกับรันไทม์ แต่มีอิทธิพลที่เกินกว่าประเภทในเวลาคอมไพล์ ถ้าpเป็นตัวชี้ไปที่int( int *p;) แล้วp + 1ชี้ไปที่จำนวนเต็มซึ่งเป็นsizeof(int)ไบต์หลังจากp(สมมติว่าp + 1ยังคงเป็นตัวชี้ที่ถูกต้อง) ถ้าqเป็นตัวชี้ไปยังcharจุดที่ไปยังที่อยู่เดียวกับp( char *q = p;) แล้วไม่ได้เป็นเช่นเดียวกับที่อยู่q + 1 p + 1หากคุณคิดว่าตัวชี้เป็นที่อยู่มันไม่ง่ายนักที่“ ที่อยู่ถัดไป” นั้นแตกต่างกันไปสำหรับตัวชี้ที่แตกต่างกันไปยังที่ตั้งเดียวกัน

เป็นไปได้ในบางสภาพแวดล้อมที่จะมีค่าตัวชี้หลายค่าที่มีการแทนค่าที่แตกต่างกัน (รูปแบบบิตที่แตกต่างกันในหน่วยความจำ) ที่ชี้ไปยังตำแหน่งเดียวกันในหน่วยความจำ คุณสามารถคิดว่าสิ่งเหล่านี้เป็นตัวชี้ที่แตกต่างกันซึ่งมีที่อยู่เดียวกันหรือเป็นที่อยู่ที่แตกต่างกันสำหรับที่ตั้งเดียวกัน - คำอุปมาไม่ชัดเจนในกรณีนี้ ==ผู้ประกอบการมักจะบอกคุณว่าทั้งสองตัวถูกดำเนินการจะชี้ไปที่สถานที่เดียวกันดังนั้นในสภาพแวดล้อมเหล่านี้คุณสามารถมีp == qแม้ว่าpและqมีรูปแบบแตกต่างกันเล็กน้อย

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

มีสภาพแวดล้อมที่พอยน์เตอร์ชนิดต่าง ๆ มีการแสดงต่างกัน คุณคิดว่าเป็นที่อยู่ประเภทต่าง ๆ ที่มีการเป็นตัวแทนที่แตกต่างกัน ตัวอย่างเช่นสถาปัตยกรรมบางอย่างมีพอยน์เตอร์พอยน์เตอร์และพอยน์เตอร์พอยน์เตอร์, หรือพอยน์เตอร์พอยน์เตอร์และพอยน์เตอร์ของฟังก์ชัน

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

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

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

มีข้อ จำกัด ที่รู้จักกันดีอยู่ก่อน ตัวอย่างเช่นจำนวนเต็มที่กำหนดสถานที่นอกพื้นที่ที่อยู่ของโปรแกรมของคุณไม่สามารถเป็นตัวชี้ที่ถูกต้อง ที่อยู่ที่ไม่ถูกต้องไม่ทำให้ตัวชี้ที่ถูกต้องสำหรับประเภทข้อมูลที่ต้องมีการจัดตำแหน่ง ตัวอย่างเช่นบนแพลตฟอร์มที่intต้องการการจัดตำแหน่ง 4 ไบต์ 0x7654321 ไม่สามารถเป็นint*ค่าที่ถูกต้องได้

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

unsigned int x = 0;
unsigned short *p = (unsigned short*)&x;
p[0] = 1;
printf("%u = %u\n", x, *p);

คุณอาจคาดหวังได้ว่าบนเครื่องที่ทำงานที่ใดsizeof(int)==4และsizeof(short)==2สิ่งนี้จะพิมพ์1 = 1?(little-endian) หรือ65536 = 1?(big-endian) แต่บน Linux PC 64 บิตของฉันด้วย GCC 4.4:

$ c99 -O2 -Wall a.c && ./a.out 
a.c: In function main’:
a.c:6: warning: dereferencing pointer p does break strict-aliasing rules
a.c:5: note: initialized from here
0 = 1?

GCC ใจดีมากพอที่จะเตือนเราว่ามีอะไรผิดปกติในตัวอย่างง่ายๆนี้ - ในตัวอย่างที่ซับซ้อนกว่านี้คอมไพเลอร์อาจไม่สังเกตเห็น เนื่องจากpมีประเภทที่แตกต่างจาก&xการเปลี่ยนpจุดที่ไม่สามารถส่งผลกระทบต่อสิ่งที่&xชี้ไปที่ (นอกบางข้อยกเว้นที่กำหนดไว้อย่างดี) ดังนั้นคอมไพเลอร์มีอิสระในการรักษามูลค่าของxการลงทะเบียนและไม่ปรับปรุงการลงทะเบียนนี้เป็นการ*pเปลี่ยนแปลง โปรแกรมกำหนดตัวชี้สองตัวไปยังที่อยู่เดียวกันและรับค่าสองค่าที่แตกต่างกัน!

คุณธรรมของตัวอย่างนี้คือการคิดถึงตัวชี้ (ที่ไม่เป็นโมฆะ) เนื่องจากที่อยู่นั้นดีตราบใดที่คุณอยู่ในกฎที่ถูกต้องของภาษา C ด้านพลิกของเหรียญคือกฎของภาษา C มีความซับซ้อนและยากที่จะได้รับความรู้สึกที่ใช้งานง่ายเว้นแต่คุณจะรู้ว่าเกิดอะไรขึ้นภายใต้ประทุน และสิ่งที่เกิดขึ้นภายใต้ประทุนคือความสัมพันธ์ระหว่างพอยน์เตอร์และที่อยู่นั้นค่อนข้างหลวมทั้งเพื่อสนับสนุนสถาปัตยกรรมโพรเซสเซอร์ "แปลกใหม่" และเพื่อสนับสนุนการปรับแต่งคอมไพเลอร์ให้เหมาะสม

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


5
+1 คำตอบอื่น ๆ ดูเหมือนจะพลาดว่าตัวชี้มาพร้อมกับข้อมูลประเภท สิ่งนี้สำคัญกว่าที่อยู่ / ID / การสนทนาอะไรก็ตาม
undur_gongor

+1 คะแนนที่ยอดเยี่ยมเกี่ยวกับข้อมูลประเภท ฉันไม่แน่ใจว่าตัวอย่างคอมไพเลอร์นั้นถูกต้องแล้ว ... ดูเหมือนว่าไม่น่าเป็นไปได้มากตัวอย่างเช่น*p = 3นี้รับประกันได้ว่าจะประสบความสำเร็จเมื่อ p ไม่ได้เริ่มต้น
LarsH

@ LarsH คุณพูดถูกขอบคุณฉันจะเขียนได้อย่างไร ฉันแทนที่มันด้วยตัวอย่างที่แสดงให้เห็นถึงพฤติกรรมที่น่าประหลาดใจบนพีซีของฉัน
Gilles 'SO- หยุดความชั่วร้าย'

1
อืม NULL คือ ((เป็นโมฆะ *) 0) .. ?
Aniket Inge

1
@ gnasher729 ตัวชี้ null เป็นตัวชี้ NULLไม่ใช่ แต่สำหรับระดับรายละเอียดที่ต้องการที่นี่การเบี่ยงเบนความสนใจไม่เกี่ยวข้อง แม้สำหรับวันต่อวันการเขียนโปรแกรมความจริงที่ว่าNULLอาจจะถูกนำมาใช้เป็นสิ่งที่ไม่ได้พูดว่า“ชี้” ไม่ได้เกิดขึ้นบ่อยครั้ง (ส่วนใหญ่ผ่านNULLไปยังฟังก์ชัน variadic - แต่แม้มีถ้าคุณไม่ได้หล่อ คุณได้สมมุติว่าประเภทตัวชี้ทั้งหมดมีการแสดงเหมือนกัน)
Gilles 'หยุดความชั่วร้าย'

19

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

ตัวอย่างเช่น:

int q = 10; /*say q is at address 0x10203040*/
int *p = &q; /*means let p contain the address of q, which is 0x10203040*/
*p = 20; /*set whatever is at the address pointed by "p" as 20*/

แค่นั้นแหละ. มันง่ายมาก

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

โปรแกรมแสดงให้เห็นถึงสิ่งที่ฉันพูดและเอาท์พุทมันอยู่ที่นี่

http://ideone.com/rcSUsb

โปรแกรม:

#include <stdio.h>

int main(int argc, char *argv[])
{
  /* POINTER AS AN ADDRESS */
  int q = 10;
  int *p = &q;

  printf("address of q is %p\n", (void *)&q);
  printf("p contains %p\n", (void *)p);

  p = NULL;
  printf("NULL p now contains %p\n", (void *)p);
  return 0;
}

5
มันสามารถสร้างความสับสนมากยิ่งขึ้น อลิซคุณเห็นแมวไหม ไม่ฉันเห็นรอยยิ้มของแมวได้เท่านั้น ดังนั้นการบอกว่าตัวชี้นั้นเป็นที่อยู่หรือตัวชี้เป็นตัวแปรที่เก็บที่อยู่หรือบอกว่าตัวชี้นั้นเป็นชื่อของแนวคิดที่อ้างอิงถึงแนวคิดของที่อยู่
exebook

@ exebook สำหรับผู้ที่มีประสบการณ์ในพอยน์เตอร์มันค่อนข้างง่าย บางทีรูปภาพอาจช่วยได้?
Aniket Inge

5
ตัวชี้ไม่จำเป็นต้องเก็บที่อยู่ ในล่าม C มันอาจเป็นอย่างอื่น ID / หมายเลขอ้างอิงบางชนิด
Alexey Frunze

"label" หรือชื่อตัวแปรเป็นคอมไพเลอร์ / แอสเซมเบลอร์และไม่มีอยู่ที่ระดับเครื่องดังนั้นฉันไม่คิดว่ามันควรจะปรากฏในหน่วยความจำ
Ben

1
@Aniket ตัวแปรตัวชี้สามารถมีค่าตัวชี้ คุณจะต้องเก็บผลลัพธ์fopenไว้ในตัวแปรเท่านั้นหากคุณต้องการใช้มันมากกว่าหนึ่งครั้ง (ซึ่ง, สำหรับfopen, ค่อนข้างสวยตลอดเวลา)
Gilles 'ดังนั้น - หยุดความชั่วร้าย'

16

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

ตัดสินจากคำตอบทั้งหมดที่เขียนบางคนคิดว่า (1) ที่อยู่จะต้องเป็นจำนวนเต็มและ (2) ตัวชี้ไม่จำเป็นต้องเป็นเสมือนที่ไม่ได้กล่าวถึงในข้อกำหนด ด้วยสมมติฐานเหล่านี้ตัวชี้อย่างชัดเจนจึงไม่จำเป็นต้องมีที่อยู่

อย่างไรก็ตามเราเห็นว่าในขณะที่ (2) อาจเป็นจริง (1) อาจไม่จำเป็นต้องเป็นจริง และจะทำอย่างไรกับข้อเท็จจริงที่ & เรียกว่าที่อยู่ของผู้ประกอบการตาม @ CornStalks คำตอบ? นี่หมายความว่าผู้เขียนสเปคตั้งใจให้พอยน์เตอร์มีที่อยู่หรือไม่?

เราสามารถพูดได้ว่าตัวชี้ประกอบด้วยที่อยู่ แต่ที่อยู่ไม่จำเป็นต้องเป็นจำนวนเต็ม? อาจจะ.

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

ฉันคิดว่าสิ่งที่ผู้เขียนหนังสือเล่มนี้ (ข้อความที่ตัดตอนครั้งแรกที่อ้างว่าตัวชี้ไม่จำเป็นต้องเป็นที่อยู่เท่านั้น) อาจหมายถึงความจริงที่ว่าตัวชี้มาพร้อมกับข้อมูลประเภทโดยธรรมชาติ

ตัวอย่างเช่น,

 int x;
 int* y = &x;
 char* z = &x;

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

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

55555 อาจไม่ใช่ตัวชี้ถึงแม้ว่ามันอาจเป็นที่อยู่ แต่ (int *) 55555 เป็นตัวชี้ 55555 + 1 = 55556 แต่ (int *) 55555 + 1 คือ 55559 (+/- ความแตกต่างในแง่ของขนาดของ (int))


1
+1 สำหรับการชี้ทางคณิตศาสตร์พอยน์เตอร์ไม่เหมือนกับเลขคณิตของที่อยู่
kutschkem

ในกรณีของ 16-bit 8086 ที่อยู่หน่วยความจำจะถูกอธิบายโดยส่วนฐาน + ชดเชยทั้ง 16 บิต มีการรวมกลุ่มของเซ็กเมนต์ + ออฟเซ็ตมากมายที่ให้ที่อยู่เดียวกันในหน่วยความจำ นี้farชี้ไม่ได้เป็นเพียง "จำนวนเต็ม"
vonbrand

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

@tang ความคิด "ชี้ == อยู่" คือการที่ไม่ถูกต้อง ที่ทุกคนและป้าคนโปรดของพวกเขาพูดต่อไปว่าอย่าทำให้ถูกต้อง
vonbrand

@ vonbrand และทำไมคุณถึงแสดงความคิดเห็นในโพสต์ของฉัน ฉันไม่ได้บอกว่ามันถูกหรือผิด ในความเป็นจริงมันถูกต้องในบางสถานการณ์ / สมมติฐาน แต่ไม่เสมอไป ฉันขอสรุปจุดโพสต์อีกครั้ง (เป็นครั้งที่สอง) จุดทั้งหมดของฉันในคำตอบคือมันไม่เกี่ยวข้อง มันเป็นแค่เรื่องอื้อฉาวและประเด็นหลักไม่ได้รับการแก้ไขในคำตอบอื่น ๆ มันจะเหมาะสมกว่าที่จะแสดงความคิดเห็นในคำตอบที่จะทำให้การเรียกร้องที่ชี้ == ที่อยู่หรือที่อยู่ == จำนวนเต็ม ดูความคิดเห็นของฉันภายใต้โพสต์ของ Alexey เกี่ยวกับกลุ่ม: offset
ท้อง

15

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

แหล่งที่มาของความเศร้าที่เป็นไปได้มากที่สุดคือตัวชี้ทางคณิตศาสตร์ซึ่งเป็นจุดแข็งของ C หากตัวชี้เป็นที่อยู่คุณจะคาดหวังให้ตัวชี้เลขคณิตเป็นเลขคณิตของที่อยู่ แต่มันไม่ใช่ ตัวอย่างเช่นการเพิ่ม 10 ไปยังที่อยู่ควรให้ที่อยู่ที่ใหญ่กว่าโดย 10 หน่วยที่อยู่ แต่การเพิ่ม 10 ไปยังตัวชี้จะเพิ่มขึ้นทีละ 10 เท่าของชนิดของวัตถุที่ชี้ไปที่ (และไม่ใช่ขนาดที่แท้จริง แต่จะถูกปัดขึ้นเป็นขอบเขตการจัดตำแหน่ง) ด้วยint *สถาปัตยกรรมแบบธรรมดาที่มีจำนวนเต็ม 32- บิตการเพิ่ม 10 เข้าไปจะเพิ่มขึ้นได้ 40 หน่วย (ไบต์) โปรแกรมเมอร์ C ที่มีประสบการณ์รู้เรื่องนี้และอยู่กับมัน แต่ผู้เขียนของคุณเห็นได้ชัดว่าไม่มีแฟนของคำอุปมาอุปมัยที่เลอะเทอะ

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


12

นี่คือวิธีที่ฉันอธิบายให้คนที่สับสนบางคนในอดีต: ตัวชี้มีสองคุณลักษณะที่มีผลต่อพฤติกรรม มันมีค่าซึ่งเป็นที่อยู่หน่วยความจำ (ในสภาพแวดล้อมทั่วไป) และประเภทซึ่งบอกประเภทและขนาดของวัตถุที่ชี้ไปที่คุณ

ตัวอย่างเช่นกำหนด:

union {
    int i;
    char c;
} u;

คุณสามารถมีตัวชี้ที่แตกต่างกันสามตัวชี้ไปที่วัตถุเดียวกันทั้งหมด:

void *v = &u;
int *i = &u.i;
char *c = &u.c;

หากคุณเปรียบเทียบค่าของพอยน์เตอร์เหล่านี้ค่าเหล่านี้จะเท่ากันทั้งหมด:

v==i && i==c

อย่างไรก็ตามหากคุณเพิ่มตัวชี้แต่ละตัวคุณจะเห็นว่าประเภทที่ชี้ไปนั้นเกี่ยวข้องกันหรือไม่

i++;
c++;
// You can't perform arithmetic on a void pointer, so no v++
i != c

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


2
+1 ขอบคุณ ด้วยพอยน์เตอร์คุณค่าและประเภทจะแยกออกไม่ได้อย่างที่ใครสามารถแยกร่างมนุษย์ออกจากวิญญาณของเขา
Aki Suihkonen

i == cมีรูปแบบไม่ดี (คุณสามารถเปรียบเทียบพอยน์เตอร์กับประเภทที่แตกต่างกันหากมีการแปลงโดยนัยจากที่หนึ่งไปยังอีกที่หนึ่ง) นอกจากนี้การแก้ไขด้วยการส่งหมายถึงคุณได้ทำการแปลงแล้วก็เป็นที่ถกเถียงกันอยู่ว่าการแปลงนั้นจะเปลี่ยนค่าหรือไม่ (คุณสามารถยืนยันได้ว่ามันไม่ได้ แต่จากนั้นเป็นเพียงการยืนยันสิ่งเดียวกับที่คุณพยายามพิสูจน์ด้วยตัวอย่างนี้)
MM

8

Mark Bessey ได้พูดไปแล้ว แต่สิ่งนี้จะต้องเน้นย้ำอีกครั้งจนกว่าจะเข้าใจ

ตัวชี้มีส่วนเกี่ยวข้องกับตัวแปรมากกว่าตัวอักษร 3

ตัวชี้เป็น tuple ของค่า (ของที่อยู่) และประเภท (พร้อมคุณสมบัติเพิ่มเติมเช่นอ่านอย่างเดียว) ประเภท (และพารามิเตอร์เพิ่มเติมถ้ามี) สามารถเพิ่มเติมกำหนดหรือ จำกัด บริบท เช่น. __far ptr, __near ptr: บริบทของที่อยู่คืออะไร: สแต็ค, กอง, ที่อยู่เชิงเส้น, ชดเชยจากที่ไหนสักแห่ง, หน่วยความจำกายภาพหรืออะไร

เป็นคุณสมบัติประเภทที่ทำให้ตัวชี้คณิตศาสตร์แตกต่างจากเลขจำนวนเต็มเล็กน้อย

ตัวอย่างตัวนับของตัวชี้ที่ไม่ใช่ตัวแปรมีจำนวนมากเกินกว่าที่จะเพิกเฉยได้

  • fopen ส่งคืนตัวชี้ FILE (ตัวแปรอยู่ที่ไหน)

  • ตัวชี้สแต็คหรือตัวชี้เฟรมโดยทั่วไปแล้วจะไม่สามารถลงทะเบียนได้

    *(int *)0x1231330 = 13; - การส่งค่าจำนวนเต็มตามอำเภอใจไปยังชนิด pointer_of_integer และการเขียน / อ่านจำนวนเต็มโดยไม่ต้องแนะนำตัวแปร

ในช่วงอายุของโปรแกรม C จะมีอินสแตนซ์อื่น ๆ อีกมากมายของพอยน์เตอร์พอยน์เตอร์ที่ไม่มีที่อยู่ - ดังนั้นพวกมันจึงไม่ใช่ตัวแปร แต่เป็นนิพจน์ / ค่าที่เกี่ยวข้องกับเวลารวบรวม


8

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

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

แต่ทุกวันนี้บนพีซีและสถาปัตยกรรมARM ที่มีรูปแบบหน่วยความจำแบบแบนและภาษา C เรียบเรียงกันแล้วก็โอเคที่จะคิดว่าตัวชี้เป็นที่อยู่จำนวนเต็มในบางพื้นที่ใน RAM แอดเดรสแบบมิติเดียว


PC ... รุ่นหน่วยความจำแบบแบนหรือไม่ ตัวเลือกคืออะไร
ตัง

Riight และเมื่อมีการเปลี่ยนแปลงสถาปัตยกรรมครั้งต่อไปอาจมีช่องว่างรหัส adn แยกต่างหากหรือใครบางคนกลับไปที่สถาปัตยกรรมเซ็กเมนต์ที่น่าเคารพ (ซึ่งมีเหตุผลด้านความปลอดภัยมากมายอาจเพิ่มคีย์ลงในหมายเลขเซกเมนต์ + ออฟเซ็ตเพื่อตรวจสอบสิทธิ์) "พอยน์เตอร์ที่น่ารักเป็นเพียงจำนวนเต็ม" ก็พังลงมา
vonbrand

7

ตัวชี้เช่นเดียวกับตัวแปรอื่น ๆ ใน C คือชุดของบิตที่อาจแสดงด้วยunsigned charค่าที่ต่อกันตั้งแต่หนึ่งค่าขึ้นไป (เช่นเดียวกับประเภทอื่นที่มีความน่าเชื่อถือsizeof(some_variable)จะระบุจำนวนของunsigned charค่า) สิ่งที่ทำให้ตัวชี้ที่แตกต่างจากตัวแปรอื่นคือ C คอมไพเลอร์จะตีความบิตในตัวชี้เป็นการระบุอย่างใดสถานที่ซึ่งตัวแปรอาจถูกเก็บไว้ ใน C แตกต่างจากภาษาอื่น ๆ เป็นไปได้ที่จะขอพื้นที่สำหรับตัวแปรหลายตัวแล้วแปลงตัวชี้เป็นค่าใด ๆ ในชุดนั้นเป็นตัวชี้ไปยังตัวแปรอื่น ๆ ภายในชุดนั้น

คอมไพเลอร์จำนวนมากใช้พอยน์เตอร์โดยใช้บิตเก็บที่อยู่เครื่องจริง แต่นั่นไม่ได้เป็นการใช้งานที่เป็นไปได้เท่านั้น การดำเนินการสามารถเก็บอาร์เรย์หนึ่ง - ไม่สามารถเข้าถึงรหัสผู้ใช้ - รายการที่อยู่ฮาร์ดแวร์และขนาดที่จัดสรรของวัตถุหน่วยความจำทั้งหมด (ชุดของตัวแปร) ซึ่งโปรแกรมใช้และมีตัวชี้แต่ละตัวมีดัชนีลงในอาร์เรย์ตาม ด้วยการชดเชยจากดัชนีนั้น การออกแบบดังกล่าวจะช่วยให้ระบบไม่เพียง จำกัด รหัสให้ทำงานเฉพาะกับหน่วยความจำที่เป็นเจ้าของ แต่ยังมั่นใจว่าตัวชี้ไปยังรายการหน่วยความจำหนึ่งไม่สามารถแปลงเป็นตัวชี้ไปยังรายการหน่วยความจำอื่นโดยไม่ตั้งใจได้ (ในระบบที่ใช้ฮาร์ดแวร์ ที่อยู่หากfooและbarเป็นอาร์เรย์ของ 10 รายการที่เก็บไว้อย่างต่อเนื่องในหน่วยความจำตัวชี้ไปยังรายการ "สิบเอ็ด" ของfooอาจชี้ไปที่รายการแรกของbarแต่ในระบบที่แต่ละ "ตัวชี้" คือ ID วัตถุและออฟเซ็ตระบบสามารถดักจับถ้ารหัสพยายามทำดัชนีตัวชี้ไปfooเกินช่วงที่จัดสรร) มันอาจเป็นไปได้ที่ระบบดังกล่าวจะกำจัดปัญหาการกระจายตัวของหน่วยความจำเนื่องจากที่อยู่ทางกายภาพที่เชื่อมโยงกับพอยน์เตอร์สามารถย้ายไปมาได้

โปรดทราบว่าถึงแม้พอยน์เตอร์จะค่อนข้างเป็นนามธรรมแต่ทว่ามันยังไม่เป็นนามธรรมเพียงพอที่จะอนุญาตให้คอมไพเลอร์ C ที่ได้มาตรฐานตรงตามมาตรฐานเพื่อใช้งานตัวรวบรวมขยะ คอมไพเลอร์ C ระบุว่าทุกตัวแปรรวมถึงพอยน์เตอร์จะแสดงเป็นลำดับของunsigned charค่า รับตัวแปรใด ๆ หนึ่งสามารถย่อยสลายมันเป็นลำดับของตัวเลขและต่อมาแปลงลำดับของตัวเลขนั้นกลับไปเป็นตัวแปรประเภทเดิม ดังนั้นมันจะเป็นไปได้สำหรับโปรแกรมที่จะcallocที่เก็บข้อมูลบางส่วน (รับตัวชี้ไปที่) จัดเก็บบางอย่างที่นั่นสลายตัวชี้ไปยังชุดข้อมูลไบต์แสดงที่อยู่บนหน้าจอแล้วลบการอ้างอิงทั้งหมดไปยังพวกเขา หากโปรแกรมยอมรับหมายเลขบางส่วนจากแป้นพิมพ์ให้สร้างหมายเลขเหล่านั้นใหม่ไปยังตัวชี้แล้วพยายามอ่านข้อมูลจากตัวชี้นั้นและหากผู้ใช้ป้อนหมายเลขเดียวกันกับที่โปรแกรมได้แสดงไว้ก่อนหน้านี้โปรแกรมจะต้องส่งออกข้อมูล ที่ถูกเก็บไว้ในcallocหน่วยความจำ 'เอ็ด เนื่องจากไม่มีวิธีเป็นไปได้ที่คอมพิวเตอร์จะรู้ได้ว่าผู้ใช้ทำสำเนาของตัวเลขที่แสดงขึ้นมาหรือไม่คอมพิวเตอร์อาจทราบได้ว่าหน่วยความจำดังกล่าวจะสามารถเข้าถึงได้ในอนาคตหรือไม่


ที่เหนือศีรษะมากคุณอาจตรวจพบการใช้ค่าตัวชี้ที่อาจ "รั่ว" ค่าตัวเลขและตรึงการจัดสรรเพื่อให้ตัวรวบรวมขยะไม่รวบรวมหรือย้ายที่ตั้งใหม่ (เว้นแต่freeจะเรียกอย่างชัดเจนว่าแน่นอน) การดำเนินการที่เกิดขึ้นจะเป็นประโยชน์ทั้งหมดหรือไม่เป็นอีกเรื่องหนึ่งเนื่องจากความสามารถในการรวบรวมอาจมี จำกัด แต่อย่างน้อยคุณอาจเรียกว่าตัวรวบรวมขยะ :-) การกำหนดตัวชี้และเลขคณิตจะไม่ "รั่วไหล" ค่า แต่ การเข้าถึงchar*แหล่งกำเนิดที่ไม่รู้จักใด ๆจะต้องมีการตรวจสอบ
Steve Jessop

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

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

@SteveJessop: เพื่อให้ระบบ GC มีประโยชน์ก็ควรจะสามารถปล่อยหน่วยความจำได้อย่างน่าเชื่อถือซึ่งfreeไม่ได้ถูกเรียกหรือป้องกันการอ้างอิงใด ๆ กับวัตถุที่เป็นอิสระจากการอ้างอิงถึงวัตถุสด [แม้ในขณะที่ใช้ทรัพยากรที่ต้องการ การจัดการอายุการใช้งานอย่างชัดเจน, GC ยังคงสามารถใช้งานฟังก์ชั่นหลัง]; ระบบ GC ซึ่งบางครั้งเท็จถือว่าเป็นวัตถุที่มีการอ้างอิงอยู่กับพวกเขาอาจจะสามารถใช้งานได้ถ้าความน่าจะเป็นของ N วัตถุถูกตรึงจำเป็นพร้อมกันใกล้ศูนย์เป็น N ได้รับขนาดใหญ่ เว้นแต่หนึ่งยินดีที่จะธงรวบรวมข้อผิดพลาด ...
SuperCat

... สำหรับโค้ดที่ถูกต้อง C ++ แต่คอมไพเลอร์จะไม่สามารถพิสูจน์ได้ว่าตัวชี้ไม่สามารถแปลงเป็นรูปแบบที่ไม่สามารถจดจำได้ฉันไม่เห็นว่าจะหลีกเลี่ยงความเสี่ยงที่โปรแกรมซึ่งจริง ๆ แล้วไม่เคยทำได้ ใช้พอยน์เตอร์เป็นจำนวนเต็มอาจถูกมองว่าเป็นเท็จ
supercat

6

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

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


1
โดยทั่วไปแล้วมันเป็นหมายเลขอ้างอิง / ID โดยปกติมันเป็นที่อยู่ธรรมดา
Alexey Frunze

ฉันปรับคำตอบของฉันให้เป็นพีซีมากขึ้นตามนิยามของHandle in wikipedia ฉันต้องการอ้างถึงพอยน์เตอร์เป็นตัวอย่างของการจัดการเนื่องจากการจัดการอาจเป็นการอ้างอิงไปยังตัวชี้
Matthew Sanders

6

สรุปโดยย่อ (ซึ่งฉันจะใส่ที่ด้านบน):

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

(1) แต่สำหรับพอยน์เตอร์คอมไพเลอร์ส่วนใหญ่สำหรับฟังก์ชั่นอาจไม่ใช่ที่อยู่ แต่ใหญ่กว่าที่อยู่ (โดยทั่วไปคือ 2x หรือมากกว่านั้น) หรือเป็นตัวชี้ไปยังโครงสร้างในหน่วยความจำมากกว่ามีที่อยู่ของฟังก์ชั่นและสิ่งต่าง ๆ เช่น สระว่ายน้ำคงที่

(2) ตัวชี้ไปยังข้อมูลสมาชิกและตัวชี้ไปยังวิธีการมักจะเป็นคนแปลกหน้า

(3) รหัส x86 รุ่นเก่าที่มีปัญหาตัวชี้ FAR และ NEAR

(4) ตัวอย่างมากมายโดยเฉพาะอย่างยิ่ง IBM AS / 400 ที่มี "พอยน์เตอร์ไขมัน" ที่ปลอดภัย

ฉันแน่ใจว่าคุณสามารถหาข้อมูลเพิ่มเติมได้

รายละเอียด:

UMMPPHHH !!!!! คำตอบจำนวนมากจนถึงขณะนี้คือคำตอบ "โปรแกรมเมอร์วีน" ทั่วไป - แต่ไม่ใช่คอมไพเลอร์ weenie หรือ weenie ฮาร์ดแวร์ เนื่องจากฉันแกล้งทำเป็น Weenie ฮาร์ดแวร์และมักจะทำงานกับ Weenies ของคอมไพเลอร์ให้ฉันโยนสองเซ็นต์ของฉัน:

ในหลาย ๆ อาจจะมากที่สุดคอมไพเลอร์ C ตัวชี้ไปยังข้อมูลจากประเภทนี้ในความเป็นจริงที่อยู่ของTT

ละเอียด.

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

ตัวอย่างเช่นพอยน์เตอร์ของฟังก์ชันบางครั้งก็ใหญ่กว่าที่อยู่ธรรมดามาก หรือพวกเขาอาจเกี่ยวข้องกับระดับของการอ้อม บทความนี้ให้คำอธิบายเดียวซึ่งเกี่ยวข้องกับโปรเซสเซอร์ Intel Itanium แต่ฉันเคยเห็นคนอื่น ๆ โดยทั่วไปแล้วการเรียกฟังก์ชันคุณต้องรู้ไม่เพียง แต่ที่อยู่ของรหัสฟังก์ชั่น แต่ยังเป็นที่อยู่ของสระว่ายน้ำคงที่ของฟังก์ชัน - ขอบเขตของหน่วยความจำที่ค่าคงที่จะถูกโหลดด้วยคำสั่งโหลดเดียวมากกว่าคอมไพเลอร์ ค่าคงที่ 64 บิตจากคำสั่งโหลดทันทีและ Shift และคำสั่ง OR ดังนั้นแทนที่จะเป็นที่อยู่ 64 บิตเดียวคุณต้องมีที่อยู่ 2 64 บิต ABIs บางตัว (Application Binary Interfaces) ย้ายสิ่งนี้ไปเป็น 128 บิตในขณะที่คนอื่นใช้ระดับของการอ้อมด้วยตัวชี้ฟังก์ชั่นจริง ๆ แล้วเป็นที่อยู่ของตัวบ่งชี้ฟังก์ชั่นที่มี 2 ที่อยู่จริงเพียงแค่กล่าวถึง ไหนดีกว่ากัน ขึ้นอยู่กับมุมมองของคุณ: ประสิทธิภาพขนาดรหัส และปัญหาความเข้ากันได้บางครั้ง - บ่อยครั้งที่โค้ดสันนิษฐานว่าตัวชี้สามารถถูกส่งไปเป็นแบบยาวหรือยาว แต่อาจสันนิษฐานว่ายาวเป็น 64 บิต รหัสดังกล่าวอาจไม่เป็นไปตามมาตรฐาน แต่อย่างไรก็ตามลูกค้าอาจต้องการให้มันใช้งานได้

พวกเราหลายคนมีความทรงจำอันเจ็บปวดของสถาปัตยกรรมเซกเมนต์เก่าของ Intel x86 ที่มีตัวชี้ใกล้และตัวชี้ไกล โชคดีที่สิ่งเหล่านี้เกือบจะสูญพันธุ์ไปแล้วในตอนนี้ดังนั้นสรุปได้อย่างรวดเร็วเท่านั้น: ในโหมดจริง 16 บิต, ที่อยู่เชิงเส้นที่แท้จริงคือ

LinearAddress = SegmentRegister[SegNum].base << 4 + Offset

ในขณะที่อยู่ในโหมดป้องกันมันอาจจะเป็น

LinearAddress = SegmentRegister[SegNum].base + offset

ด้วยที่อยู่ผลลัพธ์จะถูกตรวจสอบกับขีด จำกัด ที่ตั้งไว้ในส่วน บางโปรแกรมใช้การประกาศตัวชี้ C / C ++ FAR และ NEAR ไม่ได้มาตรฐานจริงๆ แต่หลายโปรแกรมเพิ่งบอกว่า*T--- แต่มีคอมไพเลอร์และสวิทช์ลิงค์เกอร์ตัวอย่างเช่นตัวชี้รหัสอาจอยู่ใกล้ตัวชี้เพียง 32 บิตชดเชยกับสิ่งที่อยู่ การลงทะเบียน CS (ส่วนของรหัส) ในขณะที่พอยน์เตอร์ข้อมูลอาจเป็นพอยน์เตอร์ FAR โดยระบุทั้งหมายเลขเซ็กเมนต์ 16 บิตและออฟเซ็ต 32 บิตสำหรับค่า 48 บิต ตอนนี้ปริมาณทั้งสองนี้เกี่ยวข้องกับที่อยู่อย่างแน่นอน แต่เนื่องจากขนาดไม่เท่ากันซึ่งเป็นที่อยู่ใด นอกจากนี้เซ็กเมนต์ยังมีสิทธิ์ใช้งาน - อ่านอย่างเดียวอ่านเขียนปฏิบัติได้ - นอกเหนือจากสิ่งที่เกี่ยวข้องกับที่อยู่จริง

อีกตัวอย่างที่น่าสนใจคือ IMHO คือ (หรืออาจจะเป็น) ตระกูล IBM AS / 400 คอมพิวเตอร์เครื่องนี้เป็นเครื่องแรกที่ใช้ระบบปฏิบัติการใน C ++ พอยน์เตอร์ของเครื่องนี้มีขนาดปกติ 2 เท่าเช่นงานนำเสนอนี้กล่าวว่าตัวชี้ 128 บิต แต่ที่อยู่จริงคือ 48-64 บิตและอีกครั้งข้อมูลพิเศษบางอย่างที่เรียกว่าความสามารถที่ให้สิทธิ์เช่นการอ่านเขียนและขีด จำกัด เพื่อป้องกันบัฟเฟอร์ล้น ใช่: คุณสามารถทำสิ่งนี้ร่วมกับ C / C ++ - และถ้าสิ่งนี้แพร่หลาย, PLA จีนและมาเฟียสลาฟจะไม่ถูกแฮ็คเข้าสู่ระบบคอมพิวเตอร์ของตะวันตกมากมาย แต่ในอดีตการเขียนโปรแกรม C / C ++ ส่วนใหญ่ได้ละเลยความปลอดภัยสำหรับประสิทธิภาพ สิ่งที่น่าสนใจที่สุดคือตระกูล AS400 อนุญาตให้ระบบปฏิบัติการสร้างพอยน์เตอร์ที่ปลอดภัยซึ่งอาจมอบให้กับรหัสที่ไม่ได้รับสิทธิพิเศษ แต่รหัสที่ไม่ได้รับสิทธินั้นไม่สามารถปลอมแปลงหรือแก้ไขได้ ความปลอดภัยอีกครั้งและในขณะที่เป็นไปตามมาตรฐานรหัส C / C ++ ที่ไม่เป็นไปตามมาตรฐานเลอะเทอะมากจะไม่ทำงานในระบบที่ปลอดภัยเช่นนี้ อีกครั้งมีมาตรฐานอย่างเป็นทางการ

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

มีหลายวิธีในการแก้ปัญหานี้ [ปัญหาที่เกี่ยวข้องกับความเฉื่อยชาแบบเดี่ยวและหลายครั้งและการสืบทอดเสมือน] นี่คือวิธีที่คอมไพเลอร์ Visual Studio ตัดสินใจจัดการ: ตัวชี้ไปยังฟังก์ชันสมาชิกของคลาสที่สืบทอดที่สืบทอดมานั้นเป็นโครงสร้างจริงๆ "และพวกเขากล่าวต่อไปว่า" การคัดเลือกตัวชี้ฟังก์ชันสามารถเปลี่ยนขนาดได้! "

ในขณะที่คุณสามารถเดาได้จากการรักษาความปลอดภัย (ใน) pontificating ของฉันฉันได้มีส่วนร่วมใน C / C ++ ฮาร์ดแวร์ / โครงการซอฟต์แวร์ที่ตัวชี้ได้รับการปฏิบัติเช่นความสามารถมากกว่าที่อยู่ดิบ

ฉันสามารถไปต่อได้ แต่ฉันหวังว่าคุณจะได้รับความคิด

สรุปโดยย่อ (ซึ่งฉันจะใส่ที่ด้านบน):

(0) การคิดพอยน์เตอร์เป็นที่อยู่มักจะเป็นเครื่องมือการเรียนรู้ที่ดีและมักจะเป็นการใช้งานจริงสำหรับพอยน์เตอร์กับชนิดข้อมูลธรรมดา

(1) แต่สำหรับพอยน์เตอร์คอมไพเลอร์ส่วนใหญ่สำหรับฟังก์ชั่นอาจไม่ใช่ที่อยู่ แต่ใหญ่กว่าที่อยู่ (โดยทั่วไปคือ 2X หรือมากกว่านั้นเป็นสองเท่า) หรือเป็นตัวชี้ไปยังโครงสร้างในหน่วยความจำมากกว่าที่มีที่อยู่ของฟังก์ชันและสิ่งต่าง ๆ เช่น สระว่ายน้ำคงที่

(2) ตัวชี้ไปยังข้อมูลสมาชิกและตัวชี้ไปยังวิธีการมักจะเป็นคนแปลกหน้า

(3) รหัส x86 รุ่นเก่าที่มีปัญหาตัวชี้ FAR และ NEAR

(4) ตัวอย่างมากมายโดยเฉพาะอย่างยิ่ง IBM AS / 400 ที่มี "พอยน์เตอร์ไขมัน" ที่ปลอดภัย

ฉันแน่ใจว่าคุณสามารถหาข้อมูลเพิ่มเติมได้


ในโหมด 16 บิตจริงLinearAddress = SegmentRegister.Selector * 16 + Offset(หมายเหตุคูณ 16 ไม่เลื่อน 16) ในโหมดที่ได้รับการป้องกันLinearAddress = SegmentRegister.base + offset(ไม่มีการคูณใด ๆ ฐานส่วนจะถูกเก็บไว้ใน GDT / LDT และแคชในการลงทะเบียนส่วนตามที่เป็นอยู่ )
Alexey Frunze

คุณถูกต้องเกี่ยวกับฐานส่วน ฉันได้รับการ misremembered เป็นขีด จำกัด เซ็กเมนต์ที่เป็นทางเลือกคูณด้วย 4K ฐานเซกเมนต์ของเขาจะต้อง unscrambled โดยฮาร์ดแวร์เมื่อมันโหลดตัวบ่งชี้เซ็กเมนต์จากหน่วยความจำในการลงทะเบียนเซ็กเมนต์
Krazy Glew

4

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


ดังนั้นปวงeeเป็นที่อยู่หน่วยความจำจริงหรือ คุณไม่เห็นด้วยกับผู้เขียน? แค่พยายามเข้าใจ
d0rmLife

ฟังก์ชั่นหลักของตัวชี้คือการชี้ไปที่บางสิ่งบางอย่าง วิธีการที่จะประสบความสำเร็จและไม่ว่าจะมีที่อยู่จริงหรือไม่ไม่ได้กำหนดไว้ ตัวชี้อาจเป็นเพียง ID / หมายเลขอ้างอิงไม่ใช่ที่อยู่จริง
Alexey Frunze

4

คุณสามารถดูได้ด้วยวิธีนี้ ตัวชี้คือค่าที่แสดงถึงที่อยู่ในพื้นที่หน่วยความจำที่กำหนดแอดเดรสได้


2
ตัวชี้ไม่จำเป็นต้องเก็บที่อยู่หน่วยความจำจริงไว้ ดูคำตอบและความคิดเห็นของฉันภายใต้มัน
Alexey Frunze

ตัวชี้ .... อะไรกับตัวแปรแรกบนสแต็กไม่พิมพ์ 0 มันพิมพ์ด้านบน (หรือด้านล่าง) ของสแต็กเฟรมขึ้นอยู่กับวิธีการนำไปใช้
ตัง

@thang สำหรับตัวแปรแรกด้านบนและด้านล่างจะเหมือนกัน และที่อยู่ของด้านบนหรือด้านล่างในกรณีของสแต็คคืออะไร
Valentin Radu

@ValentinRadu ทำไมคุณไม่ลอง .. เห็นได้ชัดว่าคุณไม่ได้ลอง
Thang

2
@thang คุณถูกต้องฉันทำข้อสันนิษฐานที่ไม่ดีจริงๆ
Valentin Radu

3

ตัวชี้เป็นเพียงตัวแปรอื่นที่สามารถมีที่อยู่หน่วยความจำปกติของตัวแปรอื่น ตัวชี้เป็นตัวแปรมันก็มีที่อยู่หน่วยความจำ


1
ไม่จำเป็นต้องเป็นที่อยู่ แต่คุณได้อ่านคำตอบและความคิดเห็นที่มีอยู่ก่อนโพสต์คำตอบของคุณหรือไม่
Alexey Frunze

3

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

ตัวอย่างเช่นตัวชี้ C ถูกพิมพ์ค่อนข้างรวย ถ้าคุณเพิ่มพอยน์เตอร์ผ่านอาร์เรย์ของโครงสร้างมันจะกระโดดจากโครงสร้างหนึ่งไปอีกโครงสร้างหนึ่ง

พอยน์เตอร์อยู่ภายใต้กฎการแปลงและให้การตรวจสอบประเภทเวลาคอมไพล์

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

ตัวชี้สามารถใช้เป็นตัวแปรบูลีน: มันจะทดสอบจริงถ้ามันเป็นอย่างอื่นที่ไม่ใช่โมฆะและเท็จถ้ามันเป็นโมฆะ

ในภาษาเครื่องหากตัวชี้โมฆะเป็นที่อยู่ตลกเช่น 0xFFFFFFFF คุณอาจต้องทดสอบอย่างชัดเจนสำหรับค่านั้น C ซ่อนสิ่งนั้นจากคุณ แม้ว่าชี้โมฆะคือ 0xFFFFFFFF if (ptr != 0) { /* not null! */}คุณสามารถทดสอบได้โดยใช้

การใช้พอยน์เตอร์ที่ล้มล้างระบบประเภทนำไปสู่พฤติกรรมที่ไม่ได้กำหนดในขณะที่รหัสที่คล้ายกันในภาษาเครื่องอาจถูกกำหนดไว้อย่างดี ผู้ประกอบจะรวบรวมคำแนะนำที่คุณเขียน แต่คอมไพเลอร์ C จะปรับให้เหมาะสมตามสมมติฐานที่ว่าคุณไม่ได้ทำอะไรผิด หากfloat *pตัวชี้ชี้ไปที่long nตัวแปรและ*p = 0.0ถูกเรียกใช้งานคอมไพเลอร์ไม่จำเป็นต้องจัดการสิ่งนี้ การใช้งานในภายหลังnจะไม่จำเป็นต้องอ่านรูปแบบบิตของค่าลอย แต่บางทีมันอาจเป็นการเข้าถึงที่ได้รับการปรับให้เหมาะสมซึ่งตั้งอยู่บนสมมุติฐาน "aliasing ที่เข้มงวด" ที่nยังไม่ได้สัมผัส! นั่นคือข้อสันนิษฐานว่าโปรแกรมจะมีความประพฤติดีและไม่ควรที่จะชี้ไปที่pn

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

ดังนั้นคุณจะเห็นได้ว่ามีความแตกต่างทางความหมายหลายอย่างระหว่างที่อยู่ของเครื่องและตัวชี้ C


ตัวชี้ NULL ไม่ทำงานอย่างที่คุณคิดว่ามันทำบนแพลตฟอร์มทั้งหมด - โปรดดูคำตอบของฉันไปที่ CiscoIPPhone ด้านบน NULL == 0 เป็นข้อสันนิษฐานที่มีเฉพาะแพลตฟอร์มที่ใช้ x86 Convention บอกว่าแพลตฟอร์มใหม่ควรจะตรงกับ x86 อย่างไรก็ตามโดยเฉพาะในโลกที่ฝังตัวไม่เป็นเช่นนั้น แก้ไข: นอกจากนี้ C ไม่ทำสิ่งใดให้นามธรรมค่าของตัวชี้จากฮาร์ดแวร์ - "ptr! = 0" จะไม่ทำงานเป็นการทดสอบ NULL บนแพลตฟอร์มที่ NULL! = 0.
DX-MON

1
DX-MON นั้นผิดอย่างสิ้นเชิงสำหรับมาตรฐาน C. NULL ถูกกำหนดให้เป็น 0 และสามารถใช้แทนกันได้ในคำสั่ง ไม่ว่าจะเป็นตัวแทนของตัวชี้ NULL ในฮาร์ดแวร์หรือไม่ 0 บิตทั้งหมดนั้นไม่เกี่ยวข้องกับวิธีการแสดงในซอร์สโค้ด
Mark Bessey

@ DX-MON ฉันเกรงว่าคุณไม่ได้ทำงานกับข้อเท็จจริงที่ถูกต้อง ใน C นิพจน์ค่าคงที่อินทิกรัลทำหน้าที่เป็นค่าคงที่ตัวชี้โมฆะโดยไม่คำนึงว่าตัวชี้โมฆะนั้นเป็นค่าว่างหรือไม่ หากคุณรู้จักคอมไพเลอร์ C ซึ่งptr != 0ไม่ใช่การทดสอบว่างให้เปิดเผยตัวตนของมัน (แต่ก่อนที่คุณจะส่งรายงานข้อผิดพลาดไปยังผู้ขาย)
Kaz

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

1
@alexis บทและข้อโปรด C ไม่ได้กำหนดตัวชี้โมฆะให้เป็นศูนย์ C กำหนดศูนย์ (หรือนิพจน์ค่าคงที่รวมใด ๆ ที่มีค่าเป็นศูนย์) เป็นไวยากรณ์สำหรับแสดงถึงค่าคงที่ตัวชี้โมฆะ faqs.org/faqs/C-faq/faq (มาตรา 5)
Kaz

3

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

+ : A variable of type integer (usually called offset) can be added to yield a new pointer
- : A variable of type integer (usually called offset) can be subtracted to yield a new pointer
  : A variable of type pointer can be subtracted to yield an integer (usually called offset)
* : De-referencing. Retrieve the value of the variable (called address) and map to the object the address refers to.
++: It's just `+= 1`
--: It's just `-= 1`

ตัวชี้ถูกจัดประเภทตามประเภทของวัตถุที่อ้างอิงในปัจจุบัน ข้อมูลเพียงส่วนเดียวเท่านั้นคือขนาดของวัตถุ

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

หมายเหตุตลอดคำอธิบายนี้ฉันได้ละทิ้งแนวคิดของหน่วยความจำ


ฉันชอบคำอธิบายของคุณเกี่ยวกับความเป็นจริงเชิงนามธรรมของตัวชี้ทั่วไปในระบบทั่วไป แต่บางทีการพูดคุยถึงความทรงจำอาจมีประโยชน์ ในความเป็นจริงการพูดกับตัวเองฉันรู้ว่ามันจะ ... ! ฉันคิดว่าการพูดคุยเกี่ยวกับการเชื่อมต่อจะมีประโยชน์มากสำหรับการทำความเข้าใจภาพรวม +1 anyways :)
d0rmLife

@ d0rmLife: คุณมีคำอธิบายเพียงพอในคำตอบอื่น ๆ ซึ่งครอบคลุมภาพใหญ่ขึ้น ฉันแค่อยากจะให้คำอธิบายเชิงนามธรรมทางคณิตศาสตร์เป็นมุมมองอื่น IMHO ก็จะสร้างความสับสนน้อยลงในการเรียก&ว่า 'Address of` ซึ่งจะเชื่อมโยงกับวัตถุมากกว่าตัวชี้ต่อ se`
Abhijit

ไม่มีความผิด แต่ฉันจะตัดสินใจเองว่าคำอธิบายใดเพียงพอ ตำราหนึ่งเล่มไม่เพียงพอที่จะอธิบายโครงสร้างข้อมูลและการจัดสรรหน่วยความจำได้อย่างเต็มที่ ;) .... anyways, คำตอบของคุณยังคงเป็นประโยชน์ , ถึงแม้ว่ามันจะไม่ได้เป็นนวนิยาย
d0rmLife

มันทำให้รู้สึกถึงจับไม่ชี้โดยไม่ต้องแนวคิดของหน่วยความจำ หากวัตถุมีอยู่โดยไม่มีหน่วยความจำจะต้องอยู่ในสถานที่ที่ไม่มีที่อยู่ - เช่นในการลงทะเบียน เพื่อให้สามารถใช้ '&' presupposes หน่วยความจำ
Aki Suihkonen

3

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

ในทางเทคนิคที่อยู่ไม่เคยมีค่าใน C เพราะความหมายของคำว่า "มูลค่า" ใน (ISO) C คือ:

ความหมายที่แม่นยำของเนื้อหาของวัตถุเมื่อตีความว่ามีประเภทเฉพาะ

(เน้นโดยฉัน) อย่างไรก็ตามไม่มี "ประเภทที่อยู่" ใน C

ตัวชี้ไม่เหมือนกัน ตัวชี้เป็นชนิดชนิดหนึ่งในภาษา C มีตัวชี้ที่แตกต่างกันหลายประเภท พวกเขาไม่จำเป็นต้องปฏิบัติตามชุดที่เหมือนกันของกฎของภาษาเช่นผลกระทบของ++บนค่าของชนิดเทียบกับint*char*

ค่าใน C สามารถเป็นประเภทตัวชี้ นี้เรียกว่าค่าตัวชี้ เพื่อให้ชัดเจนค่าตัวชี้ไม่ใช่ตัวชี้ในภาษา C แต่เราคุ้นเคยกับการผสมเข้าด้วยกันเพราะใน C มันไม่น่าจะคลุมเครือ: ถ้าเราเรียกการแสดงออกpว่าเป็น "ตัวชี้" มันเป็นเพียงค่าตัวชี้ แต่ไม่ใช่ประเภทเนื่องจากประเภทที่มีชื่อใน C ไม่ แสดงโดยการแสดงออกแต่โดยประเภทชื่อหรือtypedef ชื่อ

บางสิ่งอื่น ๆ ที่ลึกซึ้ง ในฐานะผู้ใช้ C อันดับแรกเราควรทราบความobjectหมาย:

ภูมิภาคของการจัดเก็บข้อมูลในสภาพแวดล้อมการดำเนินการเนื้อหาที่สามารถเป็นตัวแทนของค่า

วัตถุเป็นเอนทิตีเพื่อแสดงค่าซึ่งเป็นประเภทเฉพาะ ตัวชี้เป็นชนิดของวัตถุ ดังนั้นถ้าเราประกาศint* p;ก็pหมายถึง "วัตถุประเภทตัวชี้" หรือ "วัตถุตัวชี้"

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

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

ISO C11 6.5.2.3

3 ตัวดำเนิน&การunary ให้ที่อยู่ของตัวถูกดำเนินการ

หมายเหตุถ้อยคำนี้ได้รับการแนะนำให้รู้จักกับ WG14 / N1256 เช่น ISO C99: TC3 ใน C99 มี

3 ตัวดำเนิน&การunary ส่งคืนที่อยู่ของตัวถูกดำเนินการ

มันสะท้อนความเห็นของคณะกรรมการ: ที่อยู่ไม่ใช่ค่าตัวชี้ที่ส่งคืนโดย&ผู้ประกอบการเอก

แม้จะมีข้อความข้างต้น แต่ก็ยังมีความยุ่งเหยิงแม้จะอยู่ในมาตรฐาน

ISO C11 6.6

9 ค่าคงที่ที่อยู่คือตัวชี้โมฆะตัวชี้ไปยัง lvalue ที่กำหนดวัตถุของระยะเวลาการจัดเก็บแบบคงที่หรือตัวชี้ไปยังตัวออกแบบฟังก์ชัน

ISO C ++ 11 5.19

3 ... การแสดงออกของค่าคงที่ที่อยู่คือการแสดงออกของค่าคงที่แกนหลักของประเภทตัวชี้ที่ประเมินถึงที่อยู่ของวัตถุที่มีระยะเวลาการจัดเก็บแบบคงที่ไปยังที่อยู่ของฟังก์ชั่นหรือค่าตัวชี้โมฆะ std::nullptr_tประเภท ...

(แบบร่างมาตรฐาน C ++ ล่าสุดใช้ถ้อยคำอื่นดังนั้นจึงไม่มีปัญหานี้)

ที่จริงทั้ง "ที่อยู่คงที่" ใน C และ "ที่อยู่คงที่นิพจน์" ใน C ++ มีการแสดงออกอย่างต่อเนื่องของประเภทตัวชี้ (หรืออย่างน้อยประเภท "เหมือนตัวชี้" ตั้งแต่ C ++ 11)

และตัวดำเนิน&การunary ในตัวถูกเรียกว่า "address-of" ใน C และ C ++; ทำนองเดียวกันstd::addressofแนะนำใน C ++ 11

การตั้งชื่อเหล่านี้อาจนำมาซึ่งความเข้าใจผิด ส่งผลให้เกิดการแสดงออกเป็นประเภทตัวชี้เพื่อให้พวกเขาต้องการจะตีความว่าเป็นผลประกอบด้วย / ผลตอบแทนถัวเฉลี่ยที่อยู่แทนที่จะเป็นที่อยู่


2

มันบอกว่า "เพราะมันทำให้คนที่ไม่รู้ว่าอยู่คืออะไร" - และมันก็เป็นเรื่องจริง: ถ้าคุณเรียนรู้ว่าที่อยู่นั้นเกี่ยวข้องกับอะไรคุณจะไม่สับสน ในทางทฤษฎีพอยน์เตอร์เป็นตัวแปรที่ชี้ไปยังอีกอันหนึ่งถือที่อยู่ซึ่งเป็นที่อยู่ของตัวแปรที่ชี้ไป ฉันไม่รู้ว่าทำไมควรซ่อนความจริงนี้มันไม่ใช่วิทยาศาสตร์จรวด หากคุณเข้าใจพอยน์เตอร์คุณจะเข้าใกล้ความเข้าใจขั้นตอนการทำงานของคอมพิวเตอร์ ไปข้างหน้า!


2

ลองคิดดูสิฉันคิดว่ามันเป็นเรื่องของความหมาย ฉันไม่คิดว่าผู้เขียนนั้นถูกต้องเนื่องจากมาตรฐาน C อ้างถึงตัวชี้ว่าถือที่อยู่ไปยังวัตถุที่อ้างอิงตามที่คนอื่น ๆ ได้กล่าวถึงแล้วที่นี่ อย่างไรก็ตามที่อยู่! = ที่อยู่หน่วยความจำ ที่อยู่สามารถเป็นอะไรก็ได้ตามมาตรฐาน C แม้ว่าในที่สุดมันจะนำไปสู่ที่อยู่หน่วยความจำตัวชี้สามารถเป็น id ตัวเลือกชดเชย + (x86) อะไรก็ได้ตราบใดที่มันสามารถอธิบาย (หลังจากการทำแผนที่) หน่วยความจำใด ๆที่อยู่ในพื้นที่แอดเดรส


ตัวชี้เก็บที่อยู่ (หรือไม่ถ้าเป็นค่าว่าง) แต่นั่นเป็นหนทางไกลจากการเป็นที่อยู่: ตัวอย่างเช่นสองพอยน์เตอร์ไปยังที่อยู่เดียวกัน แต่ด้วยประเภทที่แตกต่างกันจะไม่เทียบเท่าในหลาย ๆ สถานการณ์
Gilles 'SO- หยุดความชั่วร้าย'

@Gilles หากคุณเห็นว่า "กำลังเป็น" ดังที่int i=5-> i เท่ากับ 5 ตัวชี้คือที่อยู่ใช่ นอกจากนี้ null ยังมีที่อยู่เช่นกัน โดยทั่วไปแล้วที่อยู่การเขียนที่ไม่ถูกต้อง (แต่ไม่จำเป็นต้องดูโหมด x86-real) แต่ที่อยู่ไม่น้อย มีข้อกำหนดสำหรับ null เพียง 2 ข้อเท่านั้นรับประกันการเปรียบเทียบไม่เท่ากันกับตัวชี้ไปยังวัตถุจริงและตัวชี้ null สองตัวใด ๆ จะเปรียบเทียบเท่ากัน
Valentin Radu

ในทางตรงกันข้ามตัวชี้โมฆะรับประกันว่าจะไม่เท่ากับที่อยู่ของวัตถุใด ๆ การอ้างอิงตัวชี้ null เป็นลักษณะการทำงานที่ไม่ได้กำหนด ปัญหาใหญ่ในการบอกว่า "ตัวชี้คือที่อยู่" คือพวกมันทำงานต่างกัน ถ้าpเป็นตัวชี้p+1ไม่ได้เพิ่มที่อยู่ 1 เสมอ
Gilles 'ดังนั้นหยุดชั่วร้าย'

โปรดอ่านความคิดเห็นอีกครั้ง, it's guaranteed to compare unequal to a pointer to an actual object. สำหรับตัวคำนวณเลขคณิตฉันไม่เห็นจุดนั้นค่าของตัวชี้ยังคงเป็นที่อยู่แม้ว่าการดำเนินการ "+" จะไม่จำเป็นต้องเพิ่มหนึ่งไบต์ลงไป
Valentin Radu

1

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

คอมไพเลอร์อาจสันนิษฐานว่าพอยน์เตอร์ของประเภทที่เข้ากันไม่ได้ไม่ได้ชี้ไปยังที่อยู่เดียวกันแม้ว่าพวกเขาจะทำอย่างชัดเจนซึ่งอาจให้พฤติกรรมที่ไม่เป็นไปได้ด้วยตัวชี้แบบง่าย == รูปแบบที่อยู่ พิจารณารหัสต่อไปนี้ (สมมติว่าsizeof(int) = 2*sizeof(short)):

unsigned int i = 0;
unsigned short* p = (unsigned short*)&i;
p[0]=p[1]=1;

if (i == 2 + (unsigned short)(-1))
{
  // you'd expect this to execute, but it need not
}

if (i == 0)
{
  // you'd expect this not to execute, but it actually may do so
}

โปรดทราบว่ามีข้อยกเว้นchar*ดังนั้นการจัดการค่าโดยใช้char*จึงเป็นไปได้ (แม้ว่าจะไม่สามารถพกพาได้)


0

ข้อมูลสรุปอย่างรวดเร็ว: ที่อยู่ AC คือค่าซึ่งโดยทั่วไปจะแสดงเป็นที่อยู่หน่วยความจำระดับเครื่องโดยมีประเภทเฉพาะ

คำว่า "ตัวชี้" ที่ไม่มีเงื่อนไขมีความกำกวม C มีตัวชี้วัตถุ (ตัวแปร) ตัวชี้ประเภทตัวชี้การแสดงออกและตัวชี้ค่า

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

มาตรฐาน C อย่างน้อยในบางกรณีใช้คำว่า "ตัวชี้" เพื่อหมายถึง "ค่าตัวชี้" ตัวอย่างเช่นคำอธิบายของmallocบอกว่า "ส่งคืนตัวชี้ null หรือตัวชี้ไปยังพื้นที่ที่จัดสรร"

ดังนั้นที่อยู่ใน C คืออะไร? มันคือค่าตัวชี้คือค่าของตัวชี้บางประเภท (ยกเว้นว่าค่าตัวชี้โมฆะไม่จำเป็นต้องเรียกว่า "ที่อยู่" เนื่องจากไม่ใช่ที่อยู่ของสิ่งใด)

คำอธิบายมาตรฐานของ&ผู้ประกอบการเอกบอกว่ามัน "ผลตอบแทนที่อยู่ของตัวถูกดำเนินการ" นอกเหนือจากมาตรฐาน C คำว่า "ที่อยู่" มักใช้เพื่ออ้างถึงที่อยู่หน่วยความจำ (จริงหรือเสมือน) โดยทั่วไปจะมีขนาดหนึ่งคำ

AC "ที่อยู่" โดยทั่วไปแล้วจะใช้งานเป็นที่อยู่ของเครื่อง - เช่นเดียวกับintค่าC จะถูกนำมาใช้เป็นคำของเครื่อง แต่ที่อยู่ C (ค่าตัวชี้) เป็นมากกว่าที่อยู่เครื่อง มันเป็นค่ามักจะแสดงเป็นที่อยู่เครื่องและก็คุ้มค่ากับเฉพาะบางประเภท


0

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

อย่างไรก็ตามมาตรฐานพูดคุยในระดับที่เฉพาะเจาะจงของสิ่งที่เป็นนามธรรม คนที่ผู้เขียนพูดถึงเกี่ยวกับผู้ที่ "รู้ว่าที่อยู่คืออะไรเกี่ยวกับ" แต่ผู้ที่ยังใหม่กับ C จะต้องได้เรียนรู้เกี่ยวกับที่อยู่ในระดับที่แตกต่างกันของนามธรรม - บางทีโดยการเขียนโปรแกรมภาษาประกอบ ไม่มีการรับประกันว่าการใช้งาน C จะใช้การแสดงที่อยู่เดียวกันกับที่การใช้งานซีพียู opcodes (เรียกว่า "ที่อยู่ร้านค้า" ในตอนนี้) ซึ่งคนเหล่านี้รู้อยู่แล้ว

เขาพูดต่อเกี่ยวกับ "การจัดการที่อยู่อย่างสมเหตุผล" เท่าที่มาตรฐาน C เป็นห่วงก็ไม่มีสิ่งใดที่ "จัดการที่อยู่อย่างสมเหตุสมผล" นอกจากนี้ยังมีการกำหนดไว้ในตัวชี้และนั่นคือมัน แน่นอนว่าคุณสามารถแปลงตัวชี้เป็นจำนวนเต็มทำ bitwise หรือ ops เลขคณิตและจากนั้นแปลงกลับ สิ่งนี้ไม่ได้รับประกันว่าจะทำงานได้ตามมาตรฐานดังนั้นก่อนที่จะเขียนรหัสนั้นคุณควรทราบว่าการใช้งาน C ของคุณนั้นแสดงถึงพอยน์เตอร์และดำเนินการแปลงอย่างไร มันอาจจะใช้เป็นตัวแทนอยู่ที่คุณคาดหวัง แต่มันก็ไม่ได้ว่าเป็นความผิดของคุณเพราะคุณไม่ได้อ่านคู่มือการใช้งาน นั่นไม่ใช่ความสับสนมันเป็นขั้นตอนการเขียนโปรแกรมที่ไม่ถูกต้อง ;-)

ในระยะสั้น C ใช้แนวคิดที่เป็นนามธรรมของที่อยู่มากกว่าที่ผู้เขียนทำ

แนวคิดของผู้เขียนเกี่ยวกับที่อยู่ของหลักสูตรไม่ได้เป็นคำระดับต่ำสุดในเรื่องนี้ สิ่งที่มีการแมปหน่วยความจำเสมือนและ RAM ที่อยู่จริงในชิปหลายตัวจำนวนที่คุณบอกซีพียูคือ "ที่อยู่ร้านค้า" ที่คุณต้องการเข้าถึงโดยทั่วไปแล้วไม่มีอะไรเกี่ยวข้องกับข้อมูลที่คุณต้องการอยู่ในฮาร์ดแวร์ มันเป็นเลเยอร์ทางอ้อมและการเป็นตัวแทน แต่ผู้แต่งได้เลือกหนึ่งสิทธิ์ หากคุณกำลังจะทำอย่างนั้นเมื่อพูดถึง C ให้เลือกระดับ C เพื่อรับสิทธิพิเศษ !

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


0

เพียงแค่บอกว่าพอยน์เตอร์เป็นส่วนหนึ่งของกลไกการแบ่งเซ็กเมนต์ซึ่งแปลเป็น Linear Address หลังจากการแบ่งเซ็กเมนต์และจากนั้นเป็นฟิสิคัลแอดเดรสหลังจากการเพจ ที่อยู่ทางกายภาพได้รับการแก้ไขจาก ram ของคุณ

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