Con trỏ là tính năng mạnh mẽ của lập trình C

95% Lập Trình Viên giỏi Đọc Hiểu English! Bạn Thì Sao?

Trong hướng dẫn này, bạn sẽ tìm hiểu về con trỏ; con trỏ là gì, bạn sử dụng chúng như thế nào và những lỗi phổ biến bạn có thể gặp phải khi làm việc với chúng với sự trợ giúp của các ví dụ.

Con trỏ là tính năng mạnh mẽ của lập trình C và C++. Trước khi tìm hiểu về con trỏ, chúng ta hãy tìm hiểu về địa chỉ trong lập trình C.

Địa chỉ ở C

Nếu bạn có một biến var trong chương trình của mình, &varnó sẽ cung cấp cho bạn địa chỉ của nó trong bộ nhớ.

Chúng tôi đã sử dụng địa chỉ nhiều lần trong khi sử dụng scanf()hàm.

scanf("%d", &var);

Tại đây, giá trị do người dùng nhập vào được lưu trữ trong địa chỉ của biến var . Hãy lấy một ví dụ làm việc.

#include <stdio.h>
int main()
{
  int var = 5;
  printf("var: %d\n", var);

  // Notice the use of & before var
  printf("address of var: %p", &var);  
  return 0;
}

Đầu ra

var: 5 
address of var: 2686778

Lưu ý: Bạn có thể sẽ nhận được một địa chỉ khác khi chạy đoạn mã trên.

Con trỏ C

Con trỏ (biến con trỏ) là các biến đặc biệt được sử dụng để lưu trữ địa chỉ hơn là giá trị.

Cú pháp con trỏ

Đây là cách chúng ta có thể khai báo con trỏ.

int* p;

Ở đây, chúng tôi đã công bố một con trỏ p của intloại.

Bạn cũng có thể khai báo con trỏ theo những cách này.

int *p1;
int * p2;

Hãy lấy một ví dụ khác về khai báo con trỏ.

int* p1, p2;

Ở đây, chúng ta đã khai báo một con trỏ p1 và một biến bình thường p2 .

Gán địa chỉ cho Con trỏ

Hãy lấy một ví dụ.

int* pc, c;
c = 5;
pc = &c;

Ở đây, 5 được gán cho biến c . Và, địa chỉ của c được gán cho con trỏ pc .

Nhận giá trị của điều do con trỏ chỉ ra

Để nhận giá trị của thứ được trỏ bởi các con trỏ, chúng ta sử dụng *toán tử. Ví dụ:

int* pc, c;
c = 5;
pc = &c;
printf("%d", *pc);   // Output: 5

Ở đây, địa chỉ của cđược gán cho con trỏ máy tính . Để lấy giá trị được lưu trữ trong địa chỉ đó, chúng tôi đã sử dụng * pc .

Lưu ý: Trong ví dụ trên, pc là một con trỏ, không phải *pc. Bạn không thể và không nên làm điều gì đó như *pc = &c;

Nhân tiện, *được gọi là toán tử tham chiếu (khi làm việc với con trỏ). Nó hoạt động trên một con trỏ và cung cấp giá trị được lưu trữ trong con trỏ đó.

Thay đổi giá trị được trỏ bởi con trỏ

Hãy lấy một ví dụ.

int* pc, c;
c = 5;
pc = &c;
c = 1;
printf("%d", c);    // Output: 1
printf("%d", *pc);  // Ouptut: 1

Chúng tôi đã gán địa chỉ của c cho con trỏ pc .

Sau đó, chúng tôi thay đổi giá trị của c thành 1. Vì pc và địa chỉ của c giống nhau, *pccho chúng tôi 1.

Hãy lấy một ví dụ khác.

int* pc, c;
c = 5;
pc = &c;
*pc = 1;
printf("%d", *pc);  // Ouptut: 1
printf("%d", c);    // Output: 1

Chúng tôi đã gán địa chỉ của c cho con trỏ pc .

Sau đó, chúng tôi thay đổi *pcthành 1 bằng cách sử dụng *pc = 1;. Vì pc và địa chỉ của c giống nhau nên c sẽ bằng 1.

Hãy lấy một ví dụ nữa.

int* pc, c, d;
c = 5;
d = -15;

pc = &c; printf("%d", *pc); // Output: 5
pc = &d; printf("%d", *pc); // Ouptut: -15

Ban đầu, địa chỉ của c được gán cho con trỏ máy tính bằng cách sử dụng pc = &c;. Vì c là 5, *pccho chúng ta 5.

Sau đó, địa chỉ của d được gán cho con trỏ pc bằng cách sử dụng pc = &d;. Vì d là -15, *pccho chúng ta -15.

Ví dụ: Làm việc của con trỏ

Hãy lấy một ví dụ làm việc.

#include <stdio.h>
int main()
{
   int* pc, c;
   
   c = 22;
   printf("Address of c: %p\n", &c);
   printf("Value of c: %d\n\n", c);  // 22
   
   pc = &c;
   printf("Address of pointer pc: %p\n", pc);
   printf("Content of pointer pc: %d\n\n", *pc); // 22
   
   c = 11;
   printf("Address of pointer pc: %p\n", pc);
   printf("Content of pointer pc: %d\n\n", *pc); // 11
   
   *pc = 2;
   printf("Address of c: %p\n", &c);
   printf("Value of c: %d\n\n", c); // 2
   return 0;
}

Đầu ra

Address of c: 2686784
Value of c: 22

Address of pointer pc: 2686784
Content of pointer pc: 22

Address of pointer pc: 2686784
Content of pointer pc: 11

Address of c: 2686784
Value of c: 2

Giải thích về chương trình

  1. int* pc, c;

    Ở đây, một pc con trỏ và một biến bình thường c , cả hai kiểu int, được tạo.
    Vì lúc đầu pc và c không được khởi tạo, nên pc con trỏ trỏ đến không có địa chỉ hoặc địa chỉ ngẫu nhiên. Và, biến c có một địa chỉ nhưng chứa giá trị rác ngẫu nhiên.
     
  2. c = 22;

    Điều này gán 22 cho biến c . Tức là, 22 được lưu trong vị trí bộ nhớ của biến c .
     
  3. pc = &c;

    Điều này sẽ gán địa chỉ của biến c cho con trỏ pc .
     
  4. c = 11;

    Điều này gán 11 cho biến c .
     
  5. *pc = 2;

    Điều này thay đổi giá trị tại vị trí bộ nhớ được trỏ bởi pc con trỏ thành 2.

Những lỗi thường gặp khi làm việc với con trỏ

Giả sử, bạn muốn con trỏ pc trỏ đến địa chỉ của c . Sau đó,

int c, *pc;

// pc is address but c is not
pc = c; // Error

// &c is address but *pc is not
*pc = &c; // Error

// both &c and pc are addresses
pc = &c;

// both c and *pc values 
*pc = c;

Đây là một ví dụ về cú pháp con trỏ người mới bắt đầu thường cảm thấy khó hiểu.

#include <stdio.h>
int main() {
   int c = 5;
   int *p = &c;

   printf("%d", *p);  // 5
   return 0; 
}

Tại sao chúng ta không gặp lỗi khi sử dụng int *p = &c;?

Là vì

int *p = &c;

tương đương với

int *p:
p = &c;

Trong cả hai trường hợp, chúng tôi đang tạo một con trỏ p(không phải *p) và gán &ccho nó.

Để tránh nhầm lẫn này, chúng ta có thể sử dụng câu lệnh như sau:

int* p = &c;

Bây giờ bạn đã biết con trỏ là gì, bạn sẽ tìm hiểu cách con trỏ liên quan đến mảng trong hướng dẫn tiếp theo.









Tìm kết quả nhanh