อาร์เรย์ถ่าน C ++ [] หน่วยความจำรั่ว [ซ้ำ]
ฉันสร้าง 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
- หน่วยความจำรั่วหรือไม่?
- คอมไพเลอร์จะรู้ได้อย่างไรว่าต้องว่างหน่วยความจำหลังจาก '\ 0' เป็นครั้งแรก (เมื่อไหร่จะลบตัวแปร arr)
- เป็นไปได้ไหมที่จะเปลี่ยนความยาวของตัวแปร arr นี้และแจ้งให้คอมไพเลอร์ทราบว่ามันควรจะว่างมากแค่ไหนเมื่อลบตัวแปร
คำตอบ
- หน่วยความจำรั่วหรือไม่?
ไม่
- คอมไพเลอร์จะรู้ได้อย่างไรว่าต้องว่างหน่วยความจำหลังจาก '\ 0' เป็นครั้งแรก (เมื่อไหร่จะลบตัวแปร arr)
ตัวแปรคือ 12 ตัวอักษร เหมือนกับการเขียน:
char arr[12] = "some string";
ดังนั้นมันจะฟรี 12 ตัวอักษรเสมอ ตัวแปรคืออาร์เรย์ 12 ตัวอักษร ความจริงที่ว่าถ่านตัวที่ 6 เป็น '\ 0' นั้นไม่เกี่ยวข้องเลย
อย่างไรก็ตามเมื่อคุณตั้งค่าอักขระที่ 6 เป็น "\ 0" แล้วคุณจะยังคงได้รับอนุญาตให้ใช้ทั้ง 12 ตัวอักษรเนื่องจากยังคงเป็นอาร์เรย์ 12 อักขระ แม้แต่คนที่อยู่หลัง "\ 0" แต่คุณไม่สามารถเก็บ 13 ตัวอักษรไว้ในนั้นได้
- เป็นไปได้ไหมที่จะเปลี่ยนความยาวของตัวแปร arr นี้และแจ้งให้คอมไพเลอร์ทราบว่ามันควรจะว่างมากแค่ไหนเมื่อลบตัวแปร
ไม่ไม่สามารถเปลี่ยนขนาดของตัวแปรใด ๆ
ในรหัสนี้:
char arr[] = "some string";
ตัวแปรarr
คืออาร์เรย์แบบคงที่ที่มีขนาดคงที่ ที่นี่ไม่มีการจัดสรรหน่วยความจำแบบไดนามิกดังนั้นจึงไม่จำเป็นต้องกังวลเกี่ยวกับการรั่วไหลของหน่วยความจำ arr
คอมไพเลอร์จะดูแลของหน่วยความจำโดยไม่คำนึงถึงสิ่งที่คุณเขียนลงใน
เพื่อความสมบูรณ์.
นอกจากนี้ยังไม่มีหน่วยความจำรั่วไหลในหน่วยความจำที่จัดสรรเช่นกันเช่น:
char* arr = (char*) malloc(12);
strcpy(arr, "some string");
arr[6] = '\0';
free(arr);
การจัดการหน่วยความจำดำเนินการโดยหน่วยความจำที่จัดสรร (12) ไม่ใช่โดยการใช้งานพื้นฐาน (nul-terminated char *) (สไตล์ C, C ++ เช่นเดียวกัน)
ดูเหมือนว่าคุณจะย้อนกลับไป ไม่สามารถเปลี่ยนขนาดอาร์เรย์ใน C ++ ได้ระยะเวลา เนื่องจากความจริงนั้นและเนื่องจากความจริงที่ว่าถ้าคุณส่งอาร์เรย์เป็นตัวชี้คุณจะสูญเสียข้อมูลขนาดจริงของข้อตกลงอาร์เรย์นั้นถูกสร้างขึ้นสำหรับสตริงสไตล์ C - 0 ไบต์หรือที่\0
เรียกว่า null terminator ถือเป็นจุดสิ้นสุดแบบไดนามิกของสตริง ข้อตกลงหมายความว่าฟังก์ชันที่ทำงานกับสตริงสไตล์ C ถือว่าเป็นการสิ้นสุดสตริง ซึ่งช่วยให้คุณใช้อาร์เรย์ขนาดคงที่สำหรับสตริงที่มีความยาวต่างกันและส่งผ่านตัวชี้เพียงตัวเดียวโดยไม่มีขนาดของหน่วยความจำจริงไปยังฟังก์ชันเพื่ออ่านจากมัน (ตัวอย่างเช่นพิมพ์ไปยังหน้าจอ) สังเกตว่าเมื่อคุณส่งอาร์เรย์ char ไปยังฟังก์ชันที่เขียนข้อมูลลงไปคุณมักจะต้องบอกว่าขนาดอาร์เรย์จริงคืออะไรดังนั้นฟังก์ชันนั้นจะไม่เข้าถึงหน่วยความจำนอกขอบเขตเนื่องจากฟังก์ชันเหล่านั้นจะไม่สนใจเทอร์มินัลที่เป็นโมฆะหากมีอยู่แล้ว
เพียงเท่านี้ข้อตกลงนี้เกิดขึ้นกับเลเยอร์ต่างๆที่อาร์เรย์จัดการ ดังนั้นข้อมูลใด ๆ ที่คุณใส่ในอาร์เรย์นั้นจะไม่มีผลต่อขนาดจากมุมมองของภาษาสำหรับคอมไพเลอร์ C ++ ที่คุณสร้างอาร์เรย์ขนาดคงที่คุณใส่ข้อมูลบางส่วนลงไปและเมื่อถึงอายุการใช้งานคอมไพเลอร์สิ้นสุดจะทำลายมันเป็นอาร์เรย์ขนาดคงที่ทั้งหมด ไม่สนใจว่าคุณใส่ศูนย์ไบต์ไว้ที่นั่นหรือไม่
หน่วยความจำรั่วเกิดขึ้นเมื่อหน่วยความจำที่ได้รับการจัดสรรโดยโปรแกรมเมอร์ที่ใช้ประกอบการnew
และไม่ได้ถูกลบโดยใช้ผู้ประกอบการหรือdelete
delete []
ในคำประกาศนี้
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;