Hướng Dẫn Toàn Diện Về Xử Lý Ký Tự Và Chuỗi Trong C

Bản Chất Của Ký Tự Và Chuỗi

Trong ngôn ngữ C, ký tự đơn đại diện cho một đơn vị văn bản duy nhất, bao gồm chữ cái, chữ số, dấu câu hoặc ký tự đặc biệt. Ký tự luôn được bao bọc bởi dấu nháy đơn (' '), ví dụ: 'Z', '7', '@'.

Ngược lại, chuỗi là một dãy các ký tự liên tiếp trong bộ nhớ, được kết thúc bằng ký tự null \0. Chuỗi sử dụng dấu nháy kép (" "). Kích thước thực tế của một mảng chuỗi luôn bằng số ký tự hữu ích cộng thêm 1 byte dành cho ký tự kết thúc. Ví dụ, khai báo char text[] = "hello world"; sẽ tạo ra một mảng gồm 11 ký tự nhìn thấy, 1 ký tự khoảng trắng và 1 byte \0, tổng cộng 13 byte.

Thao Tác Với Ký Tự Đơn

Khai Báo Và Xuất Dữ Liệu

Biến kiểu char chiếm 1 byte và có thể hoạt động tương tự như số nguyên. Tùy thuộc vào hệ thống, nó có thể là dạng có dấu (-128 đến 127) hoặc không dấu (0 đến 255). Khi in ra màn hình, định dạng %c sẽ hiển thị ký tự tương ứng, trong khi %d trả về mã ASCII của ký tự đó.

#include <stdio.h>

int main() {
    char ky_tu_mau = 'A';
    printf("Dang ky tu: %c\n", ky_tu_mau);
    printf("Dang so ASCII: %d\n", ky_tu_mau);
    return 0;
}

Nhập Dữ Liệu Ký Tự

Việc đọc ký tự từ bàn phím có thể thực hiện qua scanf hoặc getchar. Lưu ý rằng scanf với %c sẽ đọc mọi ký tự, kể cả khoảng trắng hoặc ký tự xuống dòng còn sót lại trong bộ đệm.

#include <stdio.h>

int main() {
    char input;
    printf("Nhap mot ky tu: ");
    scanf(" %c", &input); // Them khoang trang truoc %c de bo qua ky tu trang
    printf("Da nhan: %c\n", input);
    return 0;
}

Xử Lý Chuỗi Ký Tự

Các Phương Thức Nhập An Toàn

Sử dụng scanf với %s tiềm ẩn rủi ro tràn bộ đệm và không đọc được khoảng trắng. Hàm gets() đã bị loại bỏ hoàn toàn khỏi chuẩn C11 do không thể kiểm soát độ dài đầu vào. Phương án tối ưu là dùng fgets().

#include <stdio.h>
#include <string.h>

int main() {
    char bo_dem[50];
    printf("Nhap doan van ban: ");
    fgets(bo_dem, sizeof(bo_dem), stdin);
    
    // Loai bo ky tu xuong duong neu co
    size_t vi_tri = strcspn(bo_dem, "\n");
    bo_dem[vi_tri] = '\0';
    
    printf("Chuoi da xu ly: %s\n", bo_dem);
    return 0;
}

Quản Lý Tập Hợp Nhiều Chuỗi

Mảng Hai Chiều

Mỗi chuỗi được lưu trong một hàng cố định của ma trận ký tự. Phương pháp này cho phép sửa đổi trực tiếp nội dung từng chuỗi nhưng tốn bộ nhớ nếu độ dài thực tế ngắn hơn kích thước khai báo.

#include <stdio.h>

int main() {
    char ds_ten[][12] = {"Nguyen", "Tran", "Le"};
    int so_luong = sizeof(ds_ten) / sizeof(ds_ten[0]);
    
    for (int i = 0; i < so_luong; i++) {
        printf("Phan tu %d: %s\n", i + 1, ds_ten[i]);
    }
    return 0;
}

Mảng Con Trỏ Hằng

Cách này lưu trữ địa chỉ của các chuỗi hằng trong một mảng con trỏ. Cú pháp gọn nhẹ và tiết kiệm bộ nhớ, nhưng nội dung chuỗi nằm trong vùng chỉ đọc, không thể thay đổi trực tiếp.

#include <stdio.h>

int main() {
    const char *mang_doi_tuong[] = {"Shift", "Control", "Alt"};
    int tong_so = sizeof(mang_doi_tuong) / sizeof(mang_doi_tuong[0]);
    
    for (int idx = 0; idx < tong_so; idx++) {
        printf("Phim: %s\n", mang_doi_tuong[idx]);
    }
    return 0;
}

Cấp Phát Động Bộ Nhớ

Phù hợp khi số lượng hoặc độ dài chuỗi chưa xác định tại thời điểm biên dịch. Yêu cầu quản lý bộ nhớ thủ công để tránh rò rỉ tài nguyên.

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

int main() {
    char **ds_dong = (char **)malloc(3 * sizeof(char *));
    if (!ds_dong) return 1;
    
    const char *tam[] = {"Alpha", "Beta", "Gamma"};
    for (int i = 0; i < 3; i++) {
        size_t len = strlen(tam[i]) + 1;
        ds_dong[i] = (char *)malloc(len * sizeof(char));
        if (ds_dong[i]) {
            memcpy(ds_dong[i], tam[i], len);
        }
    }
    
    for (int i = 0; i < 3; i++) {
        printf("%s\n", ds_dong[i]);
        free(ds_dong[i]);
    }
    free(ds_dong);
    return 0;
}
Phương phápKhả năng sửa đổiQuản lý bộ nhớTrường hợp áp dụng
Mảng con trỏKhôngTự độngDữ liệu tĩnh, chỉ đọc
Mảng 2 chiềuCóCố địnhCần chỉnh sửa nội dung chuỗi
Cấp phát độngCóThủ côngDữ liệu biến đổi theo runtime

Các Hàm Thao Tác Chuỗi Cơ Bản

Toàn bộ hàm dưới đây đều nằm trong thư viện <string.h>.

strcpy và strcat

strcpy sao chép toàn bộ nội dung nguồn sang đích. strcat nối chuỗi phụ vào đuôi chuỗi chính.

#include <stdio.h>
#include <string.h>

int main() {
    char dich[50] = "Xin chao";
    char nguon[] = ", moi nguoi!";
    
    strcpy(dich, "Noi dung moi"); // Ghi de
    strcat(dich, nguon);          // Noi them
    printf("%s\n", dich);
    return 0;
}

strlen và strcmp

strlen đếm số ký tự thực tế (bỏ qua \0). strcmp so sánh theo giá trị ASCII, trả về 0 nếu trùng khớp, giá trị âm nếu chuỗi thứ nhất nhỏ hơn, và dương nếu lớn hơn.

#include <stdio.h>
#include <string.h>

int main() {
    char s1[] = "apple";
    char s2[] = "banana";
    int so_sanh = strcmp(s1, s2);
    printf("Do dai s1: %zu\n", strlen(s1));
    if (so_sanh < 0) printf("s1 dung truoc s2 trong tu dien.\n");
    return 0;
}

strchr và strstr

strchr tìm vị trí xuất hiện đầu tiên của một ký tự đơn. strstr tìm vị trí xuất hiện đầu tiên của một chuỗi con. Cả hai đều trả về con trỏ trỏ đến vị trí tìm thấy hoặc NULL nếu không có kết quả.

#include <stdio.h>
#include <string.h>

int main() {
    char van_ban[] = "Lap trinh C rat manh me";
    char ky_tim = 't';
    char chuoi_con[] = "manh";
    
    char *ket_qua_ky = strchr(van_ban, ky_tim);
    if (ket_qua_ky) printf("Tim thay '%c' tai: %s\n", ky_tim, ket_qua_ky);
    
    char *ket_qua_chuoi = strstr(van_ban, chuoi_con);
    if (ket_qua_chuoi) printf("Tim thay chuoi con: %s\n", ket_qua_chuoi);
    return 0;
}

Thẻ: ngôn-ngữ-c xâu-ký-tự con-trỏ thư-viện-string cấp-phát-bộ-nhớ

Đăng vào ngày 26 tháng 9 lúc 04:54