Tìm hiểu Mảng và Chuỗi trong Lập trình C

Khảo sát Cấu trúc Mảng

Phần này tập trung vào việc khám phá cách các mảng, cả một chiều và hai chiều, được lưu trữ trong bộ nhớ và cách truy cập các phần tử của chúng trong ngôn ngữ C.

Mảng một chiều

Trong C, các phần tử của mảng một chiều được lưu trữ liên tục trong bộ nhớ. Ví dụ sau minh họa cách mảng số nguyên (int) và mảng ký tự (char) được tổ chức.

#include <stdio.h>

#define KICH_THUOC 4

// Hàm kiểm tra mảng số nguyên một chiều
void kiemTraMangSoNguyen() {
    int mangSoNguyen[KICH_THUOC] = {10, 20, 30, 40};          
    int chiSo;

    printf("Kich thuoc mang so nguyen (bytes): %zu\n", sizeof(mangSoNguyen));

    printf("Dia chi va gia tri cua tung phan tu:\n");
    for (chiSo = 0; chiSo < KICH_THUOC; ++chiSo)
        printf("Dia chi %p: %d\n", &mangSoNguyen[chiSo], mangSoNguyen[chiSo]);

    printf("Gia tri cua ten mang (dia chi phan tu dau tien): %p\n", (void*)mangSoNguyen); 
}

// Hàm kiểm tra mảng ký tự một chiều
void kiemTraMangKyTu() {        
    char mangKyTu[KICH_THUOC] = {'A', 'B', 'C', 'D'}; 
    int chiSo;

    printf("Kich thuoc mang ky tu (bytes): %zu\n", sizeof(mangKyTu));

    printf("Dia chi va gia tri cua tung phan tu:\n"); 
    for (chiSo = 0; chiSo < KICH_THUOC; ++chiSo)
        printf("Dia chi %p: %c\n", &mangKyTu[chiSo], mangKyTu[chiSo]);
    
    printf("Gia tri cua ten mang (dia chi phan tu dau tien): %p\n", (void*)mangKyTu); 
}

int main() {
    printf("--- Kiem tra mang so nguyen mot chieu ---\n");
    kiemTraMangSoNguyen();

    printf("\n--- Kiem tra mang ky tu mot chieu ---\n");
    kiemTraMangKyTu();

    return 0;
}

Quan sát đầu ra, ta thấy các phần tử trong mảng số nguyên được lưu trữ liên tục, mỗi phần tử chiếm 4 byte (trên hệ thống 32-bit/64-bit phổ biến). Tương tự, các phần tử trong mảng ký tự cũng liên tục, mỗi phần tử chiếm 1 byte. Tên mảng (ví dụ: mangSoNguyen) tự bản thân nó là một con trỏ trỏ đến địa chỉ của phần tử đầu tiên (&mangSoNguyen[0]).

Mảng hai chiều

Mảng hai chiều trong C được lưu trữ theo cơ chế "hàng lớn" (row-major order), nghĩa là tất cả các phần tử của hàng đầu tiên được lưu trữ trước, sau đó đến hàng thứ hai, và cứ thế. Điều này tạo ra một khối bộ nhớ liên tục cho toàn bộ mảng.

#include <stdio.h>

#define SO_HANG 2
#define SO_COT 4

// Hàm kiểm tra mảng số nguyên hai chiều
void kiemTraMangSoNguyenHaiChieu() {
    int maTranSo[SO_HANG][SO_COT] = {{11, 12, 13, 14}, {21, 22, 23, 24}};
    int hang, cot;

    printf("Kich thuoc ma tran so nguyen (bytes): %zu\n", sizeof(maTranSo));

    printf("Dia chi va gia tri cua tung phan tu:\n");
    for (hang = 0; hang < SO_HANG; ++hang)
        for (cot = 0; cot < SO_COT; ++cot)
            printf("Dia chi %p: %d\n", &maTranSo[hang][cot], maTranSo[hang][cot]);
    printf("\n");

    printf("Gia tri cua ten ma tran (dia chi cua hang dau tien): %p\n", (void*)maTranSo);
    printf("Gia tri cua maTranSo[0] (dia chi cua phan tu dau tien hang 0): %p\n", (void*)maTranSo[0]);
    printf("Gia tri cua maTranSo[1] (dia chi cua phan tu dau tien hang 1): %p\n", (void*)maTranSo[1]);
    printf("\n");
}

// Hàm kiểm tra mảng ký tự hai chiều
void kiemTraMangKyTuHaiChieu() {
    char maTranKyTu[SO_HANG][SO_COT] = {{'A', 'B', 'C', 'D'}, {'E', 'F', 'G', 'H'}};
    int hang, cot;

    printf("Kich thuoc ma tran ky tu (bytes): %zu\n", sizeof(maTranKyTu));

    printf("Dia chi va gia tri cua tung phan tu:\n");
    for (hang = 0; hang < SO_HANG; ++hang)
        for (cot = 0; cot < SO_COT; ++cot)
            printf("Dia chi %p: %c\n", &maTranKyTu[hang][cot], maTranKyTu[hang][cot]);
    printf("\n");

    printf("Gia tri cua ten maTranKyTu: %p\n", (void*)maTranKyTu);
    printf("Gia tri cua maTranKyTu[0]: %p\n", (void*)maTranKyTu[0]);
    printf("Gia tri cua maTranKyTu[1]: %p\n", (void*)maTranKyTu[1]);
}

int main() {
    printf("--- Kiem tra ma tran so nguyen hai chieu ---\n");
    kiemTraMangSoNguyenHaiChieu();

    printf("\n--- Kiem tra ma tran ky tu hai chieu ---\n");
    kiemTraMangKyTuHaiChieu();

    return 0;
}

Với mảng hai chiều, địa chỉ của tên mảng (ví dụ: maTranSo), địa chỉ của hàng đầu tiên (maTranSo[0]), và địa chỉ của phần tử đầu tiên của hàng đầu tiên (&maTranSo[0][0]) có cùng giá trị số học. Tuy nhiên, chúng có các kiểu dữ liệu khác nhau (con trỏ đến mảng, con trỏ đến phần tử). Sự khác biệt về địa chỉ giữa các hàng liên tiếp (ví dụ: maTranSo[0]maTranSo[1]) chính là kích thước của một hàng (số phần tử trên một hàng nhân với kích thước của một phần tử).

Thao tác Chuỗi trong C

Các chuỗi trong C được biểu diễn bằng mảng ký tự kết thúc bằng ký tự null ('\0'). Phần này sẽ trình bày cách hoán đổi hai chuỗi và các thao tác phân tích chuỗi.

Hoán đổi chuỗi

Để hoán đổi nội dung của hai chuỗi, chúng ta không thể sử dụng phép gán trực tiếp (ví dụ: str1 = str2;) vì điều này sẽ chỉ thay đổi con trỏ mà không sao chép dữ liệu. Thay vào đó, chúng ta phải sao chép nội dung của chuỗi bằng các hàm như strcpy.

#include <stdio.h>
#include <string.h> // Cần cho strcpy

#define MAX_CHIEU_DAI_CHUOI 80

// Hàm hoán đổi nội dung của hai chuỗi
void thucHienHoanDoiChuoi(char chuoiA[], char chuoiB[]) {
    char chuoiTam[MAX_CHIEU_DAI_CHUOI];

    // Sao chép chuỗiA vào chuoiTam
    strcpy(chuoiTam, chuoiA);
    // Sao chép chuỗiB vào chuoiA
    strcpy(chuoiA, chuoiB);
    // Sao chép chuoiTam (nội dung gốc của chuỗiA) vào chuoiB
    strcpy(chuoiB, chuoiTam);
}

// Kiểm tra hoán đổi chuỗi với hai mảng ký tự riêng biệt
void kiemTraHoanDoiBangHaiMang() {
    char chuoiThuNhat[MAX_CHIEU_DAI_CHUOI] = "Lap trinh C la thu vi.";
    char chuoiThuHai[MAX_CHIEU_DAI_CHUOI] = "Lap trinh C la mot thu thach.";

    printf("Truoc khi hoan doi:\n");
    puts(chuoiThuNhat);
    puts(chuoiThuHai);

    thucHienHoanDoiChuoi(chuoiThuNhat, chuoiThuHai);

    printf("Sau khi hoan doi:\n");
    puts(chuoiThuNhat);
    puts(chuoiThuHai);
}

// Kiểm tra hoán đổi chuỗi trong mảng hai chiều (mảng các chuỗi)
void kiemTraHoanDoiTrongMangHaiChieu() {
    char tapHopChuoi[2][MAX_CHIEU_DAI_CHUOI] = {"Hoc C that tuyet!", 
                                              "Cung co luc nan long :("};

    printf("Truoc khi hoan doi:\n");
    puts(tapHopChuoi[0]);
    puts(tapHopChuoi[1]);

    // Gọi hàm hoán đổi, truyền địa chỉ của từng chuỗi con
    thucHienHoanDoiChuoi(tapHopChuoi[0], tapHopChuoi[1]);

    printf("Sau khi hoan doi:\n");
    puts(tapHopChuoi[0]);
    puts(tapHopChuoi[1]);
}

int main() {
    printf("--- Hoan doi hai chuoi bang hai mang mot chieu ---\n");
    kiemTraHoanDoiBangHaiMang();

    printf("\n--- Hoan doi hai chuoi bang mang ky tu hai chieu ---\n");
    kiemTraHoanDoiTrongMangHaiChieu();

    return 0;
}

Khi làm việc với các chuỗi trong mảng hai chiều (hay còn gọi là mảng các chuỗi), mỗi hàng views[X] thực chất là một mảng ký tự một chiều đại diện cho một chuỗi. Do đó, chúng ta có thể truyền views[0]views[1] trực tiếp vào hàm hoán đổi chuỗi.

Đếm số từ trong chuỗi

Thuật toán đếm số từ thường dựa trên việc quét chuỗi và xác định ranh giới giữa các từ (thường là khoảng trắng).

#include <stdio.h>
#include <string.h> // Để sử dụng strlen

#define KICH_THUOC_DONG 81 // +1 cho ky tu null

// Hàm đếm số từ trong một chuỗi
int demSoTu(char dongVanBan[]) {
    int chiSo = 0;
    int dangTrongTu = 0; // 0: không trong từ, 1: đang trong từ
    int soLuongTu = 0;

    while (dongVanBan[chiSo] != '\0') {
        if (dongVanBan[chiSo] == ' ' || dongVanBan[chiSo] == '\t' || dongVanBan[chiSo] == '\n') {
            dangTrongTu = 0; // Gặp khoảng trắng, không còn trong từ nữa
        } else if (dangTrongTu == 0) {
            dangTrongTu = 1; // Bắt đầu một từ mới
            soLuongTu++;
        }
        chiSo++;
    }
    return soLuongTu;
}

int main() {
    char dongNguon[KICH_THUOC_DONG];

    printf("Nhap van ban (nhan EOF de thoat):\n");
    while (fgets(dongNguon, KICH_THUOC_DONG, stdin) != NULL) {
        // Xóa ký tự xuống dòng nếu có
        dongNguon[strcspn(dongNguon, "\n")] = '\0'; 
        printf("So tu: %d\n\n", demSoTu(dongNguon));
        printf("Nhap van ban (nhan EOF de thoat):\n");
    }

    return 0;
}

Trong ví dụ này, chúng ta sử dụng một cờ dangTrongTu để theo dõi xem chúng ta đang ở trong một từ hay giữa các từ. Mỗi khi chuyển từ trạng thái "không trong từ" sang "trong từ", chúng ta tăng bộ đếm từ lên.

Tìm từ dài nhất trong chuỗi

Để tìm từ dài nhất, chúng ta cần duyệt qua chuỗi, xác định từng từ, đếm độ dài của nó và so sánh với độ dài từ dài nhất đã tìm được.

#include <stdio.h>
#include <string.h> // Cần cho strlen

#define KICH_THUOC_TOI_DA 1000

int main() {
    char dongVao[KICH_THUOC_TOI_DA];
    int doDaiHienTai;   // Độ dài của từ đang xét
    int doDaiLonNhat;    // Độ dài của từ dài nhất
    int viTriBatDauTuDaiNhat; // Vị trí bắt đầu của từ dài nhất

    printf("Nhap van ban (nhan EOF de thoat):\n");
    while (fgets(dongVao, KICH_THUOC_TOI_DA, stdin) != NULL) {
        dongVao[strcspn(dongVao, "\n")] = '\0'; // Xóa ký tự xuống dòng
        
        doDaiHienTai = 0;
        doDaiLonNhat = 0;
        viTriBatDauTuDaiNhat = 0;

        int chiSo = 0;
        int batDauTu = 0; // Ghi nhớ vị trí bắt đầu của từ hiện tại

        while (1) {
            // Bỏ qua các khoảng trắng đầu tiên
            while (dongVao[chiSo] == ' ' || dongVao[chiSo] == '\t') {
                chiSo++;
            }

            batDauTu = chiSo; // Đánh dấu vị trí bắt đầu của từ mới
            doDaiHienTai = 0;

            // Đếm độ dài từ hiện tại
            while (dongVao[chiSo] != '\0' && dongVao[chiSo] != ' ' && dongVao[chiSo] != '\t') {
                doDaiHienTai++;
                chiSo++;
            }
        
            // Cập nhật từ dài nhất nếu tìm thấy từ dài hơn
            if (doDaiHienTai > doDaiLonNhat) {
                doDaiLonNhat = doDaiHienTai;
                viTriBatDauTuDaiNhat = batDauTu;
            }

            // Thoát nếu đã đến cuối chuỗi
            if (dongVao[chiSo] == '\0')
                break;
        }

        printf("Tu dai nhat: ");
        if (doDaiLonNhat > 0) {
            for (int k = 0; k < doDaiLonNhat; ++k)
                printf("%c", dongVao[viTriBatDauTuDaiNhat + k]);
        } else {
            printf("(khong co tu nao)");
        }
        printf("\n\n");
    }

    return 0;
}

Chương trình này quét qua chuỗi, sử dụng hai vòng lặp lồng nhau để xác định và đo độ dài từng từ. Biến viTriBatDauTuDaiNhat được dùng để lưu trữ vị trí bắt đầu của từ dài nhất, giúp chúng ta in ra từ đó sau khi quét xong.

Chuyển đổi số thập phân sang hệ cơ số N

Việc chuyển đổi số thập phân sang một hệ cơ số khác (nhị phân, bát phân, thập lục phân) được thực hiện bằng cách chia liên tiếp số đó cho cơ số và ghi lại các số dư theo thứ tự ngược lại.

#include <stdio.h>
#include <string.h> // Cần cho strlen

#define MAX_CHIEU_DAI_KET_QUA 100

// Hàm chuyển đổi số thập phân x sang hệ cơ số n
void chuyenDoiCoSo(int soThapPhan, int coSoDich) {
    char bangChuyenDoi[] = "0123456789ABCDEF"; // Bảng ký tự cho các cơ số
    char ketQuaDaoNguoc[MAX_CHIEU_DAI_KET_QUA]; // Lưu kết quả theo thứ tự đảo ngược
    int chiSo = 0;
    int phanNguyen;
    int soDu;

    if (soThapPhan == 0) {
        printf("0\n");
        return;
    }

    // Thực hiện thuật toán chia lấy dư
    while (soThapPhan > 0) {
        soDu = soThapPhan % coSoDich;
        ketQuaDaoNguoc[chiSo++] = bangChuyenDoi[soDu];
        soThapPhan = soThapPhan / coSoDich;
    }

    // In kết quả theo thứ tự đúng (ngược lại của chuỗi đã lưu)
    for (int i = chiSo - 1; i >= 0; i--) {
        printf("%c", ketQuaDaoNguoc[i]);
    }
    printf("\n");
}

int main() {
    int giaTriThapPhan;

    printf("Nhap mot so nguyen thap phan (nhan Ctrl+D/Z de thoat):\n");
    while (scanf("%d", &giaTriThapPhan) != EOF) {
        printf("Thap phan %d:\n", giaTriThapPhan);
        printf("  Nhi phan: ");
        chuyenDoiCoSo(giaTriThapPhan, 2);
        printf("  Bat phan: ");
        chuyenDoiCoSo(giaTriThapPhan, 8);
        printf("  Thap luc phan: ");
        chuyenDoiCoSo(giaTriThapPhan, 16);

        printf("\nNhap mot so nguyen thap phan:\n");
    }

    return 0;
}

Xử lý Mảng và Sắp xếp

Phần này trình bày các thao tác cơ bản với mảng số nguyên như nhập, xuất, tính trung bình và sắp xếp.

Quản lý điểm số

Chúng ta sẽ xây dựng các hàm để nhập điểm, hiển thị điểm, tính điểm trung bình và sắp xếp điểm theo thứ tự giảm dần sử dụng thuật toán sắp xếp nổi bọt (Bubble Sort).

#include <stdio.h>

#define SO_MON_HOC 5

// Khai báo nguyên mẫu hàm
void nhapDiemSo(int diem[], int soLuong);
void hienThiDiemSo(int diem[], int soLuong);
double tinhDiemTrungBinh(int diem[], int soLuong);
void sapXepNoiBot(int diem[], int soLuong); // Sắp xếp giảm dần

int main() {
    int mangDiem[SO_MON_HOC];
    double diemTrungBinh;
    
    printf("Nhap %d diem cho cac mon hoc:\n", SO_MON_HOC);
    nhapDiemSo(mangDiem, SO_MON_HOC);
    
    printf("\nCac diem so da nhap: \n");
    hienThiDiemSo(mangDiem, SO_MON_HOC);
    
    printf("\nThuc hien tinh toan va sap xep...\n");
    diemTrungBinh = tinhDiemTrungBinh(mangDiem, SO_MON_HOC);
    sapXepNoiBot(mangDiem, SO_MON_HOC); // Sắp xếp tại chỗ

    printf("\nCac diem so (cao -> thap):\n");
    hienThiDiemSo(mangDiem, SO_MON_HOC);
    
    printf("Diem trung binh cac mon: %.2f\n", diemTrungBinh);
    
    return 0;
}

// Định nghĩa hàm
// Nhập n số nguyên vào mảng x
void nhapDiemSo(int diem[], int soLuong) {
    for (int i = 0; i < soLuong; ++i) {
        printf("Nhap diem mon %d: ", i + 1);
        scanf("%d", &diem[i]); 
    }
}

// Xuất n phần tử của mảng x
void hienThiDiemSo(int diem[], int soLuong) {
    for (int i = 0; i < soLuong; ++i)
        printf("%d ", diem[i]);
    printf("\n");
}

// Tính điểm trung bình của các phần tử trong mảng x
double tinhDiemTrungBinh(int diem[], int soLuong) {
    double tongDiem = 0.0;
    for (int i = 0; i < soLuong; ++i)
        tongDiem += diem[i];
    return tongDiem / soLuong;
}

// Sắp xếp mảng x theo thứ tự giảm dần bằng thuật toán nổi bọt
void sapXepNoiBot(int diem[], int soLuong) {
    int i, j, temp;
    for (i = 0; i < soLuong - 1; i++) { // Duyệt qua từng lượt
        for (j = 0; j < soLuong - 1 - i; j++) { // So sánh các cặp kề nhau
            if (diem[j] < diem[j+1]) { // Nếu phần tử hiện tại nhỏ hơn phần tử kế tiếp
                temp = diem[j];
                diem[j] = diem[j+1];
                diem[j+1] = temp;
            }
        }
    }
}

Sắp xếp mảng chuỗi

Sắp xếp mảng chuỗi tương tự như sắp xếp mảng số nguyên, nhưng cần sử dụng các hàm xử lý chuỗi như strcmp để so sánh và strcpy để sao chép chuỗi.

#include <stdio.h>
#include <string.h> // Cần cho strcmp và strcpy

#define SO_LUONG_TEN 5
#define CHIEU_DAI_TEN_TOI_DA 20

// Khai báo nguyên mẫu hàm
void hienThiDanhSach(char danhSach[][CHIEU_DAI_TEN_TOI_DA], int soLuong);
void sapXepTenTheoThuTuABC(char danhSach[][CHIEU_DAI_TEN_TOI_DA], int soLuong);

int main() {
    char danhSachNguoi[][CHIEU_DAI_TEN_TOI_DA] = {"An", "Binh", "Cuong", "Dat", "Em"}; // Ví dụ tên tiếng Việt
    
    printf("Danh sach ten ban dau:\n");
    hienThiDanhSach(danhSachNguoi, SO_LUONG_TEN);

    printf("\nDang sap xep...\n");
    sapXepTenTheoThuTuABC(danhSachNguoi, SO_LUONG_TEN); // Gọi hàm sắp xếp

    printf("\nDanh sach ten sau khi sap xep theo thu tu bang chu cai:\n");
    hienThiDanhSach(danhSachNguoi, SO_LUONG_TEN);

    return 0;
}

// Định nghĩa hàm
// Xuất các chuỗi trong mảng str
void hienThiDanhSach(char danhSach[][CHIEU_DAI_TEN_TOI_DA], int soLuong) {
    for (int i = 0; i < soLuong; ++i)
        printf("%s\n", danhSach[i]);
}

// Sắp xếp mảng chuỗi str theo thứ tự từ điển bằng thuật toán nổi bọt
void sapXepTenTheoThuTuABC(char danhSach[][CHIEU_DAI_TEN_TOI_DA], int soLuong) {
    int i, j;
    char chuoiTam[CHIEU_DAI_TEN_TOI_DA]; // Mảng tạm để lưu chuỗi khi hoán đổi

    for (i = 0; i < soLuong - 1; i++) {
        for (j = 0; j < soLuong - 1 - i; j++) {
            // So sánh hai chuỗi kề nhau. strcmp trả về > 0 nếu chuỗi đầu lớn hơn (theo thứ tự từ điển)
            if (strcmp(danhSach[j], danhSach[j+1]) > 0) {
                // Hoán đổi chuỗi bằng cách sao chép nội dung
                strcpy(chuoiTam, danhSach[j]);
                strcpy(danhSach[j], danhSach[j+1]);
                strcpy(danhSach[j+1], chuoiTam);
            }
        }
    }
}

Kiểm tra tính duy nhất của chữ số

Bài toán này yêu cầu kiểm tra xem một chuỗi số có chứa các chữ số lặp lại hay không. Chúng ta có thể sử dụng một mảng tần suất để theo dõi số lần xuất hiện của mỗi chữ số.

#include <stdio.h>
#include <string.h> // Cần cho strlen

#define MAX_CHUOI_SO 105

// Hàm kiểm tra xem một chuỗi số có chứa chữ số lặp lại không
// Trả về 1 nếu có, 0 nếu không
int coSoLapLai(char chuoiSo[]) {
    int demChuSo[10] = {0}; // Mảng tần suất cho các chữ số từ 0 đến 9
    int chiSo;

    for (chiSo = 0; chuoiSo[chiSo] != '\0'; ++chiSo) {
        int chuSoHienTai = chuoiSo[chiSo] - '0'; // Chuyển ký tự số thành giá trị số nguyên
        demChuSo[chuSoHienTai]++; // Tăng bộ đếm cho chữ số đó
        
        // Nếu số lần xuất hiện của chữ số này lớn hơn 1, nghĩa là nó bị lặp lại
        if (demChuSo[chuSoHienTai] > 1)
            return 1; // Có chữ số lặp lại
    }
    return 0; // Không có chữ số nào lặp lại
}

int main() {
    char soNguyenDangChuoi[MAX_CHUOI_SO];

    printf("Nhap mot chuoi so nguyen (nhan Ctrl+D/Z de thoat):\n");
    while (scanf("%s", soNguyenDangChuoi) != EOF) {
        if (coSoLapLai(soNguyenDangChuoi))
            printf("CO\n"); // Có chữ số lặp lại
        else
            printf("KHONG\n"); // Không có chữ số lặp lại
    }
    return 0;
}

Thao tác Ma trận: Xoay hàng

Phần này minh họa cách xoay các phần tử trong mỗi hàng của một ma trận vuông sang phải một vị trí.

#include <stdio.h>

#define KICH_THUOC_MA_TRAN 4 // Ma trận 4x4
#define MAX_HANG_COT 100    // Kích thước tối đa cho mảng để hàm có thể tổng quát hơn

// Hàm hiển thị ma trận
void hienThiMaTran(int maTran[][MAX_HANG_COT], int kichThuoc) {
    int hang, cot;

    for (hang = 0; hang < kichThuoc; ++hang) {
        for (cot = 0; cot < kichThuoc; ++cot)
            printf("%4d", maTran[hang][cot]);
        printf("\n");
    }
}

// Hàm xoay mỗi hàng của ma trận sang phải một vị trí
void xoayMaTranSangPhai(int maTran[][MAX_HANG_COT], int kichThuoc) {
    int hang, cot;
    for (hang = 0; hang < kichThuoc; ++hang) { // Duyệt qua từng hàng
        int giaTriCuoiHang = maTran[hang][kichThuoc - 1]; // Lưu phần tử cuối cùng của hàng hiện tại

        // Dịch chuyển tất cả các phần tử trong hàng hiện tại sang phải một vị trí
        for (cot = kichThuoc - 1; cot > 0; --cot) {
            maTran[hang][cot] = maTran[hang][cot - 1];
        }

        maTran[hang][0] = giaTriCuoiHang; // Đặt phần tử đã lưu vào vị trí đầu tiên của hàng
    }
}

int main() {
    int maTranBanDau[KICH_THUOC_MA_TRAN][MAX_HANG_COT] = {{1, 2, 3, 4},
                                                        {5, 6, 7, 8},
                                                        {9, 10, 11, 12},
                                                        {13, 14, 15, 16}};
                                                        
    printf("Ma tran goc:\n");
    hienThiMaTran(maTranBanDau, KICH_THUOC_MA_TRAN);
    
    xoayMaTranSangPhai(maTranBanDau, KICH_THUOC_MA_TRAN); 
    
    printf("\nMa tran sau khi xoay:\n");
    hienThiMaTran(maTranBanDau, KICH_THUOC_MA_TRAN);

    return 0;
}

Thẻ: C arrays strings memory management Data Structures

Đăng vào ngày 20 tháng 7 lúc 19:21