ฉันควรเริ่มด้วยการบอกว่า C และ C ++ เป็นภาษาโปรแกรมแรกที่ฉันได้เรียนรู้ ฉันเริ่มต้นด้วย C จากนั้นทำ C ++ ที่โรงเรียนมาก ๆ จากนั้นกลับไปที่ C เพื่อพูดให้คล่อง
สิ่งแรกที่ทำให้ฉันสับสนเกี่ยวกับพอยน์เตอร์เมื่อเรียนรู้ C นั้นง่าย:
char ch;
char str[100];
scanf("%c %s", &ch, str);
ความสับสนนี้ส่วนใหญ่เกิดจากการได้รับการแนะนำให้ใช้การอ้างอิงตัวแปรสำหรับอาร์กิวเมนต์ OUT ก่อนที่จะมีการแนะนำพอยน์เตอร์ให้ฉัน ฉันจำได้ว่าฉันข้ามการเขียนตัวอย่างแรก ๆ ในC สำหรับ Dummiesเพราะมันง่ายเกินไปที่จะไม่ได้รับโปรแกรมแรกที่ฉันเขียนเพื่อทำงาน (น่าจะเป็นเพราะสิ่งนี้)
สิ่งที่ทำให้เกิดความสับสนเกี่ยวกับเรื่องนี้คือสิ่งที่&ch
เกิดขึ้นจริงและทำไมstr
ไม่ต้องการมัน
หลังจากที่ฉันคุ้นเคยกับการที่ฉันจำได้ว่าครั้งต่อไปจะสับสนเกี่ยวกับการจัดสรรแบบไดนามิก ฉันรู้ว่าในบางจุดที่การมีตัวชี้ไปยังข้อมูลไม่มีประโยชน์อย่างยิ่งหากไม่มีการจัดสรรแบบไดนามิกบางประเภท
char * x = NULL;
if (y) {
char z[100];
x = z;
}
เพื่อพยายามจัดสรรพื้นที่แบบไดนามิก มันไม่ทำงาน ฉันไม่แน่ใจว่ามันจะทำงานได้ แต่ฉันไม่รู้ว่ามันจะทำงานได้อย่างไร
ต่อมาฉันได้เรียนรู้เกี่ยวกับmalloc
และnew
แต่พวกเขาดูเหมือนจะเป็นผู้สร้างหน่วยความจำที่มีมนต์ขลังให้ฉัน ฉันไม่รู้อะไรเลยว่าพวกเขาจะทำงานอย่างไร
หลังจากนั้นไม่นานฉันก็ถูกสอนให้รู้จักการเรียกซ้ำอีกครั้ง (ฉันได้เรียนรู้ด้วยตัวเองก่อนหน้านี้ แต่อยู่ในชั้นเรียนตอนนี้) และฉันถามว่ามันทำงานอย่างไรภายใต้ประทุน - ที่เก็บตัวแปรแยกต่างหาก อาจารย์ของฉันพูดว่า "ในกองซ้อน" และมีหลายสิ่งที่ชัดเจนสำหรับฉัน ฉันเคยได้ยินคำศัพท์นี้มาก่อนและเคยใช้งานซอฟต์แวร์ซ้อนกันมาก่อน ฉันเคยได้ยินคนอื่นพูดถึง "กองซ้อน" นานมาแล้ว แต่ลืมไปแล้ว
รอบคราวนี้ฉันก็ตระหนักว่าการใช้อาร์เรย์หลายมิติใน C อาจทำให้สับสนมาก ฉันรู้ว่าพวกเขาทำงานอย่างไร แต่พวกเขาเป็นเรื่องง่ายที่จะพันกันเมื่อฉันตัดสินใจที่จะลองใช้พวกเขาเมื่อใดก็ตามที่ฉันสามารถทำได้ ฉันคิดว่าปัญหาที่นี่ส่วนใหญ่เป็นวากยสัมพันธ์ (โดยเฉพาะอย่างยิ่งส่งผ่านหรือส่งคืนจากฟังก์ชัน)
ตั้งแต่ฉันเขียน C ++ สำหรับโรงเรียนในปีหน้าหรือสองปีฉันมีประสบการณ์มากมายในการใช้พอยน์เตอร์สำหรับโครงสร้างข้อมูล ที่นี่ฉันมีชุดปัญหาใหม่ - การพอยน์เตอร์พอยน์เตอร์ ฉันจะมีพอยน์เตอร์หลายระดับ (เช่นnode ***ptr;
) พาฉันขึ้นมา ฉันจะตรวจสอบตัวชี้จำนวนครั้งที่ผิดและในที่สุดก็หันไปหาจำนวนที่*
ฉันต้องการโดยการลองผิดลองถูก
ในบางจุดฉันได้เรียนรู้ว่าฮีปของโปรแกรมทำงานอย่างไร (เรียงลำดับ แต่ดีพอที่มันจะไม่ทำให้ฉันไม่ทำงานอีกต่อไปในตอนกลางคืน) ฉันจำได้ว่าอ่านว่าถ้าคุณดูสักสองสามไบต์ก่อนที่ตัวชี้malloc
บนระบบหนึ่งจะกลับมาคุณจะเห็นจำนวนข้อมูลที่จัดสรรจริง ฉันรู้ว่ารหัสในmalloc
สามารถขอหน่วยความจำเพิ่มเติมจากระบบปฏิบัติการและหน่วยความจำนี้ไม่ได้เป็นส่วนหนึ่งของไฟล์ปฏิบัติการของฉัน การมีความคิดในการทำงานที่ดีว่าการmalloc
ทำงานนั้นมีประโยชน์จริงๆ
หลังจากนี้ฉันก็เข้าเรียนในชั้นเรียนซึ่งไม่ได้สอนฉันมากเกี่ยวกับพอยน์เตอร์เนื่องจากโปรแกรมเมอร์ส่วนใหญ่อาจคิดว่า มันทำให้ฉันคิดเพิ่มเติมเกี่ยวกับสิ่งที่ประกอบรหัสของฉันอาจถูกแปลเป็น ฉันพยายามเขียนโค้ดที่มีประสิทธิภาพเสมอ แต่ตอนนี้ฉันมีแนวคิดที่ดีกว่า
ฉันยังเอาคู่ของการเรียนที่ผมต้องเขียนบางกระเพื่อม เมื่อเขียนเสียงกระเพื่อมฉันไม่ได้กังวลเกี่ยวกับประสิทธิภาพเหมือนใน C. ฉันมีความคิดน้อยมากรหัสนี้อาจแปลเป็นถ้ารวบรวม แต่ฉันรู้ว่ามันดูเหมือนจะใช้สัญลักษณ์ที่มีชื่อท้องถิ่น (ตัวแปร) ทำ สิ่งต่าง ๆ ง่ายขึ้นมาก ในบางจุดฉันเขียนโค้ดการหมุนทรี AVL บางส่วนในเสียงกระเพื่อมเล็กน้อยซึ่งฉันมีเวลาเขียนยากมากใน C ++ เนื่องจากปัญหาตัวชี้ ฉันตระหนักว่าสิ่งที่ฉันไม่ชอบในสิ่งที่ฉันคิดว่าเป็นตัวแปรท้องถิ่นที่เกินความสามารถของฉันในการเขียนและโปรแกรมอื่น ๆ ใน C ++
ฉันยังเรียนคอมไพเลอร์ด้วย ขณะที่อยู่ในชั้นเรียนนี้ฉันได้เรียนรู้เกี่ยวกับวัสดุขั้นสูงและเรียนรู้เกี่ยวกับการมอบหมายเดี่ยวแบบคงที่ (SSA) และตัวแปรที่ตายแล้วซึ่งไม่สำคัญยกเว้นว่าจะสอนให้ฉันรู้ว่าผู้รวบรวมที่เหมาะสมจะทำหน้าที่จัดการกับตัวแปรต่างๆ ไม่ได้ใช้อีกต่อไป ฉันรู้แล้วว่าตัวแปรเพิ่มเติม (รวมถึงพอยน์เตอร์) ที่มีประเภทที่ถูกต้องและชื่อที่ดีจะช่วยให้ฉันเก็บสิ่งต่าง ๆ ไว้ในหัวของฉันได้ แต่ตอนนี้ฉันก็รู้ว่าการหลีกเลี่ยงพวกเขาด้วยเหตุผลด้านประสิทธิภาพก็ยิ่งโง่กว่าอาจารย์ ผม.
ดังนั้นสำหรับฉันการรู้เล็กน้อยเกี่ยวกับเค้าโครงหน่วยความจำของโปรแกรมช่วยได้มาก การคิดว่าโค้ดของฉันมีความหมายอย่างไรทั้งในเชิงสัญลักษณ์และบนฮาร์ดแวร์ช่วยฉันออกมา การใช้ตัวชี้เฉพาะที่มีประเภทที่ถูกต้องช่วยได้มาก ฉันมักจะเขียนโค้ดที่ดูเหมือน:
int foo(struct frog * f, int x, int y) {
struct leg * g = f->left_leg;
struct toe * t = g->big_toe;
process(t);
เพื่อที่ว่าถ้าฉันสกรูประเภทตัวชี้มันชัดเจนมากโดยข้อผิดพลาดของคอมไพเลอร์ปัญหาคืออะไร ถ้าฉันทำ:
int foo(struct frog * f, int x, int y) {
process(f->left_leg->big_toe);
และมีตัวชี้ประเภทใดที่ไม่ถูกต้องข้อผิดพลาดของคอมไพเลอร์จะยากกว่ามากในการคิดออก ฉันจะถูกล่อลวงให้หันไปใช้การลองผิดลองถูกและอาจทำให้สิ่งต่าง ๆ แย่ลง