Truyền Con Trỏ vào Hàm trong C

Xin chào các bạn nhà lập trình nhân dân! Hôm nay, chúng ta sẽ bắt đầu hành trình hấp dẫn vào thế giới lập trình C, cụ thể là tập trung vào việc truyền con trỏ vào hàm. Đừng lo nếu bạn mới bắt đầu; tôi sẽ hướng dẫn bạn qua từng bước với tinh thần như một giáo viên kinh nghiệm đã giúp đỡ hàng ngàn học sinh hiểu các khái niệm này. Hãy bắt đầu nào!

C - Passing Pointers to Functions

Lợi Ích của Việc Truyền Con Trỏ vào Hàm

Trước khi chúng ta đặt tay vào mã nguồn, hãy hiểu tại sao việc truyền con trỏ vào hàm lại quan trọng đến vậy trong lập trình C. Hãy tưởng tượng bạn đang chia sẻ một công thức nấu ăn với một người bạn. Thay vì đưa họ một bản sao của toàn bộ cuốn sách nấu ăn, bạn chỉ cần nói cho họ biết số trang. Đó chính là điều mà chúng ta đang làm với con trỏ!

Dưới đây là những lợi ích chính:

  1. Hiệu Quả Bộ Nhớ: Truyền con trỏ giống như đưa hướng thay vì toàn bộ bản đồ. Nó sử dụng ít bộ nhớ hơn vì chúng ta chỉ truyền địa chỉ, không phải toàn bộ dữ liệu.

  2. Tốc Độ: Nó nhanh hơn việc truyền một địa chỉ nhỏ hơn việc truyền một khối lớn dữ liệu.

  3. Khả Năng Chỉnh Sửa Dữ Liệu Gốc: Khi bạn truyền một con trỏ, hàm có thể truy cập và chỉnh sửa trực tiếp dữ liệu gốc.

  4. Làm Việc với Cấu Trúc Dữ Liệu Lớn: Đối với các cấu trúc dữ liệu lớn như mảng hoặc cấu trúc, việc truyền con trỏ rất hiệu quả.

Ví Dụ về Việc Truyền Con Trỏ vào Hàm

Hãy bắt đầu với một ví dụ đơn giản để thấy cách điều này hoạt động trong thực tế:

#include <stdio.h>

void modifyValue(int *ptr) {
*ptr = 100;
}

int main() {
int num = 10;
printf("Trước: %d\n", num);

modifyValue(&num);
printf("Sau: %d\n", num);

return 0;
}

Trong ví dụ này, chúng ta đang truyền địa chỉ của num vào hàm modifyValue. Hàm sau đó thay đổi giá trị tại địa chỉ đó thành 100. Khi chúng ta chạy chương trình này, chúng ta sẽ thấy:

Trước: 10
Sau: 100

Phải không? Chúng ta vừa chỉnh sửa một biến trong hàm main từ trong một hàm khác!

Hoán Đổi Giá Trị bằng Cách Truyền Con Trỏ

Bây giờ, hãy giải quyết một vấn đề lập trình cổ điển: hoán đổi hai giá trị. Đây là nơi con trỏ thực sự sáng!

#include <stdio.h>

void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}

int main() {
int x = 5, y = 10;
printf("Trước khi hoán đổi: x = %d, y = %d\n", x, y);

swap(&x, &y);
printf("Sau khi hoán đổi: x = %d, y = %d\n", x, y);

return 0;
}

Trong đây, hàm swap của chúng ta nhận con trỏ đến hai số nguyên. Nó sau đó sử dụng các con trỏ này để hoán đổi các giá trị. Kết quả sẽ là:

Trước khi hoán đổi: x = 5, y = 10
Sau khi hoán đổi: x = 10, y = 5

Đó giống như phép màu, nhưng đó chỉ là sức mạnh của con trỏ!

Truyền Con Trỏ Mảng vào Hàm

Mảng và con trỏ trong C gần gũi. Khi chúng ta truyền một mảng vào hàm, chúng ta thực sự đang truyền một con trỏ đến phần tử đầu tiên của nó. Hãy xem điều này trong hành động:

#include <stdio.h>

void printArray(int *arr, int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}

int main() {
int numbers[] = {1, 2, 3, 4, 5};
int size = sizeof(numbers) / sizeof(numbers[0]);

printf("Các phần tử của mảng là: ");
printArray(numbers, size);

return 0;
}

Trong ví dụ này, numbers được chuyển đổi tự động thành con trỏ khi truyền vào printArray. Kết quả sẽ là:

Các phần tử của mảng là: 1 2 3 4 5

Truyền Con Trỏ Chuỗi vào Hàm

Trong C, chuỗi là chỉ một mảng ký tự, vì vậy việc truyền con trỏ chuỗi hoạt động tương tự như việc truyền con trỏ mảng. Dưới đây là một ví dụ:

#include <stdio.h>

void printString(char *str) {
while (*str != '\0') {
printf("%c", *str);
str++;
}
printf("\n");
}

int main() {
char greeting[] = "Hello, World!";
printf("Lời chào là: ");
printString(greeting);

return 0;
}

Kết quả sẽ là:

Lời chào là: Hello, World!

Truyền Con Trỏ Cấu Trúc vào Hàm

Cuối cùng, hãy xem cách chúng ta có thể truyền con trỏ vào cấu trúc. Điều này rất hữu ích khi làm việc với các cấu trúc dữ liệu lớn:

#include <stdio.h>

struct Person {
char name[50];
int age;
};

void birthday(struct Person *p) {
p->age++;
}

int main() {
struct Person john = {"John Doe", 25};

printf("Trước sinh nhật: %s là %d tuổi\n", john.name, john.age);

birthday(&john);

printf("Sau sinh nhật: %s là %d tuổi\n", john.name, john.age);

return 0;
}

Trong ví dụ này, chúng ta đang truyền một con trỏ đến cấu trúc Person vào hàm birthday. Hàm sau đó tăng tuổi của người đó. Kết quả sẽ là:

Trước sinh nhật: John Doe là 25 tuổi
Sau sinh nhật: John Doe là 26 tuổi

Và thế là đã xong! Chúng ta đã bao gồm các khái niệm cơ bản về việc truyền con trỏ vào hàm trong C. Hãy nhớ, luyện tập sẽ làm bạn hoàn hảo, vì vậy đừng sợ thử nghiệm với các khái niệm này. Hạnh phúc lập trình!

Phương Pháp Mô Tả Ví Dụ
Truyền Con Trỏ Cơ Bản Truyền địa chỉ của biến để chỉnh sửa chúng trực tiếp void modifyValue(int *ptr)
Hoán Đổi Giá Trị Sử dụng con trỏ để hoán đổi giá trị giữa hai biến void swap(int *a, int *b)
Truyền Con Trỏ Mảng Truyền mảng vào hàm một cách hiệu quả void printArray(int *arr, int size)
Truyền Con Trỏ Chuỗi Làm việc với chuỗi trong hàm void printString(char *str)
Truyền Con Trỏ Cấu Trúc Chỉnh sửa cấu trúc dữ liệu phức tạp một cách hiệu quả void birthday(struct Person *p)

Credits: Image by storyset