อาร์เรย์ถ่าน C ++ [] หน่วยความจำรั่ว [ซ้ำ]

Aug 18 2020

ฉันสร้าง char arr [] และกำหนดให้สตริงลิเทอรัล

char arr[] = "some string";                  // arr occupies 12 chars in memory
std::cout << std::strlen(arr)  << std::endl; // lenght is 11 chars + 1 null-terminator
                                             //arr[11] is '\0'

ต่อไปฉันใส่ null-terminator เป็น 6 องค์ประกอบ

arr[5] = '\0';
std::cout << std::strlen(arr) << std::endl; // lenght is 5 chars  + 1 null-terminator
  1. หน่วยความจำรั่วหรือไม่?
  2. คอมไพเลอร์จะรู้ได้อย่างไรว่าต้องว่างหน่วยความจำหลังจาก '\ 0' เป็นครั้งแรก (เมื่อไหร่จะลบตัวแปร arr)
  3. เป็นไปได้ไหมที่จะเปลี่ยนความยาวของตัวแปร arr นี้และแจ้งให้คอมไพเลอร์ทราบว่ามันควรจะว่างมากแค่ไหนเมื่อลบตัวแปร

คำตอบ

5 user253751 Aug 18 2020 at 13:03
  1. หน่วยความจำรั่วหรือไม่?

ไม่

  1. คอมไพเลอร์จะรู้ได้อย่างไรว่าต้องว่างหน่วยความจำหลังจาก '\ 0' เป็นครั้งแรก (เมื่อไหร่จะลบตัวแปร arr)

ตัวแปรคือ 12 ตัวอักษร เหมือนกับการเขียน:

char arr[12] = "some string";

ดังนั้นมันจะฟรี 12 ตัวอักษรเสมอ ตัวแปรคืออาร์เรย์ 12 ตัวอักษร ความจริงที่ว่าถ่านตัวที่ 6 เป็น '\ 0' นั้นไม่เกี่ยวข้องเลย

อย่างไรก็ตามเมื่อคุณตั้งค่าอักขระที่ 6 เป็น "\ 0" แล้วคุณจะยังคงได้รับอนุญาตให้ใช้ทั้ง 12 ตัวอักษรเนื่องจากยังคงเป็นอาร์เรย์ 12 อักขระ แม้แต่คนที่อยู่หลัง "\ 0" แต่คุณไม่สามารถเก็บ 13 ตัวอักษรไว้ในนั้นได้

  1. เป็นไปได้ไหมที่จะเปลี่ยนความยาวของตัวแปร arr นี้และแจ้งให้คอมไพเลอร์ทราบว่ามันควรจะว่างมากแค่ไหนเมื่อลบตัวแปร

ไม่ไม่สามารถเปลี่ยนขนาดของตัวแปรใด ๆ

6 cigien Aug 18 2020 at 13:03

ในรหัสนี้:

char arr[] = "some string";

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

2 JoopEggen Aug 18 2020 at 13:07

เพื่อความสมบูรณ์.

นอกจากนี้ยังไม่มีหน่วยความจำรั่วไหลในหน่วยความจำที่จัดสรรเช่นกันเช่น:

char* arr = (char*) malloc(12);
strcpy(arr, "some string");
arr[6] = '\0';
free(arr);

การจัดการหน่วยความจำดำเนินการโดยหน่วยความจำที่จัดสรร (12) ไม่ใช่โดยการใช้งานพื้นฐาน (nul-terminated char *) (สไตล์ C, C ++ เช่นเดียวกัน)

1 Slava Aug 18 2020 at 13:56

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

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

VladfromMoscow Aug 18 2020 at 13:16

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

ในคำประกาศนี้

char arr[] = "some string"; 

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

การใช้คำสั่งนี้

arr[5] = '\0';

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

คอมไพเลอร์จะรู้ได้อย่างไรว่าต้องว่างหน่วยความจำหลังจาก '\ 0' เป็นครั้งแรก (เมื่อไหร่จะลบตัวแปร arr)

เนื่องจากคอมไพเลอร์ (หรือระบบ) รู้ว่าวัตถุของประเภทอาร์เรย์ถูกประกาศอย่างไร

สำหรับวัตถุมีการจัดสรร 12 ไบต์

char arr[] = "some string"; 

เป็นไปได้ไหมที่จะเปลี่ยนความยาวของตัวแปร arr นี้และแจ้งให้คอมไพเลอร์ทราบว่ามันควรจะว่างมากแค่ไหนเมื่อลบตัวแปร

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

คุณสามารถจัดสรรออบเจ็กต์ใหม่ได้หากคุณใช้ตัวดำเนินการnewเพื่อจัดสรรวัตถุดังตัวอย่างเช่น

char *arr = new char[12];

std::strcpy( arr, "some string" );

//...

char *tmp = new char[20];

strcpy( tmp, "another " );
strcat( tmp, arr );

delete [] arr;
arr = tmp;