คำถามยั่วยุ!
แม้แต่การสแกนคร่าวๆของการตอบสนองและความคิดเห็นในกระทู้นี้จะแสดงให้เห็นว่าอารมณ์ของคุณง่ายและตรงไปตรงมาแบบสอบถามจะกลายเป็น
ไม่ควรแปลกใจ
inarguably, ความเข้าใจผิดรอบแนวคิดและการใช้งานของตัวชี้แสดงให้เห็นเด่นสาเหตุร้ายแรงความล้มเหลวในการเขียนโปรแกรมโดยทั่วไป
การรับรู้ถึงความเป็นจริงนี้เห็นได้ชัดในความแพร่หลายของภาษาที่ออกแบบมาเพื่อการจัดการโดยเฉพาะและโดยเฉพาะอย่างยิ่งเพื่อหลีกเลี่ยงความท้าทายที่พอยน์เตอร์แนะนำเข้าด้วยกัน คิดว่า C ++ และอนุพันธ์อื่น ๆ ของ C, Java และความสัมพันธ์ของมัน, Python และสคริปต์อื่น ๆ - เป็นเพียงสิ่งที่โดดเด่นและแพร่หลายมากขึ้นและสั่งมากหรือน้อยในการจัดการกับปัญหา
การพัฒนาความรู้ความเข้าใจในหลักการพื้นฐานดังนั้นจึงต้องเกี่ยวข้องเพื่อบุคคลทุกคนที่ปรารถนาที่จะเป็นเลิศในการเขียนโปรแกรม - โดยเฉพาะอย่างยิ่งในระดับระบบ
ฉันคิดว่านี่เป็นสิ่งที่ครูของคุณแสดงให้เห็น
และธรรมชาติของ C ทำให้ยานพาหนะสะดวกสำหรับการสำรวจครั้งนี้ ชัดเจนน้อยกว่าการชุมนุม - แม้ว่าอาจเข้าใจได้ง่ายกว่าและยังชัดเจนกว่าภาษาโดยอิงจากสิ่งที่เป็นนามธรรมที่ลึกซึ้งของสภาพแวดล้อมการดำเนินการ
ออกแบบมาเพื่ออำนวยความสะดวกในการแปลความตั้งใจของโปรแกรมเมอร์เป็นคำสั่งที่เครื่องสามารถเข้าใจได้ C เป็นภาษาระดับระบบ ในขณะที่จัดอยู่ในระดับสูงจริงๆมันอยู่ในหมวดหมู่ 'กลาง'; แต่เนื่องจากไม่มีอยู่เช่นนั้นการกำหนด 'ระบบ' จึงเพียงพอ
คุณลักษณะนี้มีความรับผิดชอบส่วนใหญ่ในการทำให้เป็นภาษาของตัวเลือกสำหรับไดรเวอร์อุปกรณ์ , โค้ดระบบปฏิบัติการและการใช้งานแบบฝัง นอกจากนี้ทางเลือกที่ได้รับความนิยมในการใช้งานที่มีประสิทธิภาพสูงสุดเป็นสิ่งสำคัญยิ่ง ที่หมายถึงความแตกต่างระหว่างการเอาชีวิตรอดและการสูญพันธุ์ดังนั้นจึงเป็นสิ่งจำเป็นเมื่อเทียบกับความหรูหรา ในกรณีดังกล่าวความสะดวกสบายที่น่าดึงดูดใจของการพกพาจะสูญเสียความน่าดึงดูดใจทั้งหมดและการเลือกเพื่อประสิทธิภาพการขาดความเป็นเงาของตัวส่วนร่วมที่น้อยที่สุดจะกลายเป็นตัวเลือกที่เป็นอันตราย
สิ่งที่ทำให้ C - และอนุพันธ์บางอย่างของมัน - ค่อนข้างพิเศษคือมันช่วยให้ผู้ใช้ควบคุมได้อย่างสมบูรณ์ - เมื่อนั่นคือสิ่งที่พวกเขาต้องการ -โดยไม่กำหนดความรับผิดชอบที่เกี่ยวข้องกับพวกเขาเมื่อพวกเขาไม่ทำ อย่างไรก็ตามมันไม่เคยมีมากกว่าฉนวนที่บางที่สุดจากเครื่องดังนั้นการใช้งานที่เหมาะสมจึงต้องการความเข้าใจที่แม่นยำของแนวคิดของพอยน์เตอร์น์เตอร์
โดยพื้นฐานแล้วคำตอบสำหรับคำถามของคุณนั้นเรียบง่ายและน่าพึงพอใจในการยืนยันข้อสงสัยของคุณ ที่จัดไว้ให้แต่ที่หนึ่งแนบจำเป็นอย่างมีนัยสำคัญในการแนวคิดทุกในคำสั่งนี้:
- การกระทำของการตรวจสอบการเปรียบเทียบและการจัดการกับพอยน์เตอร์เป็นสิ่งที่ถูกต้องเสมอในขณะที่ข้อสรุปที่ได้จากผลลัพธ์ขึ้นอยู่กับความถูกต้องของค่าที่มีอยู่และไม่จำเป็นต้องเป็น
อดีตเป็นทั้งสองอย่างสม่ำเสมอ ปลอดภัยและอาจ เหมาะสมในขณะที่สามารถหลังเท่านั้นที่เคยเป็นที่เหมาะสมเมื่อมันได้รับการจัดตั้งขึ้นเป็นที่ปลอดภัย น่าแปลก- บาง -เพื่อสร้างความถูกต้องของหลังขึ้นอยู่กับและเรียกร้องอดีต
แน่นอนว่าส่วนหนึ่งของความสับสนเกิดขึ้นจากผลของการเรียกซ้ำที่เกิดขึ้นภายในหลักการของตัวชี้ - และความท้าทายที่เกิดขึ้นในเนื้อหาที่แตกต่างจากที่อยู่
คุณคาดเดาได้ค่อนข้างถูกต้อง
ฉันถูกนำไปคิดว่าตัวชี้ใด ๆ สามารถเปรียบเทียบกับตัวชี้อื่น ๆ ได้ไม่ว่าพวกมันจะชี้ไปที่ใด ยิ่งกว่านั้นฉันคิดว่าตัวชี้เลขคณิตระหว่างตัวชี้สองตัวนั้นใช้ได้ไม่ว่าพวกเขาจะชี้ไปที่ใดเพราะเลขคณิตกำลังใช้หน่วยความจำที่อยู่ในที่เก็บตัวชี้
และผู้มีส่วนร่วมหลายคนยืนยัน: พอยน์เตอร์เป็นเพียงตัวเลข บางครั้งสิ่งที่ซับซ้อนกว่าแต่ก็ยังไม่เกินจำนวน
ความรุนแรงที่น่าขบขันที่ได้รับจากการโต้แย้งครั้งนี้เผยให้เห็นเกี่ยวกับธรรมชาติของมนุษย์มากกว่าการเขียนโปรแกรม บางทีเราจะทำในภายหลัง ...
ในฐานะที่เป็นหนึ่งความคิดเห็นเริ่มเป็นใบ้ ความสับสนและความตกตะลึงทั้งหมดนี้เกิดขึ้นจากความต้องการที่จะแยกแยะสิ่งที่ถูกต้องจากสิ่งที่ปลอดภัยแต่นั่นเป็นการทำให้เข้าใจผิด เราต้องแยกแยะว่าอะไรคือหน้าที่อะไรและอะไรที่เชื่อถือได้มีอะไรบ้างที่ใช้ได้จริงและอะไรที่เหมาะสมและยิ่งไปกว่านั้น: อะไรคือสิ่งที่เหมาะสมในสถานการณ์เฉพาะจากสิ่งที่อาจเหมาะสมในความหมายที่กว้างกว่า ไม่พูดถึง; ความแตกต่างระหว่างความสอดคล้องและเหมาะสม
ก่อนอื่นเราต้องเข้าใจอย่างชัดเจนว่าตัวชี้ คืออะไร
- คุณได้แสดงให้เห็นถึงแนวความคิดที่ยึดมั่นและเหมือนคนอื่น ๆ ที่อาจพบว่าภาพประกอบเหล่านี้เรียบง่ายแบบอุปถัมภ์ แต่ระดับของความสับสนที่เห็นได้ชัดที่นี่ต้องการความเรียบง่ายเช่นนั้นในการชี้แจง
ขณะที่หลายคนได้ออกมาชี้: คำชี้เป็นเพียงชื่อพิเศษสำหรับสิ่งที่เป็นเพียงดัชนีและทำให้ไม่มีอะไรมากไปกว่าที่อื่น ๆจำนวน
นี้แล้วควรจะชัดเจนในตัวเองในการพิจารณาถึงความจริงที่ว่าทุกเครื่องคอมพิวเตอร์หลักร่วมสมัยเครื่องไบนารีที่จำเป็นต้องทำงานเฉพาะกับและตัวเลข การคำนวณควอนตัมอาจเปลี่ยนแปลงสิ่งนั้น แต่มันไม่น่าเป็นไปได้สูงและมันก็ไม่ได้เกิดขึ้น
เทคนิคที่คุณได้ตั้งข้อสังเกตชี้มีความถูกต้องมากขึ้นอยู่ ; ข้อมูลเชิงลึกที่ชัดเจนที่นำเสนอการเปรียบเทียบที่สัมพันธ์กันอย่างเป็นธรรมชาติกับ 'ที่อยู่' ของบ้านหรือแปลงบนถนน
ในโมเดลหน่วยความจำแบบแบน : หน่วยความจำระบบทั้งหมดถูกจัดระเบียบในลำดับเชิงเส้นเดียว: บ้านทุกหลังในเมืองตั้งอยู่บนถนนสายเดียวกันและบ้านทุกหลังจะถูกระบุด้วยหมายเลขเดียวโดยไม่ซ้ำกัน เรียบง่ายน่ายินดี
ในรูปแบบแบ่งส่วน : องค์กรลำดับชั้นของถนนที่มีหมายเลขถูกนำเสนอข้างต้นของบ้านเลขที่เพื่อให้ที่อยู่คอมโพสิตจะต้อง
- การใช้งานบางอย่างยังคงมีความซับซ้อนมากขึ้นและจำนวนทั้งสิ้นของ 'ถนน' ไม่จำเป็นต้องรวมกับลำดับที่ต่อเนื่องกัน
- เราจำเป็นต้องสามารถย่อยสลายทุกลิงก์ลำดับชั้นกลับไปเป็นองค์กรที่เรียบง่าย ยิ่งองค์กรมีความซับซ้อนมากเท่าไหร่เราก็ยิ่งต้องกระโดดมากขึ้นเท่านั้น แต่ก็ต้องทำเป็นไปได้ อันที่จริงสิ่งนี้ยังใช้กับ 'โหมดจริง' บน x86
- มิฉะนั้นการทำแผนที่ของการเชื่อมโยงไปยังสถานที่จะไม่bijectiveเช่นการดำเนินการที่เชื่อถือได้ - ที่ระดับระบบ - ความต้องการว่ามันต้องเป็น
- ที่อยู่หลายแห่งต้องไม่จับคู่กับตำแหน่งหน่วยความจำเอกพจน์และ
- ที่อยู่เอกพจน์จะต้องไม่แมปไปยังตำแหน่งหน่วยความจำหลายแห่ง
นำเราไปบิดต่อไปที่จะเปลี่ยนปริศนาเป็นเช่นชวนชมซับซ้อนยุ่งเหยิง ด้านบนเป็นเรื่องสมควรที่จะแนะนำว่าพอยน์เตอร์เป็นที่อยู่เพื่อความง่ายและชัดเจน แน่นอนว่ามันไม่ถูกต้อง ตัวชี้เป็นไม่ได้ที่อยู่; ชี้เป็นการอ้างอิงไปยังที่อยู่ก็มีอยู่ เหมือนซองจดหมายที่มีการอ้างอิงถึงบ้าน การไตร่ตรองสิ่งนี้อาจทำให้คุณเหลือบสิ่งที่มีความหมายกับคำแนะนำของการเรียกซ้ำที่มีอยู่ในแนวคิด ยังคง; เรามีเพียงคำจำนวนมากและพูดคุยเกี่ยวกับที่อยู่ของการอ้างอิงไปยังที่อยู่และเช่นเร็ว ๆ นี้คอกม้าสมองมากที่สุดที่ที่ไม่ถูกต้องข้อยกเว้นสหกรณ์รหัส และส่วนใหญ่แล้วความตั้งใจนั้นรวบรวมมาจากบริบทดังนั้นให้เรากลับไปที่ถนน
พนักงานไปรษณีย์ในเมืองแห่งจินตนาการของเรานั้นเป็นเหมือนที่เราพบในโลก 'ของจริง' ไม่มีใครมีแนวโน้มที่จะเป็นโรคหลอดเลือดสมองเมื่อคุณพูดคุยหรือสอบถามเกี่ยวกับที่อยู่ที่ไม่ถูกต้องแต่ทุกคนสุดท้ายจะชะงักเมื่อคุณขอให้พวกเขาดำเนินการกับข้อมูลนั้น
สมมติว่ามีบ้านเพียง 20 หลังบนถนนที่เป็นเอกเทศของเรา นอกจากแกล้งทำเป็นว่าบางส่วนเข้าใจผิดหรือจิตวิญญาณ dyslexic ได้กำกับตัวอักษรหนึ่งที่สำคัญมากในการจำนวน 71 ตอนนี้เราสามารถขอให้ผู้ให้บริการของเราแฟรงก์ไม่ว่าจะมีเป็นเช่นที่อยู่และเขาจะเพียงและรายงานใจเย็น: ไม่มี เรายังสามารถคาดหวังให้เขาประเมินว่าไกลนอกถนนสถานที่แห่งนี้จะอยู่ถ้ามันไม่ได้มีอยู่: ประมาณ 2.5 เท่าไกลเกินกว่าที่สิ้นสุด สิ่งนี้จะไม่ทำให้เขาโกรธเคืองใด ๆ อย่างไรก็ตามหากเราต้องขอให้เขาส่งจดหมายนี้หรือรับสิ่งของจากสถานที่นั้นเขามีแนวโน้มที่จะค่อนข้างตรงไปตรงมาเกี่ยวกับความไม่พอใจของเขาและปฏิเสธที่จะปฏิบัติตาม
พอยน์เตอร์เป็นเพียงที่อยู่และที่อยู่เป็นเพียงตัวเลข
ตรวจสอบผลลัพธ์ต่อไปนี้:
void foo( void *p ) {
printf(“%p\t%zu\t%d\n”, p, (size_t)p, p == (size_t)p);
}
เรียกว่าเป็นพอยน์เตอร์ได้มากเท่าที่คุณต้องการใช้ได้จริงหรือไม่ กรุณาอย่าโพสต์สิ่งที่คุณพบถ้ามันล้มเหลวบนแพลตฟอร์มของคุณหรือของคุณ(ร่วมสมัย)คอมไพเลอร์บ่น
ตอนนี้เนื่องจากพอยน์เตอร์เป็นตัวเลขเพียงอย่างเดียวจึงมีความถูกต้องในการเปรียบเทียบ ในแง่หนึ่งนี่เป็นสิ่งที่ครูของคุณกำลังแสดงออก ข้อความต่อไปนี้ทั้งหมดใช้ได้อย่างสมบูรณ์- และเหมาะสม! - C และเมื่อรวบรวมจะทำงานโดยไม่มีปัญหาแม้ว่าตัวชี้ไม่จำเป็นต้องเริ่มต้นและค่าที่มีอยู่จึงอาจไม่ได้กำหนด :
- เรากำลังคำนวณ
result
อย่างชัดเจนเพื่อความชัดเจนเท่านั้นและพิมพ์เพื่อบังคับให้คอมไพเลอร์คำนวณสิ่งที่มิฉะนั้นจะซ้ำซ้อนรหัสตาย
void foo( size_t *a, size_t *b ) {
size_t result;
result = (size_t)a;
printf(“%zu\n”, result);
result = a == b;
printf(“%zu\n”, result);
result = a < b;
printf(“%zu\n”, result);
result = a - b;
printf(“%zu\n”, result);
}
แน่นอนว่าโปรแกรมนั้นมีรูปแบบไม่ดีเมื่อ a หรือ b ไม่ได้ถูกกำหนด (อ่าน: ไม่เริ่มต้นอย่างถูกต้อง ) ณ จุดที่ทำการทดสอบ แต่นั่นไม่เกี่ยวข้องกับส่วนนี้ของการสนทนาของเรา ตัวอย่างเหล่านี้มากเกินไปงบต่อไปนี้มีการรับประกัน - โดย 'มาตรฐาน' -เพื่อรวบรวมและทำงานไม่มีที่ติ แต่อย่างไรก็ตามใน -validity ของตัวชี้ใด ๆ ที่เกี่ยวข้อง
แต่ปัญหาเกิดขึ้นเมื่อตัวชี้ไม่ถูกต้องdereferenced เมื่อเราขอให้แฟรงค์ส่งหรือรับที่อยู่ที่ไม่ถูกต้องไม่มีอยู่จริง
รับตัวชี้ใด ๆ :
int *p;
ในขณะที่คำสั่งนี้จะต้องรวบรวมและเรียกใช้:
printf(“%p”, p);
... ตามที่ต้องการ:
size_t foo( int *p ) { return (size_t)p; }
... สองต่อไปนี้ในทางตรงกันข้ามจะยังคงรวบรวมได้อย่างง่ายดาย แต่ล้มเหลวในการดำเนินการเว้นแต่ตัวชี้เป็นที่ถูกต้อง - โดยที่เราที่นี่เพียงหมายความว่ามันมีการอ้างอิงอยู่ที่ประยุกต์ใช้ในปัจจุบันได้รับการเข้าถึง :
printf(“%p”, *p);
size_t foo( int *p ) { return *p; }
วิธีการเปลี่ยนแปลงที่ลึกซึ้ง? ความแตกต่างอยู่ในความแตกต่างระหว่างค่าของตัวชี้ - ซึ่งเป็นที่อยู่และค่าของเนื้อหา: ของบ้านที่หมายเลขนั้น ไม่มีปัญหาเกิดขึ้นจนกว่าตัวชี้จะถูกอ้างถึง ; จนกว่าจะมีการพยายามเข้าถึงที่อยู่ที่ลิงก์ไปถึง ในการพยายามส่งมอบหรือรับพัสดุเกินขอบเขตถนน ...
โดยการขยายหลักการเดียวกันนี้จำเป็นต้องใช้กับตัวอย่างที่ซับซ้อนมากขึ้นรวมถึงความต้องการดังกล่าวเพื่อสร้างความถูกต้องที่จำเป็น:
int* validate( int *p, int *head, int *tail ) {
return p >= head && p <= tail ? p : NULL;
}
การเปรียบเทียบเชิงความสัมพันธ์และการคำนวณทางคณิตศาสตร์นำเสนอยูทิลิตี้ที่เหมือนกันในการทดสอบความเท่าเทียมกันและมีความถูกต้องเท่าเทียมกัน - ในหลักการ อย่างไรก็ตามสิ่งที่ผลลัพธ์ของการคำนวณดังกล่าวจะมีความหมายว่าเป็นเรื่องที่แตกต่างออกไปโดยสิ้นเชิง - และเป็นปัญหาที่ระบุโดยใบเสนอราคาที่คุณระบุไว้อย่างแม่นยำ
ใน C อาร์เรย์คือบัฟเฟอร์ที่ต่อเนื่องซึ่งเป็นอนุกรมที่ไม่ต่อเนื่องของตำแหน่งหน่วยความจำ การเปรียบเทียบและการคำนวณทางคณิตศาสตร์ที่ใช้กับพอยน์เตอร์ที่สถานที่อ้างอิงภายในชุดเอกพจน์นั้นเป็นไปตามธรรมชาติและมีความหมายอย่างชัดเจนในความสัมพันธ์ซึ่งกันและกันและกับ 'อาร์เรย์' นี้ ได้อย่างแม่นยำเช่นเดียวกับทุกบล็อกจัดสรรผ่านหรือmalloc
เนื่องจากความสัมพันธ์เหล่านี้มีความหมายโดยนัยคอมไพเลอร์จึงสามารถสร้างความสัมพันธ์ที่ถูกต้องระหว่างพวกเขาดังนั้นจึงมั่นใจได้ว่าการคำนวณจะให้คำตอบที่คาดไว้sbrk
การแสดงยิมนาสติกที่คล้ายกันในตัวชี้ที่อ้างอิงบล็อกหรืออาร์เรย์ที่แตกต่างกันนั้นไม่ได้เสนอยูทิลิตี้ที่มีอยู่ในตัวและชัดเจน มากขึ้นเนื่องจากความสัมพันธ์ใด ๆ ที่มีอยู่ในช่วงเวลาหนึ่งอาจถูกทำให้เป็นโมฆะโดยการจัดสรรใหม่ที่ตามมาซึ่งประเด็นที่มีแนวโน้มสูงที่จะเปลี่ยนแปลงแม้จะถูกคว่ำ ในกรณีเช่นนี้คอมไพเลอร์ไม่สามารถรับข้อมูลที่จำเป็นเพื่อสร้างความมั่นใจในสถานการณ์ก่อนหน้านี้
คุณแต่เป็นโปรแกรมเมอร์อาจมีความรู้ดังกล่าว! และในบางกรณีจำเป็นต้องใช้ประโยชน์จากสิ่งนั้น
มีกำลังจึงตกอยู่ในสถานการณ์ที่แม้เรื่องนี้จะมีทั้งที่ถูกต้องและสมบูรณ์เหมาะสม
ในความเป็นจริงที่เป็นว่าสิ่งที่malloc
ตัวเองจะต้องทำภายในเมื่อเวลามาถึงพยายามผสานบล็อกยึด - ที่ส่วนใหญ่ของสถาปัตยกรรม เช่นเดียวกับที่เป็นจริงสำหรับตัวจัดสรรระบบปฏิบัติการเช่นที่อยู่เบื้องหลังว่าsbrk
; ถ้ามากขึ้นอย่างเห็นได้ชัด , บ่อยในที่แตกต่างกันมากขึ้นหน่วยงานที่มากขึ้นอย่างยิ่ง - และมีความเกี่ยวข้องยังบนแพลตฟอร์มที่นี้malloc
อาจจะไม่ และมีกี่คนที่ไม่ได้เขียนใน C?
ความถูกต้องความปลอดภัยและความสำเร็จของการกระทำย่อมเป็นผลมาจากระดับของความเข้าใจที่มันถูกกำหนดและนำไปใช้
ในคำพูดที่คุณเสนอให้ Kernighan และ Ritchie กำลังพูดถึงประเด็นที่เกี่ยวข้องอย่างใกล้ชิด พวกเขาจะกำหนดข้อ จำกัดของภาษาและอธิบายวิธีการที่คุณอาจจะใช้ประโยชน์จากความสามารถของคอมไพเลอร์ที่จะปกป้องคุณอย่างน้อยการตรวจสอบโครงสร้างที่ผิดพลาดที่อาจเกิดขึ้น พวกเขากำลังอธิบายความยาวที่กลไกสามารถ- ถูกออกแบบ -เพื่อไปที่เพื่อช่วยเหลือคุณในงานการเขียนโปรแกรมของคุณ คอมไพเลอร์เป็นคนรับใช้ของคุณคุณเป็นผู้เชี่ยวชาญ อย่างไรก็ตามปราชญ์ที่ฉลาดนั้นเป็นคนที่คุ้นเคยกับความสามารถของผู้รับใช้ต่าง ๆ อย่างใกล้ชิด
ภายในบริบทนี้พฤติกรรมที่ไม่ได้กำหนดทำหน้าที่เพื่อระบุอันตรายที่อาจเกิดขึ้นและความเป็นไปได้ของอันตราย ที่จะไม่บ่งบอกถึงการลงโทษที่ใกล้เข้ามาหรือการสิ้นสุดของโลกอย่างที่เรารู้ มันหมายความว่าเรา - 'หมายถึงคอมไพเลอร์' - ไม่สามารถคาดเดาเกี่ยวกับสิ่งที่สิ่งนี้อาจจะเป็นหรือเป็นตัวแทนและด้วยเหตุผลนี้เราเลือกที่จะล้างมือของเราในเรื่องนี้ เราจะไม่รับผิดชอบต่อความผิดพลาดที่อาจเกิดขึ้นจากการใช้งานหรือการใช้สถานที่นี้ผิด
ผลก็แค่พูดว่า: 'นอกเหนือจากจุดนี้คาวบอย : คุณอยู่ในตัวของคุณเอง ... '
อาจารย์ของคุณกำลังพยายามแสดงให้เห็นถึงความแตกต่างของคุณ
สังเกตว่าพวกเขาใส่ใจอย่างมากในการสร้างตัวอย่างของพวกเขา และมันเปราะยังไง โดยจดที่อยู่ของa
ใน
p[0].p0 = &a;
คอมไพเลอร์ถูกบีบบังคับให้จัดสรรหน่วยเก็บจริงสำหรับตัวแปรแทนที่จะวางลงในรีจิสเตอร์ มันเป็นตัวแปรอัตโนมัติอย่างไรก็ตามโปรแกรมเมอร์ไม่สามารถควบคุมตำแหน่งที่ได้รับมอบหมายและไม่สามารถคาดเดาได้อย่างถูกต้องเกี่ยวกับสิ่งที่จะตามมา ซึ่งเป็นสาเหตุที่a
ต้องตั้งค่าให้เท่ากับศูนย์เพื่อให้โค้ดทำงานตามที่คาดไว้
เพียงแค่เปลี่ยนบรรทัดนี้:
char a = 0;
สำหรับสิ่งนี้:
char a = 1; // or ANY other value than 0
ทำให้เกิดลักษณะการทำงานของโปรแกรมที่จะกลายเป็นไม่ได้กำหนด อย่างน้อยที่สุดคำตอบแรกจะเป็น 1; แต่ปัญหาคือสิ่งที่น่ากลัวยิ่งกว่า
ตอนนี้รหัสกำลังเชิญภัยพิบัติ
ในขณะที่ยังคงใช้งานได้ดีและสอดคล้องกับมาตรฐานแต่ตอนนี้มันมีรูปแบบไม่ดีและถึงแม้ว่าจะแน่ใจว่าได้รวบรวม แต่อาจล้มเหลวในการดำเนินการในพื้นที่ต่างๆ สำหรับตอนนี้มีหลายปัญหา - ไม่มีซึ่งคอมไพเลอร์คือสามารถที่จะรับรู้
strcpy
จะเริ่มต้นตามที่อยู่ของa
และดำเนินการต่อไปนี้เพื่อกิน - และถ่ายโอน - ไบต์หลังไบต์จนกว่าจะพบ null
p1
ชี้ได้รับการเริ่มต้นได้ที่บล็อกของตรง10ไบต์
หากa
เกิดขึ้นที่ปลายของบล็อกและกระบวนการไม่สามารถเข้าถึงสิ่งต่อไปนี้การอ่าน p0 [1] ครั้งต่อไปจะทำให้เกิด segfault สถานการณ์นี้ไม่น่าจะเกิดขึ้นกับสถาปัตยกรรม x86 แต่เป็นไปได้
หากสามารถเข้าถึงพื้นที่ที่อยู่นอกเหนือจากที่อยู่a
จะไม่เกิดข้อผิดพลาดในการอ่าน แต่โปรแกรมจะไม่ถูกบันทึกจากความโชคร้าย
หากมีศูนย์เกิดขึ้นภายในสิบเริ่มต้นที่ที่อยู่ของa
มันอาจยังคงอยู่รอดเพราะจากนั้นstrcpy
จะหยุดและอย่างน้อยเราจะไม่ได้รับการละเมิดการเขียน
ถ้ามันจะไม่โทษฐานสำหรับการอ่านผิดปกติ แต่ไม่มีศูนย์ byteเกิดขึ้นในช่วง 10 นี้strcpy
จะดำเนินต่อไปและพยายามที่จะเขียนmalloc
เกินบล็อกจัดสรรโดย
หากพื้นที่นี้ไม่ได้เป็นเจ้าของโดยกระบวนการ segfault ควรจะถูกเรียกใช้ทันที
ยังคงหายนะมากขึ้น - และลึกซึ้ง --- สถานการณ์เกิดขึ้นเมื่อบล็อกต่อไปนี้จะเป็นเจ้าของโดยกระบวนการสำหรับข้อผิดพลาดแล้วไม่สามารถถูกตรวจพบว่าไม่มีสัญญาณสามารถยกและดังนั้นจึงอาจ'ปรากฏ' ยัง 'งาน' , ในขณะที่มันจะถูกเขียนทับข้อมูลอื่น ๆ โครงสร้างการจัดการของผู้จัดสรรหรือแม้แต่รหัส (ในสภาพแวดล้อมการทำงานบางอย่าง)
นี่คือเหตุผลที่เกี่ยวข้องกับตัวชี้ข้อบกพร่องสามารถทำให้ยากที่จะติดตาม ลองนึกภาพเส้นเหล่านี้ฝังลึกภายในรหัสที่เกี่ยวข้องอย่างประณีตหลายพันบรรทัดที่คนอื่นเขียนและคุณจะถูกนำไปสู่การเจาะลึก
อย่างไรก็ตามโปรแกรมจะต้องรวบรวมเพราะมันยังคงสมบูรณ์และเป็นไปตามมาตรฐาน C.
ข้อผิดพลาดประเภทนี้ไม่มีมาตรฐานและไม่มีคอมไพเลอร์สามารถป้องกันไม่ระวัง ฉันคิดว่านั่นคือสิ่งที่พวกเขาตั้งใจจะสอนคุณ
คนหวาดระแวงอย่างต่อเนื่องพยายามที่จะเปลี่ยนธรรมชาติของ C ในการกำจัดของความเป็นไปได้มีปัญหาเหล่านี้และอื่น ๆ ช่วยเราจากตัวเราเอง แต่นั่นก็ไม่ตรงไปตรงมา นี่เป็นความรับผิดชอบที่เราจำเป็นต้องยอมรับเมื่อเราเลือกที่จะไล่ตามอำนาจและได้รับอิสรภาพที่การควบคุมเครื่องจักรโดยตรงและครอบคลุมยิ่งขึ้นให้เรา ผู้โปรโมตและผู้ไล่ตามความสมบูรณ์แบบในการปฏิบัติงานจะไม่ยอมรับสิ่งที่น้อยกว่า
ความสะดวกในการพกพาและความเป็นสากลที่จะนำเสนอเป็นข้อพิจารณาแยกต่างหากโดยพื้นฐานและทุกสิ่งที่มาตรฐานพยายามหาที่อยู่:
เอกสารนี้ระบุรูปแบบและกำหนดความหมายของโปรแกรมการแสดงออกในการเขียนโปรแกรมภาษาซีใช้ในจุดประสงค์คือการส่งเสริมการพกพาความน่าเชื่อถือ, การบำรุงรักษาและการดำเนินการที่มีประสิทธิภาพของโปรแกรมภาษา C บนความหลากหลายของการคำนวณระบบ
นี่คือเหตุผลว่าทำไมมันจึงเหมาะสมอย่างยิ่งที่จะทำให้แตกต่างจากข้อกำหนดและข้อกำหนดทางเทคนิคของภาษานั้น ๆ ขัดกับสิ่งที่หลายคนดูเหมือนจะเชื่อทั่วไปเป็นถือเพื่อที่โดดเด่นและเป็นแบบอย่าง
สรุป:
- การตรวจสอบและจัดการตัวชี้ตัวได้อย่างสม่ำเสมอที่ถูกต้องและมักจะมีผล การตีความผลลัพธ์อาจหรืออาจไม่มีความหมาย แต่จะไม่ได้รับความหายนะจนกว่าตัวชี้จะถูกอ้างถึง ; จนกว่าจะมีการพยายามเข้าถึงที่อยู่ที่เชื่อมโยงกับ
สิ่งนี้ไม่จริงการเขียนโปรแกรมตามที่เรารู้- และรักมัน -คงเป็นไปไม่ได้
C
กับสิ่งที่เป็นความปลอดภัยC
ใน การเปรียบเทียบสองพอยน์เตอร์กับประเภทเดียวกันสามารถทำได้เสมอ (เช่นการตรวจสอบความเสมอภาค) โดยใช้การคำนวณและการเปรียบเทียบ>
และ<
มีความปลอดภัยเมื่อใช้ภายในอาร์เรย์ที่กำหนด (หรือบล็อกหน่วยความจำ)