0Pricing
C Academy · บทเรียน

ขยายด้วย realloc

ปรับขนาดอาร์เรย์แบบไดนามิก

ขยายด้วย realloc เป็นบทเรียน C Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C Academy มีบทเรียนทั้งหมด 4 บทเรียน

เมื่อ malloc ครั้งเดียวไม่เพียงพอ

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

realloc ช่วยให้คุณปรับขนาดบล็อกบนฮีปที่มีอยู่ โดยรักษาข้อมูลเดิมที่อยู่ในบล็อกไว้

รูปแบบการเรียก realloc

realloc(ptr, new_bytes) รับตัวชี้เดิมและขนาดใหม่ทั้งหมดในหน่วยไบต์

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

int *bigger = realloc(a, new_n * sizeof(*a));

บล็อกอาจถูกย้าย

realloc อาจขยายบล็อกในตำแหน่งเดิม หรืออาจจัดสรรบล็อกใหม่ คัดลอกข้อมูลของคุณ แล้วคืนบล็อกเดิม

ไม่ว่ากรณีใด ตัวชี้เดิมอาจใช้ไม่ได้อีกต่อไป คุณต้องใช้ตัวชี้ที่ฟังก์ชันคืนให้ตั้งแต่นี้เป็นต้นไป

a = realloc(a, new_n * sizeof(*a));
/* the old value of a may no longer be valid */

กับดักการกำหนดค่าให้ตัวเอง

การเขียน a = realloc(a, ...) ดูเป็นระเบียบแต่มีอันตราย หาก realloc คืนค่า NULL คุณจะเขียนทับ a และสูญเสียตัวชี้เดิม ทำให้บล็อกเก่ารั่วไหล

ให้ใช้ตัวแปรชั่วคราวแทน

int *tmp = realloc(a, new_n * sizeof(*a));
if (tmp == NULL) { /* a is still valid */ return 1; }
a = tmp;

การขยายแถวลำดับอย่างปลอดภัย

โปรแกรมนี้จัดสรรจำนวนเต็ม 3 ตัว แล้วขยายเป็น 6 ตัวด้วย realloc โดยรักษาค่าสามค่าแรกไว้

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *a = malloc(3 * sizeof(*a));
    if (!a) return 1;
    for (int i = 0; i < 3; i++) a[i] = i + 1;

    int *tmp = realloc(a, 6 * sizeof(*a));
    if (!tmp) { free(a); return 1; }
    a = tmp;

    for (int i = 3; i < 6; i++) a[i] = i + 1;
    for (int i = 0; i < 6; i++) printf("%d\n", a[i]);
    free(a);
    return 0;
}

ไบต์ใหม่ยังไม่ได้กำหนดค่า

เมื่อคุณขยายบล็อก พื้นที่เพิ่มเติมตอนท้ายจะมีค่าขยะเช่นเดียวกับหน่วยความจำจาก malloc ที่เพิ่งจัดสรร

realloc รักษาข้อมูลเดิมไว้ แต่ไม่ได้กำหนดค่าเป็นศูนย์ให้พื้นที่ใหม่ คุณต้องกำหนดค่าให้พื้นที่นั้นก่อนอ่าน

a = realloc(a, 6 * sizeof(*a));
for (int i = 3; i < 6; i++) a[i] = 0;  /* clear new slots */

กลยุทธ์การเพิ่มเป็นสองเท่า

การเรียก realloc สำหรับสมาชิกทุกตัวช้า เทคนิคคลาสสิกคือเพิ่มความจุเป็นสองเท่าทุกครั้งที่พื้นที่ไม่พอ

วิธีนี้ทำให้จำนวนครั้งที่ปรับขนาดใหม่มีน้อยเมื่อแถวลำดับเติบโต และให้ประสิทธิภาพโดยเฉลี่ยที่ดี

if (count == cap) {
    cap = cap ? cap * 2 : 4;
    int *tmp = realloc(a, cap * sizeof(*a));
    if (!tmp) { free(a); return 1; }
    a = tmp;
}

สร้างแถวลำดับด้วยการเพิ่มต่อท้าย

โปรแกรมนี้เริ่มจากแถวลำดับว่าง แล้วเพิ่มตัวเลขต่อท้าย โดยเพิ่มความจุเป็นสองเท่าเมื่อจำเป็น

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *a = NULL;
    size_t count = 0, cap = 0;
    for (int v = 1; v <= 5; v++) {
        if (count == cap) {
            cap = cap ? cap * 2 : 2;
            int *tmp = realloc(a, cap * sizeof(*a));
            if (!tmp) { free(a); return 1; }
            a = tmp;
        }
        a[count++] = v;
    }
    for (size_t i = 0; i < count; i++) printf("%d\n", a[i]);
    free(a);
    return 0;
}

realloc(NULL, n) ทำงานเหมือน malloc

หากส่ง NULL เป็นตัวชี้ realloc จะทำงานเหมือน malloc ทุกประการ

ด้วยเหตุนี้การเริ่มต้นด้วย a = NULL จึงใช้ได้ในลูปเพิ่มความจุเป็นสองเท่า เพราะ realloc ครั้งแรกจะจัดสรรบล็อกเริ่มต้น

int *a = NULL;
a = realloc(a, 4 * sizeof(*a));  /* same as malloc(4 * sizeof(*a)) */

การลดขนาดบล็อก

realloc ยังสามารถทำให้บล็อกมีขนาดเล็กลงได้ ข้อมูลจนถึงขนาดใหม่จะถูกเก็บไว้ ส่วนที่เหลือจะถูกทิ้ง

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

int *tmp = realloc(a, 2 * sizeof(*a));  /* down from more */
if (tmp) a = tmp;

หลีกเลี่ยงค่าล้นในการคำนวณ

เมื่อความจุเพิ่มขึ้นมาก cap * sizeof(*a) อาจมีค่าล้นชนิดข้อมูล size_t และวนกลับกลายเป็นตัวเลขขนาดเล็กมาก

สำหรับอาร์เรย์ขนาดใหญ่มาก ให้ตรวจป้องกันการคูณล้น หรือใช้ reallocarray บนระบบที่รองรับ

if (cap > SIZE_MAX / sizeof(*a)) { /* overflow */ return 1; }
int *tmp = realloc(a, cap * sizeof(*a));

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ทดสอบความเข้าใจเกี่ยวกับ realloc ของคุณ

ทบทวน

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

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

คำถามที่พบบ่อย

บทเรียน “ขยายด้วย realloc” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “ขยายด้วย realloc” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “ขยายด้วย realloc”

ปรับขนาดอาร์เรย์แบบไดนามิก คุณปฏิบัติ C Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน C Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “ขยายด้วย realloc” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน C Academy นี้ได้ไหม

ได้ บทเรียน C Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. จัดสรรอาร์เรย์
  2. ขยายด้วย realloc
  3. ชนิดเวกเตอร์ที่นำกลับมาใช้ได้
  4. คืนหน่วยความจำและหลีกเลี่ยงการรั่วไหล
← กลับไปที่ C Academy