C Academy · บทเรียน

ชนิดเวกเตอร์ที่นำกลับมาใช้ได้

ห่อขนาดและความจุ

บทเรียน 3 จาก 413 ขั้นตอน

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

จากโค้ดที่กระจัดกระจายสู่ชนิดข้อมูล

การส่งพอยน์เตอร์ จำนวนสมาชิก และความจุไปมาด้วยตัวแปรสามตัวแยกกันมีโอกาสเกิดข้อผิดพลาดได้ง่าย

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

โครงสร้างเวกเตอร์

เวกเตอร์ต้องมีฟิลด์สามรายการ ได้แก่ พอยน์เตอร์ไปยังข้อมูล จำนวนสมาชิกที่ใช้งานอยู่ (len) และจำนวนสมาชิกที่รองรับได้ก่อนปรับขนาด (cap)

typedef struct {
    int    *data;
    size_t  len;
    size_t  cap;
} Vec;

การเริ่มต้นเวกเตอร์

เวกเตอร์ว่างมีพอยน์เตอร์ข้อมูลเป็น NULL และมีความยาวกับความจุเป็นศูนย์ ฟังก์ชันเริ่มต้นขนาดเล็กช่วยให้เจตนาของโค้ดชัดเจน

void vec_init(Vec *v) {
    v->data = NULL;
    v->len = 0;
    v->cap = 0;
}

การดำเนินการเพิ่มสมาชิก

vec_push เพิ่มสมาชิกหนึ่งรายการต่อท้าย หากเวกเตอร์เต็ม จะเพิ่มความจุเป็นสองเท่าก่อน

ฟังก์ชันนี้คืนค่า 0 เมื่อสำเร็จ และคืนค่า -1 หากการจัดสรรหน่วยความจำล้มเหลว เพื่อให้ผู้เรียกจัดการต่อได้

int vec_push(Vec *v, int value) {
    if (v->len == v->cap) {
        size_t nc = v->cap ? v->cap * 2 : 4;
        int *tmp = realloc(v->data, nc * sizeof(*v->data));
        if (!tmp) return -1;
        v->data = tmp;
        v->cap = nc;
    }
    v->data[v->len++] = value;
    return 0;
}

การอ่านสมาชิกกลับมา

เนื่องจาก len ใช้ติดตามจำนวนสมาชิกที่ใช้งานอยู่ คุณจึงวนซ้ำตั้งแต่ 0 ถึง len - 1 ได้ ความจุอาจมากกว่านี้ แต่ช่องเหล่านั้นยังไม่ถือเป็นส่วนหนึ่งของข้อมูล

for (size_t i = 0; i < v->len; i++)
    printf("%d\n", v->data[i]);

การคืนหน่วยความจำของเวกเตอร์

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

void vec_free(Vec *v) {
    free(v->data);
    v->data = NULL;
    v->len = v->cap = 0;
}

นำทุกอย่างมาประกอบกัน

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

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

typedef struct { int *data; size_t len, cap; } Vec;

int vec_push(Vec *v, int value) {
    if (v->len == v->cap) {
        size_t nc = v->cap ? v->cap * 2 : 4;
        int *tmp = realloc(v->data, nc * sizeof(*v->data));
        if (!tmp) return -1;
        v->data = tmp; v->cap = nc;
    }
    v->data[v->len++] = value;
    return 0;
}

int main(void) {
    Vec v = {0};
    for (int i = 0; i < 5; i++) vec_push(&v, i * 10);
    for (size_t i = 0; i < v.len; i++) printf("%d\n", v.data[i]);
    free(v.data);
    return 0;
}

การกำหนดค่าเป็นศูนย์ด้วย {0}

การเขียน Vec v = {0}; จะกำหนดค่าศูนย์ให้ทุกฟิลด์ รวมถึงกำหนดพอยน์เตอร์ข้อมูลเป็น NULL

นี่เป็นทางลัดที่สะดวก ทำให้เวกเตอร์พร้อมใช้กับ vec_push โดยไม่ต้องเรียกฟังก์ชันเริ่มต้นอย่างชัดเจน

Vec v = {0};      /* data=NULL, len=0, cap=0 */
vec_push(&v, 42);

ฟังก์ชันช่วย get ที่ปลอดภัย

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

int vec_get(const Vec *v, size_t i, int *out) {
    if (i >= v->len) return -1;   /* out of range */
    *out = v->data[i];
    return 0;
}

เหตุผลที่ต้องแยกติดตาม len และ cap

cap คือปริมาณหน่วยความจำที่จัดสรรไว้ ส่วน len คือปริมาณที่ใช้งานจริง

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

ทำให้ชนิดข้อมูลใช้ได้ทั่วไป

เวกเตอร์นี้เก็บข้อมูลชนิด int หากต้องการเก็บชนิดอื่น คุณสามารถเปลี่ยนชนิดของสมาชิก หรือเก็บ void * พร้อมขนาดสมาชิกได้

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

typedef struct {
    double *data;
    size_t  len, cap;
} DVec;   /* same shape, different element type */

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

ทดสอบความเข้าใจเกี่ยวกับชนิดเวกเตอร์ของคุณ

ทบทวน

เวกเตอร์รวมพอยน์เตอร์ข้อมูล len และ cap ไว้ใน struct เดียว

vec_push จะเพิ่มความจุเป็นสองเท่าเมื่อเต็ม ส่วน vec_free จะคืนบัฟเฟอร์และรีเซ็ตฟิลด์ และ {0} ใช้เริ่มต้นค่าอย่างเรียบร้อย รูปแบบที่นำกลับมาใช้ซ้ำได้นี้ดีกว่าการจัดการตัวแปรที่กระจัดกระจาย บทถัดไปคือการคืนหน่วยความจำอย่างถูกต้องและหลีกเลี่ยงการรั่วไหล

เริ่มต้นได้ฟรี

เรียนรู้ C ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
39
บทเรียน
144

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

บทเรียน “ชนิดเวกเตอร์ที่นำกลับมาใช้ได้” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “ชนิดเวกเตอร์ที่นำกลับมาใช้ได้”

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

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

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

บทเรียน “ชนิดเวกเตอร์ที่นำกลับมาใช้ได้” ใช้เวลานานแค่ไหน

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

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

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

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

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