Menu
CoddyTech

Truyền con trỏ cấu trúc

Thuộc phần Logic và luồng điều khiển trong hành trình C của Coddy. Bài học 47 trên 63.

Truyền struct theo giá trị phù hợp khi đọc dữ liệu, nhưng sẽ kém hiệu quả với struct lớn vì toàn bộ cấu trúc bị sao chép. Quan trọng hơn, bạn không thể sửa đổi struct ban đầu bên trong hàm. Đây là lúc việc truyền con trỏ đến struct trở nên cần thiết.

Khi truyền con trỏ đến một struct thay vì chính struct đó, hàm sẽ nhận địa chỉ bộ nhớ của struct gốc. Cách này có hai ưu điểm chính: hiệu quả hơn (không cần sao chép) và cho phép hàm sửa đổi dữ liệu gốc.

Cú pháp của hàm nhận con trỏ đến một struct là:

void functionName(struct StructureName *ptr) {
    // Thân hàm (function) sử dụng ptr->member
}

Bên trong hàm (function), bạn dùng toán tử mũi tên để truy cập và sửa đổi các thành viên của struct. Mọi thay đổi thông qua con trỏ đều tác động trực tiếp đến struct ban đầu trong hàm gọi, nên cách này rất phù hợp với những hàm cần cập nhật hoặc chuyển đổi dữ liệu của struct.

Kỹ thuật này rất quan trọng khi viết các chương trình C hiệu quả làm việc với cấu trúc dữ liệu phức tạp, vì nó kết hợp sức mạnh của con trỏ với cách tổ chức của các struct.

challenge icon

Thử thách

Dễ

Tạo một chương trình C minh họa cách truyền con trỏ đến struct cho hàm để sửa đổi dữ liệu hiệu quả. Chương trình của bạn cần:

  1. Định nghĩa một struct có tên BankAccount với các thành viên sau:
    • Một số nguyên accountNumber để lưu số tài khoản
    • Một mảng ký tự ownerName có kích thước 30 để lưu tên chủ tài khoản
    • Một số thực balance để lưu số dư tài khoản
    • Một số nguyên transactionCount để lưu số lượng giao dịch
  2. Viết một hàm có tên depositMoney để:
    • Nhận một con trỏ đến struct BankAccount và một số thực làm tham số
    • Cộng số tiền đó vào số dư tài khoản bằng toán tử mũi tên
    • Tăng số lượng giao dịch thêm 1
    • In ra Deposit successful. New balance: [balance]
  3. Viết một hàm có tên withdrawMoney để:
    • Nhận một con trỏ đến struct BankAccount và một số thực làm tham số
    • Kiểm tra xem số tiền rút có lớn hơn số dư hiện tại hay không
    • Nếu không đủ tiền, in ra Insufficient funds. Current balance: [balance]
    • Nếu đủ tiền, trừ số tiền khỏi số dư, tăng số lượng giao dịch và in ra Withdrawal successful. New balance: [balance]
  4. Viết một hàm có tên displayAccount để:
    • Nhận một con trỏ đến struct BankAccount làm tham số
    • In thông tin tài khoản theo đúng định dạng sau:
      • Account Information:
      • Account Number: [accountNumber]
      • Owner: [ownerName]
      • Balance: [balance]
      • Transactions: [transactionCount]
  5. Trong hàm main:
    • Tạo một biến BankAccount có tên account
    • Đọc số tài khoản, tên chủ tài khoản và số dư ban đầu từ đầu vào
    • Đặt số lượng giao dịch thành 0
    • Gọi displayAccount để hiển thị trạng thái tài khoản ban đầu
    • Đọc số tiền gửi và gọi depositMoney
    • Đọc số tiền rút và gọi withdrawMoney
    • Gọi displayAccount để hiển thị trạng thái tài khoản cuối cùng

Thử thách này minh họa sức mạnh của việc truyền con trỏ đến struct cho hàm. Khác với cách truyền theo giá trị, các hàm nhận địa chỉ bộ nhớ của struct gốc, nhờ đó có thể sửa đổi trực tiếp dữ liệu ban đầu. Cách này hiệu quả hơn vì không cần sao chép, đồng thời cho phép các hàm thay đổi vĩnh viễn giá trị của struct trong hàm gọi.

Tự làm thử

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

// TODO: Định nghĩa struct BankAccount tại đây

// TODO: Viết hàm (function) depositMoney tại đây

// TODO: Viết hàm withdrawMoney tại đây

// TODO: Viết hàm displayAccount tại đây

int main() {
    // Đọc đầu vào
    int accountNum;
    char ownerName[30];
    float initialBalance;
    float depositAmount;
    float withdrawAmount;
    
    scanf("%d", &accountNum);
    scanf("%s", ownerName);
    scanf("%f", &initialBalance);
    scanf("%f", &depositAmount);
    scanf("%f", &withdrawAmount);
    
    // TODO: Tạo biến (variable) BankAccount và khởi tạo biến đó
    
    // TODO: Gọi displayAccount để hiển thị trạng thái ban đầu
    
    // TODO: Gọi depositMoney với số tiền gửi
    
    // TODO: Gọi withdrawMoney với số tiền rút
    
    // TODO: Gọi displayAccount để hiển thị trạng thái cuối cùng
    
    return 0;
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Logic và luồng điều khiển

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