Slide bài giảng Lập trình C++ - Lương Trần Hy Hiến - Con trỏ
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
Tóm tắt nội dung Slide bài giảng Lập trình C++ - Lương Trần Hy Hiến - Con trỏ, để xem tài liệu hoàn chỉnh bạn click vào nút "TẢI VỀ" ở trên
HIENLTH, C++ - 2010
Nội dung
Tổ chức của chương trình
Địa chỉ
Biến con trỏ
HIENLTH, C++ - 2010
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
2
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.
HIENLTH, C++ - 2010
Mỗi segment lưu một loại dữ liệu nhất định.
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
3
Địa chỉ
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 biến
HIENLTH, C++ - 2010
ư
Vị trí của biến trong segment
Đị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
4
Ví dụ
int a;
void main()
{
16
12
16
12
HIENLTH, C++ - 2010 5
int b;
double c;
…
}
8
4
0 a
Stack Data
8 c
4
0 b
Con trỏ – Một số lý do nên sử dụng
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ỉ
HIENLTH, C++ - 2010
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
Biến con trỏ
Là biến dùng để lưu giá trị địa chỉ
Cú pháp khai báo một biến con trỏ
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
HIENLTH, C++ - 2010
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)
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.
7
Con trỏ – Khai báo trong C++
int *pi;
long int *p;
fl t* f
HIENLTH, C++ - 2010 8
oa p ;
char c, d, *pc; /* c và d kiểu char
pc là con trỏ đến char */
double* pd, e, f; /* pd là con trỏ đến double
e and f are double */
char *start, *end;
Các thao tác trên con trỏ
Phép lấy địa chỉ:
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
HIENLTH, C++ - 2010
chỉ phải thuộc kiểu mà con trỏ có thể lưu địa chỉ.
Ví dụ:
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
9
Con trỏ - Toán tử “&”
Đị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.
char g = 'z';
p c
HIENLTH, C++ - 2010 10
0x91A2
0x1132
void main()
{
char c = 'a';
char *p;
p = &c;
p = &g;
}
'a'
0x1132
p g
'z'
0x91A2
Con trỏ - Toán tử *
Phép khử địa chỉ
Kí hiệu: *
Cú pháp: *tên-biến-con-trỏ
Ý ngh a: truy xuất ến vùng nh có a chỉ ang c
HIENLTH, C++ - 2010
ĩ đ ớ đị đ đượ
lưu bởi biến con trỏ đi kèm
Ví dụ:
int a = 5;
int* pa = &a;
*pa = 6;
cout << *pa;
11
Con trỏ - Toán tử *
#include
using namespace std;
char g = 'z';
void main()
a
z
0x1132
p c
'a'
0x1132
HIENLTH, C++ - 2010 12
{
char c = 'a';
char *p;
p = &c;
cout<<*p<<"\n";
p = &g;
cout<<*p<<"\n";
}
xuất giá trị do p đang
quản lý
0x91A2
p g
'z'
0x91A2
Con trỏ - Truyền tham số địa chỉ
#include
using namespace std;
void change(int *v);
void main()
HIENLTH, C++ - 2010 13
{
int var = 5;
change(&var);
cout<<"main: var = “<<var<<endl;
}
void change(int *v)
{
(*v) *= 100;
cout<<“change: *v = “<< (*v)<<endl;
}
Con trỏ - Truyền tham số địa chỉ
void Swap(int *a, int *b)
{
int t = *a; *a = *b; *b = t;
}
HIENLTH, C++ - 2010
void main()
{
int m = 5, n = 7;
cout<<“m = “<<m<<“, n = “<<n<<endl;
Swap(&m, &n);
cout<<“m = “<<m<<“, n = “<<n<<endl;
}
14
Con trỏ NULL
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ệ.
#i l d i t
HIENLTH, C++ - 2010 15
nc u e
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";
}
Con trỏ - Toán tử gán “=”
Có sự khác biệt rất quan trọng khi thực hiện các
phép gán:
0x15A0int i = 10, j = 14;
int* p = &i;
p i
10
0x15A0
14
HIENLTH, C++ - 2010 16
0x15A0
0x15A4
int *q = &j;
*p = *q;
int i = 10, j = 14;
int *p = &i;
int *q = &j;
p = q;
và:
q j
0x15A4
14
p i
10
0x15A0q j
0x15A4
0x15A4
14
0x15A4
Luyện tập – Điền vào ô trống
void main()
{
inti = 10, j = 14, k;
int*p = &i;
i
0x2100
j
0x2104
HIENLTH, C++ - 2010 17
int*q = &j;
*p += 1;
p = &k;
*p = *q;
p = q;
*p = *q;
}
k
0x1208
p
0x120B
q
0x1210
Con trỏ và mảng
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.
int A[6] = {2, 4, 6, 8, 10, 12};
HIENLTH, C++ - 2010 18
int *P;
P = A;
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
HIENLTH, C++ - 2010
định qua phép gán địa chỉ khi chương trình thực thi.
19
#include
using namespace std;
void main()
{
int a[10] = {1, 3, 4, 2, 0};
int *p;
p = a; //a = p: sai
cout<<a<<a[0]<<p<<*p<<endl;
}
Ví dụ con trỏ và mảng
Bắt đầu:
HIENLTH, C++ - 2010 20
Thực hiện P = &A[2];
Bây giờ, P[0] là A[2],
P[1] là A[3], …
Con trỏ - Toán tử “+” với số nguyên
34
#include
using namespace std;
void main()
{
short a[10] = {1, 3, 5, 2, 0};
1
5
a
0x15A0
HIENLTH, C++ - 2010 21
0x15A02
short *p = a;
cout<<a<<a[0]<<p<<*p<<endl;
p ++;
cout<<a<<a[0]<<p<<*p<<endl;
(*p) ++;
cout<<a<<a[0]<<p<<*p<<endl;
}
2
0
…
p0x16B2
Con trỏ và mảng
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 a[i], tức a[i-j]
HIENLTH, C++ - 2010
ư
22
Các phép toán trên con trỏ
HIENLTH, C++ - 2010 23
Con trỏ - Luyện tập
void main()
{
int a[10] = {2, 3, 5, 1, 4,
7, 0};
2 2
3 1
1 9
1 3
HIENLTH, C++ - 2010 24
int *p = a;
cout<< a[0] << *p <<endl;
p ++;
cout<< *p << p[2] <<endl;
p ++; a[2] = 9;
cout<< p[1] << *p;
p -= 2;
cout<< p[3] << p[1] <<endl;
}
Biến tĩnh và biến động
Biến tĩnh Biến động
Có tên Không có tên
HIENLTH, C++ - 2010
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
Phạm vi sử dụng từ lúc khai báo đến
hết khối gần nhất chứa nó.
Phạm vi sử dụng bắt đầu từ lúc
đượ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
Không tự động giải phóng. Lập
trình viên phải lo việc này.
25
Cấp phát biến động
Không có tên, chỉ có địa chỉ dùng biến con trỏ để
lưu địa chỉ.
Cú pháp:
Biế t ỏ Kiể
HIENLTH, C++ - 2010
n-con- r = new u;
Biến-con-trỏ = new Kiểu[số phần tử];
Ví dụ:
int* p = new int;
double* pd = new double[10];
26
Hủy biến động
Thông qua biến con trỏ lưu địa chỉ của biến động.
Cú pháp:
delete biến-con-trỏ;
ế
HIENLTH, C++ - 2010
delete [] bi n-con-trỏ;
Ví dụ:
delete p;
delete [] pd;
27
Câu hỏi và thảo luận
HIENLTH, C++ - 2010 28
File đính kèm:
Slide bài giảng Lập trình C++ - Lương Trần Hy Hiến - Con trỏ.pdf

