Pointer trong C là gì?
Các con trỏ trong C, là một biến mà các cửa hàng địa chỉ của một biến khác. Một con trỏ cũng có thể được sử dụng để tham chiếu đến một hàm con trỏ khác. Một con trỏ có thể được tăng / giảm, tức là, để trỏ đến vị trí bộ nhớ tiếp theo / trước đó. Mục đích của con trỏ là tiết kiệm không gian bộ nhớ và đạt được thời gian thực thi nhanh hơn.
Cách sử dụng con trỏ trong C
Nếu chúng ta khai báo một biến v kiểu int, v sẽ thực sự lưu trữ một giá trị.
v bằng 0 bây giờ.
Tuy nhiên, mỗi biến, ngoài giá trị, còn có địa chỉ của nó (hay nói một cách đơn giản là nó nằm ở đâu trong bộ nhớ). Địa chỉ có thể được truy xuất bằng cách đặt dấu và (&) trước tên biến.
Nếu bạn in địa chỉ của một biến trên màn hình, nó sẽ giống như một số hoàn toàn ngẫu nhiên (hơn nữa, nó có thể khác với run to run).
Hãy thử điều này trong thực tế với con trỏ trong ví dụ C
Đầu ra của chương trình này là -480613588.
Bây giờ, con trỏ là gì? Thay vì lưu trữ một giá trị, một con trỏ y sẽ lưu trữ địa chỉ của một biến.
Biến con trỏ
Int * y = & v;
BIẾN ĐỔI |
POINTER |
Một giá trị được lưu trữ trong một địa chỉ lưu trữ / bộ nhớ được đặt tên |
Một biến mà điểm đến địa chỉ lưu trữ / bộ nhớ của một biến |
Khai báo một con trỏ
Giống như các biến, con trỏ trong lập trình C phải được khai báo trước khi chúng có thể được sử dụng trong chương trình của bạn. Con trỏ có thể được đặt tên bất cứ thứ gì bạn muốn miễn là chúng tuân theo các quy tắc đặt tên của C. Một khai báo con trỏ có dạng sau.
data_type * pointer_variable_name;
Đây,
- data_type là kiểu cơ sở của con trỏ trong các kiểu biến của C và cho biết kiểu của biến mà con trỏ trỏ tới.
- Dấu hoa thị (*: cùng một dấu hoa thị được sử dụng cho phép nhân), là toán tử điều hướng, khai báo một con trỏ.
Hãy xem một số khai báo con trỏ hợp lệ trong hướng dẫn con trỏ C này:
int *ptr_thing; /* pointer to an integer */int *ptr1,thing;/* ptr1 is a pointer to type integer and thing is an integer variable */double *ptr2; /* pointer to a double */float *ptr3; /* pointer to a float */char *ch1 ; /* pointer to a character */float *ptr, variable;/*ptr is a pointer to type float and variable is an ordinary float variable */
Khởi tạo một con trỏ
Sau khi khai báo một con trỏ, chúng ta khởi tạo nó giống như các biến tiêu chuẩn với một địa chỉ biến. Nếu con trỏ trong lập trình C không được khởi tạo và sử dụng trong chương trình, kết quả là không thể đoán trước và có khả năng gây thảm họa.
Để lấy địa chỉ của một biến, chúng ta sử dụng toán tử dấu và (&), được đặt trước tên của một biến có địa chỉ mà chúng ta cần. Khởi tạo con trỏ được thực hiện theo cú pháp sau.
Cú pháp con trỏ
pointer = &variable;
Dưới đây là một chương trình đơn giản để minh họa con trỏ:
#includeint main(){int a=10; //variable declarationint *p; //pointer variable declarationp=&a; //store address of variable a in pointer pprintf("Address stored in a variable p is:%x\n",p); //accessing the addressprintf("Value stored in a variable p is:%d\n",*p); //accessing the valuereturn 0;}
Đầu ra:
Address stored in a variable p is:60ff08Value stored in a variable p is:10
Nhà điều hành | Ý nghĩa |
* | Phục vụ 2 mục đích
|
& | Chỉ phục vụ 1 mục đích
|
Các loại con trỏ trong C
Sau đây là các loại con trỏ khác nhau trong C :
Null Pointer
Chúng ta có thể tạo một con trỏ null bằng cách gán giá trị null trong quá trình khai báo con trỏ. Phương pháp này hữu ích khi bạn không có bất kỳ địa chỉ nào được gán cho con trỏ. Một con trỏ null luôn chứa giá trị 0.
Chương trình sau minh họa việc sử dụng con trỏ null:
#includeint main(){int *p = NULL; //null pointerprintf(“The value inside variable p is:\n%x”,p);return 0;}
Đầu ra:
The value inside variable p is:0
Con trỏ Void
Trong lập trình C, con trỏ void còn được gọi là con trỏ chung. Nó không có bất kỳ kiểu dữ liệu tiêu chuẩn nào. Một con trỏ void được tạo bằng cách sử dụng từ khóa void. Nó có thể được sử dụng để lưu trữ một địa chỉ của bất kỳ biến nào.
Chương trình sau minh họa việc sử dụng con trỏ void:
#includeint main(){void *p = NULL; //void pointerprintf("The size of pointer is:%d\n",sizeof(p));return 0;}
Đầu ra:
The size of pointer is:4
Con trỏ hoang dã
Một con trỏ được cho là một con trỏ hoang dã nếu nó không được khởi tạo cho bất kỳ thứ gì. Các loại con trỏ C này không hiệu quả vì chúng có thể trỏ đến một số vị trí bộ nhớ không xác định có thể gây ra sự cố trong chương trình của chúng tôi và có thể dẫn đến sự cố chương trình. Người ta phải luôn cẩn thận khi làm việc với các con trỏ hoang dã.
Chương trình sau minh họa việc sử dụng con trỏ đại diện:
#includeint main(){int *p; //wild pointerprintf("\n%d",*p);return 0;}
Đầu ra
timeout: the monitored command dumped coresh: line 1: 95298 Segmentation fault timeout 10s main
Các loại con trỏ khác trong 'c' như sau:
- Con trỏ nguy hiểm
- Con trỏ phức tạp
- Con trỏ gần
- Con trỏ xa
- Con trỏ khổng lồ
Con trỏ truy cập trực tiếp và gián tiếp
Trong C, có hai cách tương đương để truy cập và thao tác với một nội dung biến
- Truy cập trực tiếp: chúng tôi sử dụng trực tiếp tên biến
- Truy cập gián tiếp: chúng tôi sử dụng một con trỏ đến biến
Hãy hiểu điều này với sự trợ giúp của chương trình dưới đây
#include/* Declare and initialize an int variable */int var = 1;/* Declare a pointer to int */int *ptr;int main( void ){/* Initialize ptr to point to var */ptr = &var;/* Access var directly and indirectly */printf("\nDirect access, var = %d", var);printf("\nIndirect access, var = %d", *ptr);/* Display the address of var two ways */printf("\n\nThe address of var = %d", &var);printf("\nThe address of var = %d\n", ptr);/*change the content of var through the pointer*/*ptr=48;printf("\nIndirect access, var = %d", *ptr);return 0;}
Sau khi biên dịch chương trình mà không có bất kỳ lỗi nào, kết quả là:
Direct access, var = 1Indirect access, var = 1The address of var = 4202496The address of var = 4202496Indirect access, var = 48
Số học con trỏ trong C
Các hoạt động của con trỏ được tóm tắt trong hình sau

Hoạt động ưu tiên (ưu tiên)
Khi làm việc với con trỏ C, chúng ta phải tuân thủ các quy tắc ưu tiên sau:
- Các toán tử * và & có cùng mức độ ưu tiên với các toán tử một ngôi (phủ định !, tăng ++, giảm--).
- Trong cùng một biểu thức, các toán tử một ngôi *, &,!, ++, - được đánh giá từ phải sang trái.
Nếu một con trỏ P trỏ đến một biến X, thì * P có thể được sử dụng ở bất cứ nơi nào X có thể được viết.
Các biểu thức sau là tương đương:
int X = 10 int * P = & Y; Đối với đoạn mã trên, các biểu thức dưới đây là đúng | |
Biểu hiện | Biểu thức tương đương |
Y = * P + 1 * P = * P + 10 * P + = 2 ++ * P (* P) ++ | Y = X + 1 X = X + 10 X + = 2 ++ X X ++ |
Trong trường hợp thứ hai, dấu ngoặc đơn là cần thiết: vì các toán tử một ngôi * và ++ được đánh giá từ phải sang trái, không có dấu ngoặc đơn thì con trỏ P sẽ được tăng lên, không phải đối tượng mà P trỏ đến.
Bảng dưới đây cho thấy phép toán số học và cơ bản có thể được sử dụng khi xử lý con trỏ C
Hoạt động | Giải trình |
Chuyển nhượng | int * P1, * P2 P1 = P2; P1 và P2 trỏ đến cùng một biến số nguyên |
Tăng và giảm | Int * P1; P1 ++; P1--; |
Thêm một phần bù (Hằng số) | Điều này cho phép con trỏ di chuyển N phần tử trong bảng. Con trỏ sẽ được tăng hoặc giảm N lần số byte (các) kiểu của biến. P1 + 5; |
Con trỏ & Mảng C với các ví dụ
Theo truyền thống, chúng tôi truy cập các phần tử mảng bằng cách sử dụng chỉ mục của nó, nhưng phương pháp này có thể bị loại bỏ bằng cách sử dụng con trỏ. Con trỏ giúp dễ dàng truy cập từng phần tử mảng.
#includeint main(){int a[5]={1,2,3,4,5}; //array initializationint *p; //pointer declaration/*the ptr points to the first element of the array*/p=a; /*We can also type simply ptr==&a[0] */printf("Printing the array elements using pointer\n");for(int i=0;i<5;i++) //loop for traversing array elements{printf("\n%x",*p); //printing array elementsp++; //incrementing to the next element, you can also write p=p+1}return 0;}
Đầu ra
12345
Việc thêm một số cụ thể vào một con trỏ sẽ di chuyển vị trí của con trỏ đến giá trị thu được bằng một phép toán cộng. Giả sử p là một con trỏ hiện đang trỏ đến vị trí bộ nhớ 0 nếu chúng ta thực hiện thao tác cộng sau, p + 1 thì nó sẽ thực thi theo cách sau:

Vì p hiện đang trỏ đến vị trí 0 sau khi thêm 1, giá trị sẽ trở thành 1, và do đó con trỏ sẽ trỏ đến vị trí bộ nhớ 1.
Con trỏ và chuỗi C với các ví dụ
Chuỗi là một mảng các đối tượng char, kết thúc bằng ký tự rỗng '\ 0'. Chúng ta có thể thao tác các chuỗi bằng cách sử dụng con trỏ. Con trỏ trong ví dụ C giải thích phần này
#include#include int main(){char str[]="Hello Guru99!";char *p;p=str;printf("First character is:%c\n",*p);p =p+1;printf("Next character is:%c\n",*p);printf("Printing all the characters in a string\n");p=str; //reset the pointerfor(int i=0;i Đầu ra
First character is:HNext character is:ePrinting all the characters in a stringHelloGuru99!Một cách khác để xử lý chuỗi là với một mảng con trỏ như trong chương trình sau:
#includeint main(){char *materials[ ] = { "iron", "copper", "gold"};printf("Please remember these materials :\n");int i ;for (i = 0; i < 3; i++) {printf("%s\n", materials[ i ]);}return 0;} Đầu ra:
Please remember these materials:ironcoppergoldƯu điểm của Con trỏ trong C
- Con trỏ hữu ích để truy cập các vị trí bộ nhớ.
- Con trỏ cung cấp một cách hiệu quả để truy cập các phần tử của cấu trúc mảng.
- Con trỏ được sử dụng để cấp phát bộ nhớ động cũng như phân bổ giao dịch.
- Con trỏ được sử dụng để tạo cấu trúc dữ liệu phức tạp như danh sách liên kết, đồ thị, cây, v.v.
Nhược điểm của con trỏ trong C
- Con trỏ hơi phức tạp để hiểu.
- Con trỏ có thể dẫn đến nhiều lỗi khác nhau như lỗi phân đoạn hoặc có thể truy cập vào một vị trí bộ nhớ không cần thiết.
- Nếu một giá trị không chính xác được cung cấp cho một con trỏ, nó có thể gây hỏng bộ nhớ.
- Con trỏ cũng là nguyên nhân gây rò rỉ bộ nhớ.
- Con trỏ tương đối chậm hơn so với con trỏ của các biến.
- Các lập trình viên cảm thấy rất khó khăn khi làm việc với các con trỏ; do đó trách nhiệm của lập trình viên là phải thao tác một cách cẩn thận với một con trỏ.
Tóm lược
- Một con trỏ không là gì khác ngoài một vị trí bộ nhớ nơi dữ liệu được lưu trữ.
- Một con trỏ được sử dụng để truy cập vị trí bộ nhớ.
- Có nhiều loại con trỏ khác nhau như con trỏ null, con trỏ hoang dã, con trỏ void và các loại con trỏ khác.
- Con trỏ có thể được sử dụng với mảng và chuỗi để truy cập các phần tử hiệu quả hơn.
- Chúng ta có thể tạo các con trỏ hàm để gọi một hàm động.
- Các phép toán số học có thể được thực hiện trên một con trỏ được gọi là số học con trỏ.
- Con trỏ cũng có thể trỏ đến một hàm giúp dễ dàng gọi các hàm khác nhau trong trường hợp xác định một mảng con trỏ.
- Khi bạn muốn xử lý kiểu dữ liệu biến khác nhau, bạn có thể sử dụng con trỏ void typecast.