Structures, File Handling, và Quản lý Bộ nhớ trong C

Cấu trúc và Dữ liệu Tổ chức

Định nghĩa Cấu trúc (struct)

Trong ngôn ngữ C, từ khóa struct được dùng để nhóm các biến thuộc các kiểu dữ liệu khác nhau thành một đơn vị duy nhất. Mỗi biến bên trong cấu trúc được gọi là thành viên.

Ví dụ:

struct SinhVien {
    char hoTen[60];
    int namSinh;
    double diemTrungBinh;
};

Khai báo Biến Cấu trúc

Sau khi định nghĩa, ta có thể khai báo biến theo kiểu cấu trúc đó. Việc truy cập các thành viên sử dụng toán tử chấm (.).

struct SinhVien sv1;
strcpy(sv1.hoTen, "Nguyen Van A");
sv1.namSinh = 2000;
sv1.diemTrungBinh = 3.7;

Mảng Cấu trúc

Ta có thể tạo mảng các đối tượng cấu trúc để lưu trữ nhiều bản ghi cùng loại.

struct SinhVien danhSach[50]; // Mảng 50 sinh viên
danhSach[0] = sv1;

Sử dụng Con trỏ với Cấu trúc

Con trỏ tới cấu trúc giúp truy cập hiệu quả hơn, đặc biệt khi làm việc với hàm hoặc cấp phát động. Toán tử mũi tên (->) dùng để truy cập thành viên qua con trỏ.

struct SinhVien *ptr = &sv1;
printf("Tuoi: %d\n", ptr->namSinh);

Cấp phát Bộ nhớ Động cho Cấu trúc

Hàm malloc cho phép xin cấp vùng nhớ động cho một cấu trúc. Sau khi sử dụng, cần giải phóng bằng free để tránh rò rỉ bộ nhớ.

struct SinhVien *svMoi = (struct SinhVien*) malloc(sizeof(struct SinhVien));
if (svMoi != NULL) {
    svMoi->diemTrungBinh = 3.9;
}
// ...
free(svMoi);

Cấu trúc Lồng nhau

Một cấu trúc có thể chứa thành viên là một cấu trúc khác, hỗ trợ mô hình hóa dữ liệu phức tạp.

struct DiaChi {
    char tenDuong[80];
    int maBuucuc;
};

struct SinhVien {
    char hoTen[60];
    struct DiaChi noiO;
};

Cấu trúc trong Danh sách Liên kết

Các nút trong danh sách liên kết thường được xây dựng bằng cấu trúc có chứa con trỏ trỏ đến nút kế tiếp.

struct Nut {
    int giaTri;
    struct Nut *tiepTheo;
};

Xử lý Tập tin trong C

Mở và Đóng Tập tin

Thao tác với tập tin bắt đầu bằng fopen và kết thúc bằng fclose. Nếu mở thất bại, con trỏ trả về là NULL.

FILE *f = fopen("du_lieu.txt", "w");
if (f == NULL) {
    printf("Khong the mo tap tin!\n");
    return;
}
fprintf(f, "Xin chao!\n");
fclose(f);

Các Chế độ Mở Tập tin

  • "r": Chỉ đọc
  • "w": Ghi (ghi đè toàn bộ nội dung cũ)
  • "a": Ghi tiếp vào cuối tập tin
  • "rb", "wb": Mở ở chế độ nhị phân
  • "r+": Đọc và ghi

Đọc/ghi Ký tự và Chuỗi

Dùng fgetcfputc để xử lý từng ký tự. Hàm fgets đọc một dòng, còn fputs ghi chuỗi không bao gồm ký tự null.

char buffer[100];
fgets(buffer, 100, f);        // Đọc một dòng
fputs("Noi dung moi", f);     // Ghi chuỗi

Đọc/ghi Khối Dữ liệu

Hàm freadfwrite rất hữu ích khi làm việc với mảng hoặc cấu trúc dưới dạng nhị phân.

int mang[50] = {0};
fwrite(mang, sizeof(int), 50, f);  // Ghi toàn bộ mảng
fread(mang, sizeof(int), 50, f);   // Đọc lại

Di chuyển Con trỏ Tập tin

Các hàm như rewind, ftell, và fseek cho phép điều khiển vị trí hiện tại trong tập tin.

long viTriHienTai = ftell(f);
fseek(f, 0, SEEK_SET);  // Quay về đầu tập tin
rewind(f);              // Cách khác để quay về đầu

Phát hiện Lỗi Tập tin

Trong quá trình thao tác, lỗi có thể xảy ra. Dùng ferror để kiểm tra và clearerr để đặt lại cờ lỗi.

if (ferror(f)) {
    printf("Loi khi thao tac tap tin.\n");
    clearerr(f);
}

Tập tin Nhị phân

Khi làm việc với dữ liệu không phải văn bản (như ảnh, âm thanh, hay cấu trúc đã được serial hóa), nên dùng chế độ nhị phân để đảm bảo tính toàn vẹn dữ liệu.

FILE *binFile = fopen("data.bin", "wb");
fwrite(&sv1, sizeof(struct SinhVien), 1, binFile);
fclose(binFile);

Tập tin Tạm thời

Hàm tmpfile tạo một tập tin tạm, tự động bị xóa khi chương trình đóng hoặc gọi fclose.

FILE *temp = tmpfile();
if (temp) {
    fwrite(mang, sizeof(int), 50, temp);
    rewind(temp);
    fread(mang, sizeof(int), 50, temp);
    fclose(temp); // Tự động xóa
}

Thẻ: struct file-handling dynamic-memory linked-list binary-files

Đăng vào ngày 19 tháng 5 lúc 13:39