
64
"e>dit an address",
"d>isplay an address"
};
static char tieude[40]="main menu\n\n";
thucdon(tieude,chon,3);
getch();
return 0;
}
void thucdon(char *tieude,char *lua[],int
kichthuoc)
{
int i;
printf(tieude);
for (i=0;i<kichthuoc;i++)
printf("%s\n",*(lua +i));
}
2.5. Con trỏ
2.5.1. Khái niệm con trỏ
Con trỏ là một biến chứa địa chỉ của một biến.
Vì có nhiều loại địa chỉ nên cũng có nhiều kiểu con trỏ tương ứng. Con trỏ
int chứa địa chỉ của các biến kiểu int, con trỏ kiểu float, kiểu double,... Cũng tương
tự như vậy.
Trong C, con trỏ thường được sử dụng vì với con trỏ thì chương trình có thể
được viết ngắn gọn hơn và hiệu quả hơn những cấu trúc khác.
2.5.2. Khai báo con trỏ
Cũng như các biến khác, một con trỏ phải được khai báo trước khi sử dụng.
Người lập trình phải chỉ ra kiểu của biến được trỏ tới.
Mẫu khai báo
kiểu_của_biến_được_trỏ *tên_biến_trỏ;

65
ví dụ: int *p;
*p là dữ liệu được chứa trong địa chỉ là p. Nói cách khác p là vùng nhớ chứa
địa chỉ của *p. Hay p là con trỏ trỏ tới biến chứa giá trị *p.
Khi ta khai báo một biến con trỏ, máy sẽ cấp phát một vùng bộ nhớ là 2 byte
hoặc 4 byte tuỳ theo kiểu của biến được trỏ.
Ví dụ: khai báo int *p; thì máy sẽ cấp phát một vùng nhớ 2 byte liên tiếp
cho biến trỏ p.
Khai báo
float x=90.8; - máy sẽ cấp phát một vùng nhớ là 4 byte liên tiếp cho biến x.
Con trỏ và địa chỉ của biến
Địa chỉ của biến là số thứ tự của byte đầu tiên được cấp phát trong dãy các
byte cấp phát cho biến (các byte được đánh số từ 0)
Như đã trình bày trên, con trỏ là một biến gồm một nhóm các ô nhớ (2 hoặc
4 byte) để lưu trữ các địa chỉ.
Phép toán một ngôi & xác định địa chỉ của đối tượng mà con trỏ trỏ tới.
Phép toán một ngôi * sử dụng với biến trỏ để xác định giá trị ở địa chỉ mà
con trỏ trỏ tới.
Ví dụ: giả sử ta khai báo các biến x, p và phép gán như sau:
int x=12; // x là biến có giá trị bằng 15
int *p; // con trỏ p trỏ tới dữ liệu kiểu số nguyên
p=&x; // p nhận giá trị địa chỉ của x.
Đầu tiên biến trỏ p chứa có một giá trị xác định, sau khi có phép gán p=&x;
thì biến p chứa địa chỉ của ô nhớ x, và tất nhiên nó cũng chứa địa chỉ của bản thân
nó. Khi biến trỏ không chứa bất kì một địa chỉ nào thì giá trị của nó là null.
Cách dùng con trỏ
Ta có thể sử dụng tên con trỏ hoặc khai báo của nó trong các biểu thức.
Không nhập giá trị cho con trỏ từ bàn phím.
Quy cách in con trỏ và địa chỉ là: *p
tên biến trỏ
chỉ rằng đây là biến trỏ
kiểu biến được trỏ

66
+ Sử dụng tên con trỏ: con trỏ cũng là một biến nên có thể dùng trong biểu
thức vì giá trị của nó sẽ được dùng trong biểu thức này (nhưng chú ý rằng giá trị của
con trỏ là địa chỉ của biến nào đó). Khi tên con trỏ đứng ở vế trái của biểu thức gán
thì vế phải (phải là địa chỉ của biến) được gán cho con trỏ.
Ví dụ: float a, *p, *q; // khai báo a là một số thực, p và q là hai con trỏ
p=&a; // địa chỉ của biến a được gán cho con trỏ p
q=p; // giá trị của con trỏ p được gán cho con trỏ q
Cũng như các biến khác, nội dung của con trỏ có thể được thay đổi và ta có
thể sử dụng quy tắc này để biến đổi địa chỉ.
Sử dụng dạng khai báo của con trỏ
giả sử ta có các khai báo
int x,y,z,*px,*py;
px=&x;
py=&y;
Thì con trỏ px trỏ tới x (hay còn nói px chứa địa chỉ của x) và con trỏ py trỏ
tới y (py chứa địa chỉ của y). Khi đó ta có các cách viết x và *px là như nhau,
nghĩa là
*px=x;
*py=y
*px, *py là giá trị mà con trỏ px, py trỏ tới
ví dụ: kiểm định các giá trị của con trỏ
#include<stdio.h>
#include<conio.h>
void main()
{
clrscr();
int so;
int *contro;
so=10;
printf(“\ndia chi cua so:%p “,&so);
printf(“\ngia tri cua so:%d “,so);
contro=&so;

67
printf(“\ndia chi cua con tro:%p “,&contro);
printf(“\ngia tri cua con tro:%p “,contro);
printf(“\ng_tri duoc con tro tro toi:%d “,*contro);
getch();
return;
}
Giả sử địa chỉ của biến so là fff4 và địa chỉ của contro là fff2, khi đó chương
trình sẽ cho kết quả là:
2.5.3. Các phép toán trên con trỏ
Phép toán một ngôi & xác định địa chỉ của đối tượng mà con trỏ trỏ tới.
Phép toán một ngôi * sử dụng với biến trỏ để xác định giá trị ở địa chỉ mà
con trỏ trỏ tới.
Các phép toán số học:
Phép cộng một con trỏ với một số nguyên được một con trỏ có cùng kiểu
Phép trừ một con trỏ với một số nguyên được một con trỏ có cùng kiểu
Phép trừ hai con trỏ có cùng kiểu sẽ được một số nguyên giả sử ta có khai
báo: int *p, i=5;
thế thì:
- phép ++p là: tăng giá trị của p lên một đơn vị
- phép --p là: giảm giá trị của p một đơn vị
Đơn vị tăng hay giảm của một con trỏ luôn luôn có kích thước của biến được
trỏ vào. Nếu giá trị của biến được trỏ vào thuộc kiểu int thì một đơn vị tăng giảm là
2 byte. Nếu giá trị của biến được trỏ vào thuộc kiểu float thì một đơn vị tăng giảm
là 4 byte ... .
dia chi cua so: fff4
gia tri cua so: 10
dia chi cua con tro: fff2
gia tri cua con tro: fff4
gia tri duoc con tro tro toi: 10

68
Các phép giữa các biến con trỏ:
Phép gán: =
Các phép so sánh: = (bằng nhau), != (khác nhau)
Lưu ý:
Phép toán & chỉ thực hiện cho các đối tượng trong bộ nhớ, nghĩa là chỉ
thực hiện đối với các biến và các phần tử của mảng (mà thực chất là các biến có
cùng tên), không được sử dụng được với các hằng, biểu thức và các biến thanh ghi.
Nếu p là con trỏ trỏ tới một biến nguyên a thì p có thể xuất hiện trong các
biểu thức, các câu lệnh giống như x.
Ví dụ: *p=10+ ++*p;
Con trỏ kiểu tổng quát: Con trỏ kiểu tổng quát là con trỏ có thể trỏ tới
mọi kiểu con trỏ, nhưng ngược lại thì không được mà phải dùng phép ép kiểu.
Con trỏ kiểu tổng quát là con trỏ khai báo kiểu void.
Các phép tăng, giảm địa chỉ và phép so sánh không dùng với con trỏ
tổng quát.
ví dụ:
void *tongquat;
int *nguyen;
char *kitu;
tongquat = nguyen; //phộp gỏn hợp lệ
*nguyen = *tongquat; //khụng hợp lệ
kitu = (char)tongquat; //sử dụng đúng phép ép
kiểu
2.5.4. Con trỏ và xâu ký tự
Về thực chất xâu ký tự chính là một mảng có các phần tử là các ký tự, do
vậy việc mối quan hệ giữa xâu ký tự và con trỏ chính là mối quan hệ giữa mảng
một chiều với con trỏ, và điều này ta đã nghiên cứu ở phần trước.
Tên xâu ký tự là một hằng địa chỉ biểu thị địa chỉ phần tử đầu của mảng chứa
xâu ký tự đó.
Khai báo
char *tên;
Ví dụ:

