Vì con trỏ có khả năng tham chiếu trực tiếp đến giá trị mà chúng trỏ tới nên cần thiết phải chỉ rõ kiểu dữ liệu nào mà một biến con trỏ trỏ tới khai báo nó. Vì vậy, khai báo của một biến con trỏ sẽ có mẫu sau:
<kiểu dữ lỉệu> *<tên_con_trỏ>;
frong đó kiểu dữ 1 Ỉ1 là kiểu dữ liệu của vùng nhớ được trỏ tới, không phải là kiểu của bản thân con trỏ. Ví dụ:
int *number; char *character; float *greatnumber;
Đó là khai báo của ba biến con trỏ. Mỗi biến trỏ tới một kiểu dữ liệu khác nhau nhưng cả ba đều là con trỏ và chúng đều chiếm một lượng bộ nhớ như nhau (kích thước của một biến con ưỏ tùy thuộc vào hệ điều hành). Nhưng dữ liệu mà chúng trỏ tới không chiếm lượng bộ nhớ như nhau, một kiểu ỉnt, một kiểu char và cái còn lại kiểu float.
Chú ý: Dấu sao (*) mà được đặt khi khai báo một con trỏ để ám chỉ
Ví dụ 3.2.1: Ví dụ cách sử dụng con trỏ
#include <stdio.h> #include <conio.h> int main 0
{
int vall = 5, val2 = 15; int *ptr;
ptr = &val 1; // tuong duong voi *ptr = 5 *ptr =10; // tuong duong voi vall = 10 ptr = &val2; // tuong duong voi *ptr = 15 *ptr = 20; // tuong duong voi val2 =20
printf("valuel=%d\t value2 =%d",vall,val2); //In ra: valuel=10 value2=20
getch(); return 0;
}
Khi con trỏ chưa được chỉ định vào một vùng nhớ cụ thể nào, có thể coi con trỏ mang giá trị NULL. Ví dụ như dịng khai báo int *ptr ở trên. Thực sự con trò pfr đã được khởi tạo một giá trị nào đó, và cỏ thể nó trùng với một địa chỉ của vùng nhớ nào đó trong ơ nhớ. Nhưng khơng có nghĩa là nó sẽ trỏ vào vùng nhớ đó. Cho nên có thể nói con trỏ 1ÚQ này là con trỏ rỗng, hay mang giá trị NULL. Để cấp phát bộ nhớ cho con trỏ có thể dung hàm malloc. Tuỳ bộ chương trình dịch mà hàm này có thể đặt frong thư viện có tên là malloc.h hay alloc.h hay calloc.h
Cú pháp: <Tên_contrỏ> = <(kiểu_dữliệu *)> malloc (n*sizeof
(kiểudữliệu));
Ví dụ 3.2.2
int *ptr;
pư = (int *) malloc(sizeof(int));
Khi đó con trỏ ptr sẽ được trỏ vào địa chỉ đầu của vùng nhớ bằng với kích cỡ của dữ liệu kiểu int. Khi đó các phép tốn sau là hoàn toàn hợp lệ
.int X = 5; ♦ptr = x;
Lúc này vùng nhớ do ptr trò tới cũng chứa giá trị 5. Nhưng xin lưu ý ràng khi gán như trên thì pư trỏ tới vùng nhớ khác hồn tồn vùng nhớ của X. Chỉ như ví dụ sau mới là ptr trỏ tới vùng nhớ của X
Ví dụ
int *ptr; int X = 5; pfr = &x;
Tại sao lúc này không cấp phát một vùng nhớ cho con trỏ? Câu trả led đơn giản là vì khi cấp phát bộ nhớ do con trò ptr trỏ tới rồi thực hiện phép gán ptr =&x thì con trỏ ptr sẽ khơng trỏ vào vùng nhớ đã được cấp phát nữa. Và chẳng có con trỏ nào hay biến nào kiểm soát vùng nhớ này. Nó gây ra hiện tượng thất thốt bộ nhớ hay còn gọi là rò rỉ bộ nhớ.
Với hàm malloc ở trên có thể cấp phát bộ nhớ cho con trỏ ngay khi nó được khai báo:
int *x = (int*) malloc(sizeof(int))
Chúng ta lại gặp hàm sizeofQ. Chi tiết về hàm này sẽ được giới thiệu ở phần đọc thêm của chương này.
Chúng ta có thể khai báo nhiều con trỏ trên mơt dịng, nhưng hết sức lưu ý:
Ví dụ
int *ptrl, ptr2; int *ptrl, *ptr2;
Hai cách khai báo trên là hoàn toàn khác nhau và cách khai báo thứ hai mới là khai báo hai cịn trỏ. Con trỏ cũng có phép tốn của nó. Vậy phép tốn trên con trỏ bao gồm những gì?
oPhép cộng con trỏ với số nguyên:
■ Pfr là con trỏ kiểu T, k là số nguyên thì (Ptr+k) là con trỏ kiểu T. Ptr trỏ tới phần tử t thì (Ptr+k) trỏ tới phần tử cách t một khoảng là k (k<0 về miền địa chỉ lớn hơn và k<0 về miền địa chỉ nhỏ hơn)
oPhép trừ hai con trỏ:
■ p, q là hai con trỏ kiểu T thì p-q là số nguyên chỉ số phần tử kiểu T nằm giữa hai phần tử do p và q trỏ tới.
Trong các kiểu dữ liệu thì có loại dữ liệu không xác định là void. Tương ứng với nó cũng có con trỏ void*. Con trỏ như vậy gọi là con frỏ không định kiểu. Con ứỏ không định kiểu là một loại con trỏ đặc biệt. Nó có thể trỏ tới bất kì loại dữ liệu nào, từ giá trị nguyên hoặc thực cho tới một xâu kí tự. Hạn chế duy nhất của nó là dữ liệu được trỏ tới không thể được tham chiếu tới một cách trực tiếp (chúng ta khơng thể dùng tốn tử tham chiếu * với chúng) vì độ dài của nó là khơng xác định và vì vậy chúng ta phải dùng đến toán tử chuyển kiểu dữ liệu hay phép gán để chuyển con trỏ không kiểu thành một con trỏ trỏ tới một loại dữ liệu cụ thể.
Một trong những tiện ích của nó là cho phép truyền tham số cho hàm mà không cần chỉ rõ kiểu. Truyền tham số bằng con trỏ sẽ được giới thiệu kĩ hơn trong các phần dưới đây.