Nội dung
Tổ chức của chương trình
Địa chỉ
Biến con trỏ
Các thao tác trên biến con trỏ
Biến tĩnh và biến động
Cấp phát và hủy biến động
HIENLTH, C++ - 2010
HIENLTH, C++ - 2010
Địa chỉ
Tổ chức của chương trình
Một chương trình được chia ra thành nhiều phân
đoạn (segment).
Mỗi segment có thể xem như là một mảng một
chiều.
Mỗi segment lưu một loại dữ liệu nhất định.
Một ô nhớ bất kỳ (một biến bất kỳ) trong chương
trình có một địa chỉ duy nhất.
Mỗi địa chỉ gồm có hai thành phần:
Tên segment lưu
l u biến
Vị trí của biến trong segment
Data Segment: lưu các biến toàn cục
Stack Segment: lưu các biến cục bộ của các hàm và
các thông tin khác
Heap Segment: lưu các biến động
Code Segment: lưu các chỉ thị đoạn mã của chương
trình
HIENLTH, C++ - 2010
2
Địa chỉ thường được ký hiệu là segment:offset
Segment có thể là Data, Heap, Code, Stack
Offset là vị trí của biến trong segment tương ứng
3
HIENLTH, C++ - 2010
4
Con trỏ – Một số lý do nên sử dụng
Ví dụ
int
a;
void main()
{
int b;
double
c;
…
}
16
12
8
4
0
c
b
Stack
16
12
8
4
0
Con trỏ là kiểu dữ liệu lưu trữ địa chỉ của các vùng
dữ liệu trong bộ nhớ máy tính
Kiểu con trỏ cho phép:
Truyền tham số kiểu địa chỉ
Biểu diễn các kiểu, cấu trúc dữ liệu động
Lưu trữ dữ liệu trong vùng nhớ heap
a
Data
HIENLTH, C++ - 2010
5
Biến con trỏ
HIENLTH, C++ - 2010
Con trỏ – Khai báo trong C++
Là biến dùng để lưu giá trị địa chỉ
Cú pháp khai báo một biến con trỏ
int
long int *p;
Kiểu* tên-biến;
Ý nghĩa: khai báo một biến con trỏ dùng để lưu địa chỉ của
các biến thuộc kiểu đã chỉ ra.
Biến con trỏ có kích thước 4 bytes (hệ điều hành 32 bit)
float*
fl t*
pf;
f
char
c, d, *pc; /* c và d kiểu char
pc là con trỏ đến char */
double*
pd, e, f;
char
*start, *end;
Ví dụ:
int* pint; // khai báo một biến con trỏ dùng để lưu địa chỉ
của các biến thuộc kiểu int.
double* pd; // khai báo một biến con trỏ dùng để lưu địa chỉ
của các biến thuộc kiểu double.
HIENLTH, C++ - 2010
*pi;
7
/* pd là con trỏ đến double
e and f are double */
HIENLTH, C++ - 2010
8
Con trỏ - Toán tử “&”
Các thao tác trên con trỏ
Phép lấy địa chỉ:
Địa chỉ của tất cả các biến trong chương trình đều
đã được chỉ định từ khi khai báo.
Kí hiệu: &
Cú pháp: &tên-biến
Ý nghĩa: lấy địa chỉ của biến đi kèm. Biến được lấy địa
chỉ phải thuộc kiểu mà con trỏ có thể lưu địa chỉ.
Ví dụ:
char g = 'z';
void main()
{
char c = 'a';
char *p;
p = &c;
p = &g;
}
int a = 5;
int* pa = &a; // pa sẽ lưu địa chỉ của biến a
int **pb = &pa;//pb lưu địa chỉ của con trỏ pa
HIENLTH, C++ - 2010
9
Con trỏ - Toán tử *
p
0x91A2
c
'a'
0x1132
g
'z'
0x91A2
10
HIENLTH, C++ - 2010
Con trỏ - Toán tử *
Phép khử địa chỉ
#include <iostream>
using namespace std;
char g = 'z';
a
void main()
z
{
char c = 'a';
char *p;
p = &c;
cout<<*p<<"\n";
p = &g;
cout<<*p<<"\n";
}
Kí hiệu: *
Cú pháp: *tên-biến-con-trỏ
Ý nghĩa:
ngh a: truy xuất đến
ến vùng nhớ
nh có địa
a chỉ đang
ang đượcc
lưu bởi biến con trỏ đi kèm
Ví dụ:
int a = 5;
int* pa = &a;
*pa = 6;
cout << *pa;
HIENLTH, C++ - 2010
p
0x1132
11
p
0x1132
c
p
0x91A2
g
'a'
0x1132
'z'
0x91A2
xuất giá trị do p đang
quản lý
HIENLTH, C++ - 2010
12
Con trỏ - Truyền tham số địa chỉ
Con trỏ - Truyền tham số địa chỉ
#include <iostream>
using namespace std;
void change(int *v);
void main()
{
int var = 5;
change(&var);
cout<<"main: var = “<
}
void change(int *v)
{
(*v) *= 100;
cout<<“change: *v = “<< (*v)<
}
HIENLTH, C++ - 2010
13
Con trỏ NULL
14
HIENLTH, C++ - 2010
Con trỏ - Toán tử gán “=”
Giá trị đặc biệt để chỉ rằng con trỏ không quản lý
vùng nào. Giá trị này thường được dùng để chỉ một
con trỏ không hợp lệ.
#include
#i l d <iostream>
i t
using namespace std;
void
main()
{
int i = 13;
short *p = NULL;
if (p == NULL)
cout<<“Con trỏ không hợp lệ!\n";
else
cout<<“Giá trị : “<<*p<<“\n";
}
HIENLTH, C++ - 2010
void Swap(int *a, int *b)
{
int t = *a; *a = *b; *b = t;
}
void main()
{
int m = 5, n = 7;
cout<<“m = “<
Swap(&m, &n);
cout<<“m = “<
}
Có sự khác biệt rất quan trọng khi thực hiện các
phép gán:
int i = 10, j = 14;
int
int* p = &i;
int *q = &j;
*p = *q;
và:
int i = 10, j = 14;
int *p = &i;
int *q = &j;
15
p = q;
p
0x15A0
q
0x15A4
p 0x15A4
0x15A0
q
0x15A4
HIENLTH, C++ - 2010
i
10 14
0x15A0
j
14
0x15A4
i
10
0x15A0
j
14
0x15A4
16
Luyện tập – Điền vào ô trống
void
main()
{
inti = 10, j = 14, k;
int*p = &i;
int*q = &j;
Tên mảng được coi như là một con trỏ trỏ tới phần
tử đầu tiên của mảng.
i
0x2100
j
int A[6] = {2, 4, 6, 8, 10, 12};
0x2104
int *P;
k
P = A;
0x1208
*p += 1;
p = &k;
*p = *q;
p = q;
*p = *q;
}
Con trỏ và mảng
p
0x120B
q
0x1210
HIENLTH, C++ - 2010
17
Con trỏ và Mảng
18
Ví dụ con trỏ và mảng
Biến kiểu mảng là địa chỉ tĩnh của một vùng nhớ, được
xác định khi khai báo, không thay đổi trong suốt chu kỳ
sống.
Biến con trỏ là địa chỉ động của một vùng nhớ, được xác
định qua phép gán địa chỉ khi chương trình thực thi.
#include <iostream>
using namespace std;
void
main()
{
int a[10] = {1, 3, 4, 2, 0};
int *p;
p = a; //a = p: sai
cout<
}
HIENLTH, C++ - 2010
HIENLTH, C++ - 2010
Bắt đầu:
Thực hiện P = &A[2];
Bây giờ, P[0] là A[2],
P[1] là A[3], …
19
HIENLTH, C++ - 2010
20
Con trỏ - Toán tử “+” với số nguyên
#include <iostream>
using namespace std;
void main()
{
short a[10] = {1, 3, 5, 2, 0};
short
*p = a;
cout<
0x15A0
a
}
Giả sử con trỏ ptr trỏ tới phần tử a[i] nào đó của mảng
a, thì:
ptr + j chỉ đến phần tử thứ j sau a[i], tức a[i+j]
ptr - j chỉ đến phần tử thứ j trước
tr ớc a[i], tức a[i-j]
1
4
3
5
2
0
…
p ++;
cout<
(*p) ++;
cout<
Con trỏ và mảng
0x16B2
p
0x15A0
0x15A2
HIENLTH, C++ - 2010
21
Con trỏ - Luyện tập
Các phép toán trên con trỏ
HIENLTH, C++ - 2010
22
HIENLTH, C++ - 2010
23
void main()
{
int a[10] = {2, 3, 5, 1, 4,
7, 0};
int *p = a;
cout<< a[0] << *p <
p ++;
cout<< *p << p[2] <
p ++; a[2] = 9;
cout<< p[1] << *p;
p -= 2;
cout<< p[3] << p[1] <
}
HIENLTH, C++ - 2010
2
3
1
1
2
1
9
3
24
Biến tĩnh và biến động
Cấp phát biến động
Không có tên, chỉ có địa chỉ
lưu địa chỉ.
Cú pháp:
Biến động
Biến tĩnh
Có tên
Không có tên
Kích thước cố định
Kích thước không cố định
Được cấp phát tự động trong Data
Segment hoặc Stack Segment
Được cấp phát trong Heap
Segment
Biến-con-trỏ
Biế
t ỏ = new Kiểu;
Kiể
Biến-con-trỏ = new Kiểu[số phần tử];
Ví dụ:
int* p = new int;
double* pd = new double[10];
Phạm vi sử dụng từ lúc khai báo đến Phạm vi sử dụng bắt đầu từ lúc
hết khối gần nhất chứa nó.
được tạo ra và kết thúc khi bị hủy.
Tự động giải phóng khi hết phạm vi
sử dụng
dùng biến con trỏ để
Không tự động giải phóng. Lập
trình viên phải lo việc này.
HIENLTH, C++ - 2010
25
Hủy biến động
HIENLTH, C++ - 2010
26
Câu hỏi và thảo luận
Thông qua biến con trỏ lưu địa chỉ của biến động.
Cú pháp:
delete biến-con-trỏ;
delete [] biến-con-trỏ;
ế
Ví dụ:
delete p;
delete [] pd;
HIENLTH, C++ - 2010
27
HIENLTH, C++ - 2010
28