C การจัดการหน่วยความจำ


90

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

ใครช่วยแสดงตัวอย่างเวลาที่คุณจะต้องทำ "การจัดการหน่วยความจำ" บ้าง


สถานที่ที่ดีในการเรียนรู้G4G
EsmaeelE

คำตอบ:


231

มีสองตำแหน่งที่สามารถใส่ตัวแปรในหน่วยความจำได้ เมื่อคุณสร้างตัวแปรดังนี้:

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

ตัวอย่างเริ่มต้นจำนวนมากจะใช้เฉพาะตัวแปรสแตก

สแต็กเป็นสิ่งที่ดีเพราะเป็นแบบอัตโนมัติ แต่ก็มีข้อบกพร่องสองประการ: (1) คอมไพเลอร์จำเป็นต้องรู้ล่วงหน้าว่าตัวแปรมีขนาดใหญ่เพียงใดและ (b) พื้นที่สแต็กค่อนข้าง จำกัด ตัวอย่างเช่นใน Windows ภายใต้การตั้งค่าเริ่มต้นสำหรับ Microsoft linker สแต็กจะถูกตั้งค่าเป็น 1 MB และไม่ใช่ทั้งหมดสำหรับตัวแปรของคุณ

หากคุณไม่ทราบว่าอาร์เรย์ของคุณมีขนาดใหญ่เพียงใดในเวลาคอมไพล์หรือถ้าคุณต้องการอาร์เรย์หรือโครงสร้างขนาดใหญ่คุณต้องมี "แผน B"

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

(โปรดทราบว่าตัวแปรในฮีปไม่ได้ถูกจัดการโดยตรง แต่ผ่านตัวชี้)

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

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

ใน C และ C ++ คุณมีหน้าที่ล้างตัวแปรฮีปดังที่แสดงไว้ด้านบน อย่างไรก็ตามมีภาษาและสภาพแวดล้อมเช่นภาษา Java และ. NET เช่น C # ที่ใช้วิธีการอื่นซึ่งฮีปจะถูกล้างด้วยตัวเอง วิธีที่สองนี้เรียกว่า "การเก็บขยะ" เป็นวิธีที่ง่ายกว่ามากสำหรับนักพัฒนา แต่คุณต้องเสียค่าปรับในเรื่องค่าใช้จ่ายและประสิทธิภาพ มันเป็นความสมดุล

(ฉันได้อธิบายรายละเอียดมากมายเพื่อให้ง่ายขึ้น แต่หวังว่าจะได้คำตอบที่มีระดับมากกว่านี้)


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

1
บางทีคุณอาจเพิ่มหนึ่งหรือสองประโยคเกี่ยวกับตำแหน่งหน่วยความจำของตัวแปรส่วนกลาง
Michael Käfer

In C never cast return of malloc(), its cause UB, (char *)malloc(size);see stackoverflow.com/questions/605845/…
EsmaeelE

17

นี่คือตัวอย่าง สมมติว่าคุณมีฟังก์ชัน strdup () ที่ทำซ้ำสตริง:

และคุณเรียกสิ่งนี้ว่า:

คุณจะเห็นว่าโปรแกรมทำงานได้ แต่คุณได้จัดสรรหน่วยความจำ (ผ่าน malloc) โดยไม่ทำให้มันว่าง คุณสูญเสียตัวชี้ไปยังบล็อกหน่วยความจำแรกเมื่อคุณเรียก strdup ครั้งที่สอง

นี่ไม่ใช่เรื่องใหญ่สำหรับหน่วยความจำจำนวนน้อยนี้ แต่ให้พิจารณากรณี:

ตอนนี้คุณใช้หน่วยความจำไปแล้ว 11 กิกะไบต์ (อาจมากกว่านั้นขึ้นอยู่กับตัวจัดการหน่วยความจำของคุณ) และหากคุณไม่ได้ขัดข้องกระบวนการของคุณอาจทำงานได้ช้า

ในการแก้ไขคุณต้องโทรฟรี () สำหรับทุกสิ่งที่ได้รับจาก malloc () หลังจากที่คุณใช้งานเสร็จ:

หวังว่าตัวอย่างนี้จะช่วยได้!


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

ไม่มีที่เป็นส่วนหนึ่งของมาตรฐาน หากคุณเข้าสู่ C ++ คุณจะได้รับสตริงและคอนเทนเนอร์ที่จัดการหน่วยความจำอัตโนมัติ
Mark Harrison

ฉันเห็นดังนั้นจึงมี libs ของบุคคลที่สาม? ช่วยตั้งชื่อให้หน่อยได้ไหม
Lorenzo

9

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


5

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

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

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

การจัดสรรฮีปมีผลต่อภาษาน้อยกว่า โดยพื้นฐานแล้วจะเป็นชุดของการเรียกใช้ไลบรารีที่ให้สิทธิ์คุณเป็นเจ้าของบล็อกหน่วยความจำในขนาดที่กำหนดจนกว่าคุณจะพร้อมส่งคืน ('ฟรี') ฟังดูง่าย แต่เกี่ยวข้องกับความเศร้าโศกของโปรแกรมเมอร์ที่ไม่ได้บอกเล่า ปัญหานั้นง่ายมาก (ปล่อยหน่วยความจำเดิมสองครั้งหรือไม่เลย [หน่วยความจำรั่ว] ไม่จัดสรรหน่วยความจำเพียงพอ [บัฟเฟอร์ล้น] ฯลฯ ) แต่หลีกเลี่ยงและแก้ไขจุดบกพร่องได้ยาก แนวทางที่มีระเบียบวินัยสูงเป็นสิ่งจำเป็นอย่างยิ่งในทางปฏิบัติ แต่แน่นอนว่าภาษาไม่ได้บังคับอย่างแท้จริง

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


4

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

ตัวอย่าง:

ณ จุดนี้คุณได้จัดสรร 5 ไบต์สำหรับ myString และเติมด้วย "abcd \ 0" (สตริงลงท้ายด้วย null - \ 0) หากการจัดสรรสตริงของคุณคือ

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


ที่นี่คุณจัดสรร 5 ไบต์ หลวมโดยกำหนดตัวชี้ ความพยายามใด ๆ ที่จะปลดปล่อยตัวชี้นี้จะนำไปสู่พฤติกรรมที่ไม่ได้กำหนดไว้ หมายเหตุ C-Strings ไม่โอเวอร์โหลดตัวดำเนินการ = ไม่มีสำเนา
Martin York

แม้ว่าจริงๆแล้วมันขึ้นอยู่กับ malloc ที่คุณใช้ ตัวดำเนินการ malloc จำนวนมากจัดแนวเป็น 8 ไบต์ ดังนั้นหาก malloc นี้ใช้ระบบส่วนหัว / ส่วนท้าย malloc จะจอง 5 + 4 * 2 (4 ไบต์สำหรับทั้งส่วนหัวและส่วนท้าย) นั่นจะเป็น 13 ไบต์และ malloc จะให้ 3 ไบต์พิเศษสำหรับการจัดตำแหน่ง ฉันไม่ได้บอกว่ามันเป็นความคิดที่ดีที่จะใช้สิ่งนี้เพราะจะใช้เฉพาะระบบที่ malloc ทำงานเช่นนี้ แต่อย่างน้อยก็สำคัญที่จะต้องรู้ว่าเหตุใดการทำอะไรผิดจึงอาจได้ผล
kodai

Loki: ฉันแก้ไขคำตอบเพื่อใช้strcpy()แทน=; ฉันคิดว่านั่นเป็นความตั้งใจของ Chris BC
echristopherson

ฉันเชื่อว่าการป้องกันหน่วยความจำฮาร์ดแวร์ของแพลตฟอร์มสมัยใหม่จะป้องกันไม่ให้กระบวนการ userspace เขียนทับช่องว่างที่อยู่ของกระบวนการอื่น คุณจะได้รับข้อผิดพลาดในการแบ่งส่วนแทน แต่นั่นไม่ใช่ส่วนหนึ่งของ C per se
echristopherson

4

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


2

นอกจากนี้คุณอาจต้องการใช้การจัดสรรหน่วยความจำแบบไดนามิกเมื่อคุณต้องการกำหนดอาร์เรย์ขนาดใหญ่เช่น int [10000] คุณไม่สามารถวางซ้อนกันได้เพราะงั้นอืม ... คุณจะได้สแต็กล้น

อีกตัวอย่างหนึ่งที่ดีคือการใช้โครงสร้างข้อมูลเช่นรายการที่เชื่อมโยงหรือต้นไม้ไบนารี ฉันไม่มีโค้ดตัวอย่างที่จะวางที่นี่ แต่คุณสามารถ google ได้อย่างง่ายดาย


2

(ฉันเขียนเพราะฉันรู้สึกว่าคำตอบจนถึงตอนนี้ยังไม่ค่อยตรงประเด็น)

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

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

  • การใช้ข้อเท็จจริงที่ว่าmallocได้รับการรับรอง (ตามมาตรฐานภาษา) เพื่อส่งกลับตัวชี้หารด้วย 4
  • จัดสรรพื้นที่พิเศษสำหรับจุดประสงค์ที่น่ากลัวของคุณเอง
  • การสร้างพูลหน่วยความจำ s ..

รับดีบั๊ก ... ขอให้โชคดี!


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

0

@ ยูโรมิเชลลี

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


0

@ Ted Percival :
... คุณไม่จำเป็นต้องทิ้งค่าตอบแทนของ malloc ()

คุณถูกต้องแน่นอน. ฉันเชื่อว่าเป็นความจริงเสมอแม้ว่าฉันจะไม่มีสำเนาK&Rให้ตรวจสอบ

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

โดยเฉพาะอย่างยิ่งถ้าคอมไพเลอร์ของคุณเข้าใจความคิดเห็นสไตล์ C ++

ใช่ ... คุณจับฉันไปที่นั่น ฉันใช้เวลาใน C ++ มากกว่า C มากขอบคุณที่สังเกตเห็นสิ่งนั้น


@echristopherson ขอบคุณ คุณพูดถูก - แต่โปรดทราบว่า Q / A นี้มาจากเดือนสิงหาคม 2008 ก่อนที่ Stack Overflow จะเป็นเบต้าสาธารณะด้วยซ้ำ ในตอนนั้นเรายังคงหาวิธีการทำงานของไซต์ รูปแบบของคำถาม / คำตอบนี้ไม่ควรถูกมองว่าเป็นแบบจำลองสำหรับวิธีใช้ SO ขอบคุณ!
Euro Micelli

อาขอบคุณที่ชี้ให้เห็น - ตอนนั้นฉันไม่รู้ว่าแง่มุมของไซต์ยังคงอยู่ในสภาพคล่อง
echristopherson

0

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

ก. คุณต้องการให้ตัวแปรมีอายุยืนกว่าฟังก์ชันและคุณไม่ต้องการให้มีตัวแปรส่วนกลาง เช่น:

โครงสร้างคู่ {
   int วาล;
   โครงสร้างคู่ * ถัดไป;
}

โครงสร้างคู่ * new_pair (int val) {
   โครงสร้างคู่ * np = malloc (sizeof (คู่โครงสร้าง));
   np-> val = วาล;
   np-> ถัดไป = NULL;
   กลับ np;
}

ข. คุณต้องการจัดสรรหน่วยความจำแบบไดนามิก ตัวอย่างที่พบบ่อยที่สุดคืออาร์เรย์ที่ไม่มีความยาวคงที่:

int * my_special_array;
my_special_array = malloc (sizeof (int) * number_of_element);
สำหรับ (i = 0; i

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

โครงสร้างข้อมูล { int data_type; data_in_mem ยาว; }; โครงสร้างสัตว์ {/ * something * /}; โครงสร้างบุคคล {/ * บางสิ่งบางอย่าง * /}; โครงสร้างสัตว์ * read_animal (); คนโครงสร้าง * read_person (); / * ในหลัก * / ตัวอย่างข้อมูลโครงสร้าง sampe.data_type = input_type; สวิตช์ (ประเภทอินพุต) { กรณี DATA_PERSON: sample.data_in_mem = read_person (); หยุดพัก; กรณี DATA_ANIMAL: sample.data_in_mem = read_animal (); ค่าเริ่มต้น: printf ("โอ้โห! ฉันเตือนคุณอีกครั้งและฉันจะทำผิดพลาด OS ของคุณ"); }

เห็นไหมค่ายาวก็เพียงพอที่จะเก็บอะไรก็ได้ อย่าลืมปลดปล่อยมันไม่เช่นนั้นคุณจะเสียใจ นี่เป็นหนึ่งในเทคนิคที่ฉันชอบในการสนุกใน C: D

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


"เห็นไหมค่า long ก็เพียงพอที่จะเก็บทุกอย่าง" -: / คุณกำลังพูดถึงอะไรในระบบส่วนใหญ่ค่า long คือ 4 ไบต์เหมือนกับ int ทุกประการ เหตุผลเดียวที่เหมาะกับพอยน์เตอร์ในที่นี้ก็คือขนาดของ long นั้นเท่ากับขนาดตัวชี้ คุณควรใช้ void * จริงๆ
Score_U ใน

-2

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

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

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


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