อาร์เรย์แบบคงที่เทียบกับอาร์เรย์แบบไดนามิกใน C ++


93

อะไรคือความแตกต่างระหว่างอาร์เรย์แบบคงที่และอาร์เรย์แบบไดนามิกใน C ++?

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

ฉันคิดว่าคงถูกสร้างขึ้นในเวลาคอมไพล์และไดนามิกที่รันไทม์ แต่ฉันอาจเข้าใจผิดเกี่ยวกับการจัดสรรหน่วยความจำ

คุณสามารถอธิบายความแตกต่างระหว่างอาร์เรย์แบบคงที่และอาร์เรย์แบบไดนามิกใน C ++ ได้หรือไม่?


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

3
ดูแผนภาพในคำถามนี้: stackoverflow.com/a/11698458/1143274อาร์เรย์แบบสแตติกไม่ได้รับการจัดสรรบนสแต็กหรือฮีป
Evgeni Sergeev

* อาร์เรย์คงที่เทียบกับอาร์เรย์แบบไดนามิก
csguy

คำตอบ:


106

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

int foo[10];

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

int* foo = new int[10];
delete[] foo;

18
นี่เป็นสิ่งที่ถูกต้อง แต่เพื่อแสดงให้เห็นถึงวิธีการทำงานเท่านั้น โปรดอย่าทำในโค้ดจริง แต่ใช้ std :: vector แทน
Eddy Pronk

23
@Eddy: ขึ้นอยู่กับสถานการณ์ว่าจำเป็นต้องใช้เวกเตอร์หรือไม่
Casebash

6
@Casebash: คุณต้องการอาร์เรย์ในสถานการณ์ใด "คุณควรเลือกใช้เวกเตอร์หรือ deques แทนอาร์เรย์" - Herb Sutter (C ++ พิเศษเพิ่มเติม)
Eddy Pronk

16
@EddyPronk ด้วยเหตุผลการกระจายตัวของหน่วยความจำเราอาจใช้อาร์เรย์แบบคงที่เป็นพูล ไม่ใช่ทุกกรณีที่ต้องการฮีปมีประโยชน์พิเศษในการใช้อาร์เรย์แบบเรียงซ้อน คุณกำลังปฏิบัติกับ std :: vector เหมือนค้อนทองคำซึ่งเป็นรูปแบบการต่อต้านทั่วไป
void.pointer

4
@EddyPronk: ฉันค่อนข้างมั่นใจว่า Herb Sutter หมายถึงอาร์เรย์แบบไดนามิกเช่นเดียวกับint* foo = new int[N]ที่คุณมีต่อdeleteตัวคุณเองและด้วยเหตุนี้โปรดระวังเมื่อมีข้อยกเว้น อาร์เรย์แบบคงที่ไม่มีปัญหาเหล่านี้
Alexander Malakhov

33

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

ให้ฉันอธิบาย:

ประการแรกคือ C ++ เฉพาะ:

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

สองสืบทอดมาจาก C:

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

  • ตัวแปรคงที่ประกาศภายนอกฟังก์ชันเป็นตัวแปรส่วนกลางที่สามารถเข้าถึงได้จากภายในโมดูลเดียวกันเท่านั้น (ไฟล์ซอร์สโค้ดที่มี # รวมอื่น ๆ )

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


4
+1 คำตอบของคุณถูกต้องและแม่นยำที่สุดและควรได้รับการโหวตมากกว่านี้
Z boson

หากคุณประกาศขนาดของอาร์เรย์ด้วยตัวnew[]ดำเนินการจะเป็นอย่างไรจึงไม่ทราบขนาดจนกว่าจะรันไทม์ ieint* p = new int[10]
wulfgarpro

"พวกมันจะถูกจัดสรรก่อนที่ฟังก์ชันหลักจะทำงาน" เหตุใดจึงต้องจัดสรรตัวแปรสแต็กก่อนที่จะป้อนบล็อกที่เกี่ยวข้อง
AlwaysLearning

ตัวแปรสแต็ก (โดยทั่วไปคือตัวแปรโลคัลในฟังก์ชัน) มีขนาดและตำแหน่งที่กำหนดไว้ล่วงหน้าภายในสแต็กเฟรมและสแต็กทั้งหมดจะถูกจัดสรรก่อนที่ฟังก์ชันหลักจะทำงาน @AlwaysLearning เมื่อเข้าสู่สแต็กเฟรมผ่านการเรียกใช้ฟังก์ชันตัวชี้สแต็กจะถูกอัพเดต แต่สแต็กเฟรมใหม่อยู่ภายในสแต็ก ไม่มีการจัดสรรกองซ้อนอีกต่อไป ในความเป็นจริงตัวแปรที่ใหญ่เกินไป (เช่นอาร์เรย์ขนาดใหญ่) หรือการเรียกใช้ฟังก์ชันจำนวนมากเกินไปในเวลาเดียวกันส่งผลให้เกิดสแต็กล้นซึ่งไซต์นี้มีชื่อว่า
Joshua Clayton

@JoshuaClayton ฉันคิดว่ามันไม่ถูกต้อง คุณจะจัดสรรสแต็กเฟรม (สังเกตพหูพจน์) สำหรับฟังก์ชันวนซ้ำได้อย่างไรเมื่อคุณไม่รู้ว่าจะป้อนกี่ครั้ง
AlwaysLearning

11

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

int x[10];

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

std::vector<int> x(10); // this starts with 10 elements, but the vector can be resized.

std::vectorได้operator[]กำหนดไว้เพื่อให้คุณสามารถใช้กับความหมายเดียวกันกับอาร์เรย์


1
ฉันคิดว่าค่อนข้างชัดเจนว่าโดย "อาร์เรย์แบบไดนามิก" นั้นหมายถึงอาร์เรย์ที่จัดสรรแบบไดนามิก (นั่นคือขนาดที่สามารถระบุได้แบบไดนามิกในขณะรันไทม์) Likenew int[10]
jalf

@jalf: ฉันกังวลเกี่ยวกับคำว่า 'คงที่' มากกว่า ฉันชอบเรียก "อาร์เรย์แบบไดนามิก" ว่าอาร์เรย์ขนาดจัดสรรหรือตัวแปรเพื่อความสอดคล้อง
Ben Collins

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

9

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

int arr[] = { 1, 3, 4 }; // static integer array.   
int* arr = new int[3]; // dynamic integer array.

6
อาร์เรย์ส่วนกลางเป็นอาร์เรย์แบบคงที่และถูกนำไปใช้ในส่วนข้อมูลไม่ใช่จากสแต็ก
Z boson

9

สิ่งสำคัญคือต้องมีคำจำกัดความที่ชัดเจนว่าคำศัพท์หมายถึงอะไร น่าเสียดายที่ดูเหมือนจะมีคำจำกัดความหลายคำว่าอาร์เรย์แบบคงที่และไดนามิกหมายถึงอะไร

ตัวแปรคงเป็นตัวแปรกำหนดโดยใช้การจัดสรรหน่วยความจำแบบคงที่ นี่เป็นแนวคิดทั่วไปที่ไม่ขึ้นกับ C / C ++ ใน C / C ++ เราสามารถสร้างตัวแปรแบบคงที่ด้วย global, file หรือ local scope ได้ดังนี้:

int x[10]; //static array with global scope
static int y[10]; //static array with file scope
foo() {
    static int z[10]; //static array with local scope

ตัวแปรอัตโนมัติมักจะดำเนินการโดยใช้การจัดสรรหน่วยความจำสแต็คตาม สามารถสร้างอาร์เรย์อัตโนมัติใน C / C ++ ดังนี้:

foo() {
    int w[10]; //automatic array

สิ่งที่อาร์เรย์เหล่านี้x, y, zและwมีเหมือนกันคือขนาดของแต่ละอาร์เรย์ได้รับการแก้ไขและกำหนดไว้ในเวลาคอมไพล์

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

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

foo() {
   int *d = new int[n]; //dynamically allocated array with size n     

แต่เป็นไปได้ที่จะสร้างอาร์เรย์อัตโนมัติที่มีขนาดการแก้ไขที่กำหนดไว้ที่รันไทม์โดยใช้alloca:

foo() {
    int *s = (int*)alloca(n*sizeof(int))

สำหรับอาร์เรย์ไดนามิกที่แท้จริงควรใช้บางอย่างเช่นstd::vectorใน C ++ (หรืออาร์เรย์ความยาวตัวแปรใน C )

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


3

ฉันคิดว่าในบริบทนี้หมายความว่ามันคงที่ในแง่ที่ว่าขนาดคงที่ ใช้ std :: vector มีฟังก์ชัน resize ()


2

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

int size;
cin >> size;
int dynamicArray[size];

ไม่ใช่ส่วนหนึ่งของ C ++ มาตรฐาน (ใน C99 และเป็นส่วนขยายของคอมไพเลอร์สำหรับ gcc)
crashmstr

1

อาร์เรย์แบบคงที่ :

  1. อาร์เรย์คงถูกจัดสรรหน่วยความจำในเวลาคอมไพล์
  2. ขนาดคงที่
  3. อยู่ในพื้นที่หน่วยความจำสแต็ก
  4. เช่น. : int อาร์เรย์ [10]; // อาร์เรย์ขนาด 10

อาร์เรย์แบบไดนามิก:

  1. มีการจัดสรรหน่วยความจำในขณะทำงาน
  2. ขนาดไม่คงที่
  3. อยู่ในพื้นที่หน่วยความจำ Heap
  4. เช่น. : int * array = int ใหม่ [10];

0

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


0

อาร์เรย์แบบคงที่: ประสิทธิภาพ ไม่จำเป็นต้องมีการจัดสรรแบบไดนามิกหรือการจัดสรรตำแหน่ง

อาร์เรย์ที่ประกาศใน C, C ++ ในฟังก์ชันรวมถึงตัวปรับแต่งคงที่เป็นแบบคงที่ ตัวอย่าง: static int foo [5];


1
@admdrew นั่นเป็นความจริง แต่คำถามไม่เคยตอบได้ดี คำตอบที่ดีที่สุดคือคำตอบของ Joshua Clayton แต่ฉันคิดว่าคำตอบที่ดีกว่าคือคำตอบนี้stackoverflow.com/questions/17775066/…
Z boson

@Zboson ดีที่ทราบขอบคุณ เฮ้และฉันเพิ่งรู้ว่าฉันแสดงความคิดเห็นนั้นเมื่อเกือบปีที่แล้ว
สมัคร

-3

คงที่ arrary meens กับการให้กับองค์ประกอบในด้านข้างของอาร์เรย์

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

ตัวอย่าง:

     char a[10]; //static array
       char a[];  //dynamic array

ผมคิดว่าเขาพูดถูกต้อง เมื่อคุณกำหนดความยาวที่แน่นอนให้กับอาร์เรย์ก็จะเป็นอาร์เรย์แบบคงที่และเมื่อคุณไม่ระบุความยาวก็จะเป็นอาร์เรย์แบบไดนามิก แต่ด้วยความที่เขาไม่รู้ว่าจะเขียนภาษาอังกฤษอย่างไรจึงเป็นสาเหตุที่ทำให้คนเขียนคำตอบนี้
มูฮัมหมัดเทยยับ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.