Menu
CoddyTech

Trình tạo chuỗi động

Thuộc phần Lập trình hướng đối tượng trong hành trình C của Coddy. Bài học 59 trên 61.

challenge icon

Thử thách

Dễ

Hãy tạo một StringBuilder: vùng chứa chuỗi động tự động tăng kích thước khi bạn nối thêm văn bản. Đây là tiện ích thực tế kết hợp quản lý bộ nhớ động với các mẫu OOP mà bạn đã thành thạo trong suốt khóa học này.

Bạn sẽ sắp xếp code trong ba tệp:

  • stringbuilder.h: Khai báo cấu trúc StringBuilder với ba thành viên: vùng đệm char*, một size_t lưu độ dài hiện tại và một size_t lưu dung lượng tổng. Khai báo nguyên mẫu hàm để tạo StringBuilder, nối thêm văn bản vào đó, lấy chuỗi cuối cùng và giải phóng bộ nhớ. Các chỉ thị bảo vệ tệp tiêu đề là rất cần thiết.
  • stringbuilder.c: Triển khai hệ thống StringBuilder của bạn:
    • create_stringbuilder: cấp phát một StringBuilder trên heap, khởi tạo vùng đệm với dung lượng ban đầu là 16 byte, đặt độ dài thành 0 và bảo đảm vùng đệm bắt đầu bằng chuỗi rỗng (kết thúc bằng ký tự null)
    • append: nhận một con trỏ StringBuilder và một chuỗi cần nối thêm. Tính độ dài mới cần thiết. Nếu độ dài này vượt quá dung lượng, hãy tăng gấp đôi dung lượng (lặp lại nếu cần) và dùng realloc để mở rộng vùng đệm. Sau đó nối văn bản mới bằng strcat
    • get_string: trả về con trỏ đến vùng đệm bên trong (chỉ đọc)
    • free_stringbuilder: giải phóng vùng đệm trước, sau đó giải phóng chính cấu trúc StringBuilder
  • main.c: Đọc một số nguyên cho biết cần nối thêm bao nhiêu chuỗi. Sau đó đọc từng chuỗi bằng fgets và nối chuỗi đó vào StringBuilder. Sau khi thêm tất cả chuỗi, in toàn bộ chuỗi đã ghép bằng get_string. Cuối cùng, giải phóng StringBuilder.

Hai hàm quan trọng được dùng trong thử thách này:

  • realloc(ptr, new_size): thay đổi kích thước một khối bộ nhớ đã cấp phát trước đó. Hàm nhận con trỏ đến khối hiện có và kích thước mới mong muốn tính bằng byte, rồi trả về con trỏ đến khối đã đổi kích thước (có thể đã được chuyển vị trí). Dùng hàm này trong append khi cần mở rộng vùng đệm:
    sb->buffer = (char*)realloc(sb->buffer, sb->capacity);
  • fgets(buffer, size, stream): đọc một dòng văn bản từ luồng đầu vào vào mảng ký tự, dừng khi gặp ký tự xuống dòng hoặc khi đã đọc size - 1 ký tự. Hàm giữ lại ký tự xuống dòng trong vùng đệm, vì vậy bạn cần tự xóa ký tự này. Dùng hàm trong main.c để đọc từng chuỗi đầu vào:
    fgets(line, sizeof(line), stdin);
    Để xóa ký tự xuống dòng ở cuối: kiểm tra xem ký tự cuối cùng có phải là '\n' không, rồi thay nó bằng '\0'.

Chương trình của bạn sẽ nhận:

  1. Số lượng chuỗi cần nối thêm
  2. Mỗi chuỗi nằm trên một dòng riêng

Ví dụ đầu ra khi đầu vào là 3, rồi đến Hello, , World:

Hello World

Ví dụ đầu ra khi đầu vào là 4, rồi đến C, is, a, great language!:

C is a great language!

Ví dụ đầu ra khi đầu vào là 1, rồi đến SingleString:

SingleString

Nhớ cập nhật trường length sau mỗi lần nối thêm. Khi kiểm tra xem có cần cấp phát lại hay không, hãy tính cả ký tự kết thúc null: vùng đệm cần có chỗ cho length + new_text_length + 1 byte. Dùng strlen từ <string.h> để đo độ dài chuỗi. Ngoài ra, hãy gọi getchar() sau scanf trong main.c để đọc và loại bỏ ký tự xuống dòng còn lại trước khi đọc chuỗi bằng fgets.

Tự làm thử

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

int main() {
    int n;
    scanf("%d", &n);
    getchar(); // Đọc bỏ ký tự xuống dòng sau số
    
    // TODO: Tạo StringBuilder bằng create_stringbuilder()
    
    // TODO: Đọc n chuỗi và nối từng chuỗi vào StringBuilder
    // Gợi ý: Dùng fgets hoặc cách tương tự để đọc từng dòng
    // Nếu dùng fgets, nhớ xử lý ký tự xuống dòng
    
    // TODO: In ra chuỗi hoàn chỉnh đã ghép bằng get_string()
    
    // TODO: Giải phóng StringBuilder bằng free_stringbuilder()
    
    return 0;
}

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch C online