Xem mẫu
- BÀI GIẢNG HỌC PHẦN
KỸ THUẬT LẬP TRÌNH
CHƯƠNG 6: CON TRỎ
- Nội dung
6.1. Con trỏ và cú pháp khai báo
6.2. Các phép toán trên biến con trỏ
6.3. Con trỏ và hàm
6.4. Con trỏ và dữ liệu kiểu mảng, xâu ký tự, cấu trúc
6.5. Cấp phát bộ nhớ động
2
- 6.1. Con trỏ và cú pháp khai báo
• Khái niệm
• Cú pháp khai báo
• Con trỏ kiểu void
3
- Khái niệm
• Kiểu con trỏ là kiểu dữ liệu dùng để chứa địa chỉ
• Biến con trỏ (gọi tắt là con trỏ) dùng để chứa địa chỉ
của một đối tượng (biến hoặc hàm)
• Con trỏ thường được dùng trong các trường hợp:
- Trả về nhiều giá trị từ hàm (thông qua cơ chế
truyền tham số theo địa chỉ trong hàm)
- Truyền mảng và xâu ký tự giữa các hàm
- Tạo các cấu trúc dữ liệu phức tạp (danh sách liên
kết, cây nhị phân, …)
4
- Cú pháp khai báo (1)
• Cú pháp:
kiểu_dữ_liệu *tên_con_trỏ;
Ví dụ:
int x,y,*px,*py;
x, y là các biến nguyên
px, py là các con trỏ kiểu int (cấp phát các vùng nhớ
có tên là px, py dùng để lưu địa chỉ của các đối
tượng kiểu int)
*px là nội dung của px (giá trị của đối tượng mà px
lưu địa chỉ)
*py là nội dung của py (giá trị của đối tượng mà py
lưu địa chỉ)
5
- Cú pháp khai báo (2)
Khi sử dụng các lệnh:
px = &x; //gán địa chỉ của biến x cho con trỏ px
py = &y; //gán địa chỉ của biến y cho con trỏ py
ta nói: px trỏ tới x và py trỏ tới y
*px tương đương với x, *py tương đương với y
6
- Ví dụ (1)
• Khai báo:
int x = 4,y = 5,*px,*py;
Địa chỉ Nội Địa chỉ Nội
Biến Biến
vùng nhớ dung vùng nhớ dung
x 1201 px 2010
4
1202 2011
1203 2012
1204 2013
y 1205 py 2014
5
1206 2015
1207 2016
7
- Ví dụ (2)
• Thực hiện các lệnh gán:
px = &x; py = &y;
Địa chỉ Nội Địa chỉ Nội
Biến Biến
vùng nhớ dung vùng nhớ dung
x 1201 px 2010
4 1201
1202 2011
1203 2012
1204 2013
y 1205 py 2014
5 1205
1206 2015
1207 2016
8
- Ví dụ (3)
• Thực hiện các lệnh gán:
*px += 10; *py += 10;
Địa chỉ Nội Địa chỉ Nội
Biến Biến
vùng nhớ dung vùng nhớ dung
x 1201 px 2010
14 1201
1202 2011
1203 2012
1204 2013
y 1205 py 2014
15 1205
1206 2015
1207 2016
9
- Con trỏ kiểu void
• Là dạng con trỏ đặc biệt (con trỏ không kiểu), có
thể nhận bất kỳ địa chỉ kiểu nào
• Cú pháp khai báo:
void *tên_con_trỏ;
Ví dụ: void *p;
float a[20][30];
p=a;
• Con trỏ void thường được dùng làm tham số để
nhận bất kỳ địa chỉ kiểu nào từ tham số thực. Khi
đó, trong thân hàm phải sử dụng phép ép kiểu để
chuyển sang dạng địa chỉ cần xử lý
10
- 6.2. Các phép toán trên biến con trỏ (1)
Có 4 phép toán cơ bản: Phép gán, phép tăng/giảm
địa chỉ, phép truy nhập bộ nhớ, phép so sánh
• Phép gán giá trị:
- Các con trỏ phải cùng kiểu, muốn gán các con trỏ
khác kiểu nên dùng phép ép kiểu
Ví dụ:
int x;
char *p;
p = (char*)(&x);
11
- 6.2. Các phép toán trên biến con trỏ (2)
• Phép tăng/giảm địa chỉ:
- Ví dụ 1:
float x[30],*p;
p = &x[10];//p trỏ tới x[10]
Giá trị kiểu float lưu trong 4 byte các phép
tăng/giảm địa chỉ được thực hiện trên 4 byte
p+i trỏ tới x[10+i], p-i trỏ tới x[10-i]
- Ví dụ 2:
float y[20][30];
y là một mảng gồm các dòng có 30 phần tử thực
Kiểu địa chỉ của y là 30*4 = 120 byte
y trỏ tới đầu dòng thứ nhất y[0][0]
y+1 trỏ tới đầu dòng thứ hai y[1][0]
…
12
- 6.2. Các phép toán trên biến con trỏ (3)
• Nguyên tắc truy nhập bộ nhớ:
- Con trỏ float truy nhập tới 4 byte, con trỏ int truy
nhập tới 2 byte, con trỏ char truy nhập tới 1 byte
- Ví dụ:
float *pf;
int *pi;
char *pc;
Giả sử pf trỏ tới byte 10001 thì *pf biểu thị vùng
nhớ 4 byte từ 10001 đến 10004
Giả sử pi trỏ tới byte 10001 thì *pi biểu thị vùng
nhớ 2 byte từ 10001 đến 10002
Giả sử pc trỏ tới byte 10001 thì *pc biểu thị vùng
nhớ 1 byte 10001
13
- 6.2. Các phép toán trên biến con trỏ (4)
• Phép so sánh:
- Áp dụng với các con trỏ cùng kiểu
- Ví dụ:
float *p1,*p2;
Khi đó:
+ p1p2 nếu địa chỉ p1 trỏ tới là cao hơn địa chỉ p2
trỏ tới
• Lưu ý: Các phép tăng/giảm địa chỉ, truy nhập bộ
nhớ và phép so sánh không dùng trên con trỏ void
14
- 6.3. Con trỏ và hàm (1)
• Tham số của hàm có thể được chia làm 2 loại: Tham
số đầu vào (chứa các giá trị đã biết) và tham số đầu
ra (chứa các kết quả mới nhận được)
• Thông thường, hàm được dùng để trả về một kết
quả thông qua tên hàm. Khi cần trả về nhiều kết
quả, cần sử dụng các tham số đầu ra dạng con trỏ
• Ví dụ: Hàm trả về nghiệm của phương trình bậc hai
ax2 + bx + c = 0
Tham số đầu vào: a, b, c
Tham số đầu ra: x1, x2
Lưu ý: Khi sử dụng các tham số đầu ra là các con trỏ,
các tham số thực sự tương ứng trong lời gọi hàm
phải là các địa chỉ
15
- 6.3. Con trỏ và hàm (2)
• Chương trình giải phương trình bậc 2:
#include
#include
int ptb2(float a, float b, float c, float *x1,float *x2);
int main(void)
{ float a,b,c,x1,x2;
int kt;
printf("Nhap vao cac he so:\n");
printf("a = ");scanf("%f",&a);
printf("b = ");scanf("%f",&b);
printf("c = ");scanf("%f",&c);
16
- 6.3. Con trỏ và hàm (3)
• Chương trình giải phương trình bậc 2: (tiếp)
kt = ptb2(a,b,c,&x1,&x2);
if (kt == -1)
printf("Delta < 0, phuong trinh vo nghiem!");
else if (kt == 0)
printf("Delta = 0, phuong trinh co nghiem
kep: x1 = x2 = %6.2f",x1);
else
printf("Delta > 0, phuong trinh co 2 nghiem:
x1 = %6.2f, x2 = %6.2f",x1,x2);
return 0;
}
17
- 6.3. Con trỏ và hàm (4)
• Chương trình giải phương trình bậc 2: (tiếp)
int ptb2(float a, float b, float c, float *x1,float *x2)
{
float delta;
delta = b*b-4*a*c;
if (delta < 0)
return -1;
else if (delta == 0)
{
*x1 = -b/(2*a);
return 0;
}
18
- 6.3. Con trỏ và hàm (5)
• Chương trình giải phương trình bậc 2: (tiếp)
else
{
*x1 = (-b+sqrt(delta))/(2*a);
*x2 = (-b-sqrt(delta))/(2*a);
return 1;
}
}
19
- 6.4. Con trỏ và dữ liệu kiểu mảng, xâu ký tự,
cấu trúc
• Con trỏ và mảng một chiều
• Con trỏ và mảng nhiều chiều
• Con trỏ và xâu ký tự
• Con trỏ và cấu trúc
• Mảng con trỏ
20
nguon tai.lieu . vn