Chèn chuỗi trong C++ | Laptrinhcanban.com

Chèn chuỗi trong C++

Hướng dẫn cách chèn chuỗi trong C++. Bạn sẽ học được cách chèn một chuỗi vào giữa một chuỗi khác trong C++ sau bài học này.

Chúng ta có 2 phương pháp để chèn chuỗi trong C++ như sau:

  • Đảm bảo độ dài chuỗi ban đầu đủ dài để chèn chuỗi khác vào
  • Cấp phát bộ nhớ động khi chèn chuỗi trong C++

Lại nữa, nếu bạn chỉ muốn chèn chuỗi vào cuối chuỗi khác trong C++ thì sẽ có những cách đơn giản hơn nhiều.

Chèn chuỗi vào chuỗi trong C++

Giả sử bạn có một chuỗi và bạn muốn chèn một chuỗi khác vào giữa chuỗi này. Ví dụ như chèn "xyz" vào giữa chuỗi "abcdef" ở vị trí thứ 2 chẳng hạn.

Trong các ngôn ngữ lập trình khác, ví dụ như Python chẳng hạn, chúng ta có thể sử dụng trực tiếp một hàm có sẵn là hàm insert() và giải quyết việc chèn chuỗi vào chuỗi trong C++ vô cùng đơn giản.

Thật không may, không có hàm insert chuỗi trong C++ hay là bất kỳ hàm có sẵn nào trong thư viện chuẩn giúp chúng ta chèn chuỗi trong C++ cả. Do đó chúng ta sẽ phải tự tạo hàm để giải quyết vấn đề này.

Tất nhiên, việc chèn một chuỗi sẽ làm tăng tổng số ký tự của chuỗi ban đầu. Do đó, nếu bạn muốn chèn một chuỗi khác vào chuỗi ban đầu, hãy đảm bảo là bộ nhớ cấp phát cho chuỗi ban đầu đủ khả năng để chứa hết chuỗi cần chèn. Nếu không thì sự cố tràn bộ nhớ sẽ bị xảy ra.

Ví dụ:

/* Chuỗi ban đầu chỉ có tối đa 7 ký tự và không thể chèn thêm */
char str1[] = "abcde";


/* Chuỗi ban đầu có tối đa 10 ký tự và có thể chèn thêm chuỗi "xyz" */
char str2[10] = "abcde";

Để đảm bảo đủ bộ nhớ khi chèn chuỗi trong C++ mà chúng ta sẽ có 2 phương pháp như dưới đây.

Cách 1: đảm bảo độ dài chuỗi ban đầu đủ dài để chèn chuỗi khác vào

Nếu bạn có thể dự đoán trước độ dài của chuỗi ký tự sau khi chèn, bạn có thể chuẩn bị một mảng có kích thước dự đoán trước và thực hiện công việc chèn trong mảng đó.

Các bước tiến hành chèn chuỗi vào chuỗi lúc này như sau:

  1. Bắt đầu từ vị trí cần chèn trong chuỗi ban đầu, chúng ta dịch chuyển dần về phía sau lượng ký tự bằng đúng với số ký tự của chuỗi cần chèn và tạo ra các ô trống.

  2. Sao chép chuỗi ký tự cần chèn để chèn vào các ô trống vừa tạo.

Để tiện sử dụng thì chúng ta sẽ tạo ra một hàm để thực hiện các xử lý này, và chương trình chèn chuỗi ký tự trong C++ thực tế sẽ như sau.

#include <iostream>
#include <cassert>
#include <cstring>
using namespace std;

#define SIZE_OF_ARRAY(array) (sizeof(array)/sizeof(array[0]))

/*
Chèn chuỗi trong C++

Tham số
str1: Chuỗi ban đầu (không chấp nhận Null)
str1_size: Độ dài chuỗi str1
pos: Vị trí chèn (tính từ đầu chuỗi str1)
str2: Chuỗi chèn vào (không chấp nhận Null pointer)
Giá trị trả về
str1
*/
char* str_insert(char* str1, size_t str1_size, size_t pos, const char* str2)
{
assert(str1 != NULL);
assert(str2 != NULL);

size_t len1 = strlen(str1);
size_t len2 = strlen(str2);

// Kiểm tra str1 có đủ độ dài để chèn str2 không
assert(len1 + len2 < str1_size);

// Kiểm tra vị trí chèn có nằm trong chuỗi str1 không
assert(len1 >= pos);


// Làm trống một phạm vi dài với len2 ký tự, từ str1[pos])
// Dịch chuyển chuỗi ban đầu về sau, bao gồm cả ký tự `\0'
memmove(&str1[pos + len2], &str1[pos], len1 - pos + 1);

// Copy str2 và dán vào khoảng trống mới tạo
memcpy(&str1[pos], str2, len2);

return str1;
}

int main()
{
char str[10] = "abcde";
cout <<"before: "<< str <<endl;

cout<< "after: "<<str_insert(str, SIZE_OF_ARRAY(str), 2, "xyz");

return 0;
}

Kết quả, chuỗi "xyz" được chèn vào chuỗi "abcde" tại vị trí thứ 2 như sau:

before: abcde
after: abxyzcde

Trong hàm str_insert() mới tạo ở trên có 4 tham số, trong đó tham số str1_size được sử dụng để kiểm tra độ dài chuỗi ban đầu có đủ để chứa cả chuỗi chèn vào hay không.

Để thực hiện bước 1 - chuỗi ký tự ra phía sau bằng độ dài của chuỗi ký tự cần chèn, chúng ta sử dụng tới hàm memmove(). Lưu ý là cả ký tự kết thúc chuỗi \0 cũng sẽ được dịch chuyển, nên chúng ta cần cộng thêm 1 trong đối số thứ ba của hàm memove().

Và để thực hiện bước 2 - Sao chép chuỗi ký tự cần chèn để chèn vào các ô trống vừa tạo, chúng ta sử dụng tới hàm memcpy(). Lưu ý ở đây chúng ta không thể dụng hàm strcpy() để copy chuỗi, vì cả ký tự \0 sẽ bị copy, dẫn đến chuỗi kết quả sẽ trở thành 「abxyz\0cde\0」 mất.

Cách 2: cấp phát bộ nhớ động khi chèn chuỗi trong C++

Nếu chúng ta không thể thay đổi chuỗi ban đầu trong chương trình, hoặc là không biết chính xác độ dài chuỗi kết quả sau khi chèn, thì chúng ta buộc phải cấp phát bộ nhớ động để lưu kết quả chèn chuỗi.

Để tiện sử dụng thì chúng ta sẽ tạo ra một hàm để thực hiện các xử lý này, và chương trình chèn chuỗi ký tự trong C++ thực tế sẽ như sau.

#include <iostream>
#include <cassert>
#include <cstdlib>
#include <cstring>
using namespace std;

#define SIZE_OF_ARRAY(array) (sizeof(array)/sizeof(array[0]))

/*
Chèn chuỗi trong C++

Tham số
str1: Chuỗi ban đầu (không chấp nhận Null)
pos: Vị trí chèn (tính từ đầu chuỗi str1)
str2: Chuỗi chèn vào (không chấp nhận Null pointer)
Giá trị trả về
Con trỏ mảng chứa kết quả. Nếu thực thi thất bại thì trả về Null
*/
char* str_alloc_and_insert(const char* str1, size_t pos, const char* str2)
{
assert(str1 != NULL);
assert(str2 != NULL);

size_t len1 = strlen(str1);
size_t len2 = strlen(str2);

// Kiểm tra vị trí chèn có nằm trong chuỗi str1 không
assert(len1 >= pos);


size_t result_size = len1 + len2 + 1;

char* result = (char*) malloc(sizeof(char) *result_size);
if (result == NULL) {
return NULL;
}

// Copy phạm vi từ đầu chuỗi ban đầu tới trước vị trí cần chèn vào chuỗi kết quả
memcpy(result, str1, pos);

// Copy chuỗi cần chèn vào cuối kết quả
memcpy(&result[pos], str2, len2);

// Copy phạm vi từ vị trí cần chèn tới cuối chuỗi ban đầu vào chuỗi kết quả
// Thêm ký tự kết thúc chuỗi `\0` vào kết quả
strcpy(&result[pos + len2], &str1[pos]);

return result;
}

int main()
{
char str[] = "abcde";
cout <<"before: "<< str <<endl;

char* result = str_alloc_and_insert(str, 2, "xyz");
if (result != NULL) {
cout <<"after: "<< result;
free(result);
}

return 0;
}

Kết quả:

before: abcde
after: abxyzcde

Khác với hàm str_insert() tạo ở phương pháp 1 thì hàm str_alloc_and_insert() mới tạo ở trên sẽ chỉ sử dụng nội dung của chuỗi ban đầu mà không làm thay đổi nó. Bởi vậy , chúng ta sử dụng tới const char* str1 để biểu thị ý nghĩa này.

Và do chúng ta đã cấp phát bộ nhớ động trong hàm, nên sẽ không phải lo lắng chuỗi kết quả có đủ bộ nhớ để chèn hay không, và sự cố tràn bộ nhớ tất nhiên sẽ không xảy ra.

Lại nữa, kết quả trả về của hàm này không phải là chuỗi kết quả, mà là một con trỏ trỏ đến vùng được cấp phát động để lưu giữ kết quả chèn chuỗi trong hàm. Chú ý là hàm free() cần được gọi bên ngoài hàm str_alloc_and_insert() để có thể giải phóng bộ nhớ đã cấp phát sau khi kết thúc hàm.

Cuối cùng, thì trong hàm trên chúng ta đã sử dụng hàm malloc() để cấp phát bộ nhớ động, và tiến hành copy 3 lần chuỗi bằng hàm memcpy(), là phần đầu chuỗi ban đầu, chuỗi cần chèn, và phần cuối chuỗi ban đầu. Ký hiệu kết thúc chuỗi \0 cũng cần được thêm vào để hoàn thành chuỗi.

Tổng kết

Trên đây Kiyoshi đã hướng dẫn bạn cách chèn chuỗi trong C++ rồi. Để nắm rõ nội dung bài học hơn, bạn hãy thực hành viết lại các ví dụ của ngày hôm nay nhé.

Và hãy cùng tìm hiểu những kiến thức sâu hơn về C++ trong các bài học tiếp theo

HOME>> >>

Profile
きよしです!笑

Tác giả : Kiyoshi (Chis Thanh)

Kiyoshi là một cựu du học sinh tại Nhật Bản. Sau khi tốt nghiệp đại học Toyama năm 2017, Kiyoshi hiện đang làm BrSE tại Tokyo, Nhật Bản.