Tải bản đầy đủ (.ppt) (25 trang)

Tài liệu Ngôn ngữ lập trình - Con trỏ ppt

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (179.09 KB, 25 trang )

1
Lập trình C++ 1
2
Con trỏ
1. Biến và con trỏ
2. Cấp phát và giải phóng bộ nhớ động
3. Mô hình bộ nhớ chương trình
4. Quan hệ giữa mảng và con trỏ
5. Phân biệt tham chiếu và con trỏ
6. Mảng con trỏ. Con trỏ cấu trúc. Con trỏ void
7. Con trỏ làm đối số trong hàm
8. Review
9. Bài tập
3
Biến và con trỏ

Khai báo

int a = 5; // a là biến chứa giá trị int

int *p; // p là con trỏ int, p là biến chứa địa chỉ
// của ô nhớ kiểu int

Truy nhập ô nhớ

p = &a; // toán tử & cho phép lấy địa chỉ của một biến,
// p chứa địa chỉ của biến a

*p = 7; // toán tử * cho phép truy nhập giá trị ô nhớ
// thông qua địa chỉ, giá trị của ô nhớ có địa
// chỉ trong p được gán giá trị 7


4
Biến và con trỏ

Mô tả:
1. int a = 5; // a là biến chứa giá trị int
2. int *p; // p là con trỏ int, p là biến chứa địa chỉ
3. p = &a; // p trỏ đến a
4. *p = 7; // gán giá trị qua p
a
1001
5
p
1100
1. Cấp ô
nhớ cho a
p
1100 1001
2. Cấp ô
nhớ cho p
a
1001
5
3. p chứa địa chỉ
của biến a
p
1100 1001
a
1001
7
4. gán giá trị vào ô

nhớ có địa chỉ trong p
5
Biến và con trỏ

Cho biết kết quả trên màn hình:

int a = 5;

int *p;

p = &a;

cout<< *p <<“\t”<< a <<endl;

*p = 8;

cout<< *p <<“\t”<< a <<endl;

a = 9;

cout<< *p <<“\t”<< a <<endl;
6
Cấp phát và giải phóng bộ nhớ động

Biến tĩnh

Là biến được cấp vùng nhớ ngay khi lời khai báo
được thực hiện

Tự động mất đi khi ra khỏi phạm vi khai báo


Biến tĩnh thường được sử dụng thông qua tên biến

Biến động

Là biến được cấp vùng nhớ bất kì khi nào chương
trình yêu cầu

Bị mất đi khi chương trình giải phóng vùng nhớ

Biến động thường được sử dụng thông qua con trỏ
7
Cấp phát và giải phóng bộ nhớ động

Toán tử new: Cấp phát vùng nhớ

int *p, *q, *r;

p = new int; // cấp phát ô nhớ cỡ int

q = new int(5); // cấp phát đồng thời khởi tạo giá trị

r = new int[8]; // cấp phát mảng động

Toán tử delete: Giải phóng vùng nhớ

delete p; // giải phóng vùng nhớ do p trỏ đến

delete[] r; // giải phóng mảng động
8

Cấp phát và giải phóng bộ nhớ động

Ví dụ:

// biến động

int *p = new int(5); // cấp phát ô nhớ

cout<< *p << endl;

delete p; // giải phóng ô nhớ

// mảng động

int *r = new int[7]; // cấp phát mảng động

for(int i = 0; i<7; i++)

{

r[i] = 3;

cout<<r[i]<<endl;

}

delete[ ] r; // giải phóng mảng động
9
Cấp phát và giải phóng bộ nhớ động


Chú ý: Khi giải phóng một vùng nhớ thì con trỏ
trỏ đến vùng nhớ đó vẫn chứa địa chỉ của vùng
nhớ, và như vậy việc truy nhập đến vùng nhớ đã
giải phóng là không hợp lệ (về logic).
=> Khi giải phóng vùng nhớ, nên gán tất cả con trỏ trỏ
đến vùng nhớ đó bằng NULL.

delete p; // giải phóng vùng nhớ do p trỏ đến

p = NULL; // p không chứa địa chỉ của vùng nhớ nào,
// p không trỏ đến vùng nhớ nào

Không giải phóng một vùng nhớ đã cấp phát sẽ
dẫn đến hiện tượng rò bộ nhớ (memory leak).
10
Cấp phát và giải phóng bộ nhớ động

Cho biết kết quả của đoạn chương trình sau:

int *p, *q;

p = new int(1);

q = new int(2);

cout<< *p <<"\t"<< *q <<endl;

*p = *q + 3;

cout<< *p <<"\t"<< *q <<endl;


p = q;

cout<< *p <<"\t"<< *q <<endl;

*p = 7;

cout<< *p <<"\t"<< *q <<endl;

p = new int;

delete p;

p = NULL;

q = NULL;
11
Mô hình bộ nhớ chương trình

Khi một chương trình được thực thi (execute),
nó có các vùng nhớ như sau:

Vùng CODE: Chứa mã lệnh chương trình

Vùng DATA: Chứa các biến toàn cục

Vùng STACK: Chứa các biến cục bộ

Vùng HEAP: Chứa các biến động


Kích thước của vùng có thể được thiết đặt trước
khi biên dịch.
12
Mô hình bộ nhớ chương trình

Thử nghiệm:

#include <iostream.h>

int g;

void test(int x)

{ int c;

cout<<“Dia chi cua x la: “<< &x <<endl;

cout<<“Dia chi cua c la: “<< &c <<endl;

}

void main()

{ int m;

cout<<“Dia chi cua m la: ”<< &m <<endl;

test(8);

cout<<“Dia chi cua g la: ”<< &g <<endl;


int *p = new int;

cout<<“Dia chi p la: ”<< p <<endl;

}
13
Mảng và con trỏ

Trong C++, mảng là con trỏ hằng trỏ đến một
dãy ô nhớ.

Ví dụ: int x[7]; int a; int *p;

x là một mảng, x là con trỏ hằng trỏ đến ô nhớ đầu
tiên của 7 ô nhớ được cấp phát

Vì x là con trỏ hằng nên ta không thể thay đổi giá trị
địa chỉ mà nó lưu giữ, ví dụ: x = &a;

Vì p cũng là con trỏ nên ta có thể gán p = x;

x trỏ đến ô nhớ đầu tiên, x+1 trỏ đến ô nhớ tiếp
theo Vậy ta có *(x+1) tương đương với x[1]
14
Mảng và con trỏ

Cho biết kết quả của đoạn chương trình sau:

int x[5] = {5, 3, 4, 8, 9};


int *p = x;

*p = 1;

*(p+1) = 7;

p[2] = 15;

x[3] = p[3] + 2;

for(int i=0; i<5; i++)

cout<<x[i]<<endl;
15
Con trỏ và tham chiếu

Con trỏ và tham chiếu hoạt động gần giống
nhau song chúng khác nhau.

Tham chiếu: Là bí danh của một biến.

Con trỏ: Là biến chứa địa chỉ.

Có thể tạo tham chiếu tới một biến động. Ví dụ:

int *p = new int(3); // tạo biến động

int &x = *p; // tạo tham chiếu tới biến động


cout<<x<<endl;

cout<<&x<<endl<<p;
16
Mảng con trỏ

Cho biết kết quả của đoạn chương trình sau:

int *r[5]; // khai báo mảng 5 con trỏ

int i;

for(i=0; i<5; i++)

{

r[i] = new int(i*2); // cấp phát vùng nhớ cho từng con trỏ

cout<<*(r[i])<<endl;

}

for(i=0; i<5; i++)

{

delete r[i]; // giải phóng vùng nhớ

r[i] = NULL;


}
17
Con trỏ cấu trúc

Ví dụ cấu trúc Hàng hoá

struct Hanghoa

{

int soluong;

float dongia;

};



Hanghoa x;

Hanghoa *p, *q;

p = &x;

q = new Hanghoa;

q->soluong = 7; // giống (*q).soluong = 7;

q->dongia = 20.50; // giống (*q).dongia = 20.50;
18

Con trỏ đối tượng

Ví dụ lớp Sinh viên

class Sinhvien

{

private:



float dtb;

public:

void DatDTB(float d) { dtb = d; }

};



Sinhvien *p = new Sinhvien;

p->DatDTB(8.7); // giống (*p).DatDTB(8.7);
19
Con trỏ đối tượng

Ví dụ lớp Hình tròn


class Hinhtron

{

private:

int bankinh;

public:

Hinhtron(int a) { bankinh = a; }

float LayDientich() { return 3.14*bankinh*bankinh; }

};



Hinhtron *p = new Hinhtron(4); // tạo hình tròn có đối số

cout<< p->LayDientich(); // giống (*p).LayDientich();
20
Con trỏ void

Con trỏ void là con trỏ có thể trỏ đến bất kỳ đối
tượng nào. Khi muốn lấy giá trị của nó ta cần
phải ép kiểu.

void* p;


p = new int(4); // p trỏ đến một vùng nhớ kiểu int

cout<< *((int *) p); // ép kiểu để lấy giá trị int

p = new Hanghoa; // p trỏ đến một vùng nhớ kiểu Hanghoa

cout<< ((Hanghoa *) p)->soluong; // ép kiểu Hanghoa

p = new Sinhvien; // p trỏ đến một vùng nhớ kiểu Sinhvien

((Sinhvien *) p)->DatDTB(8.7); // ép kiểu Sinhvien

p = new Hinhtron(4); // p trỏ đến một vùng nhớ kiểu Hinhtron

cout<< ((Hinhtron *) p)->LayDientich(); // ép kiểu Hinhtron
21
Con trỏ và hàm

Con trỏ làm đối số: Thường được dùng khi đối
số truyền vào là một mảng

void display(int *p, int n)

{

for(int i=0; i<n; i++)

cout<<p[i]<<endl;

}


void main()

{

int x[5] = {3, 8, 2, 9, 4};

display(x, 5);

}
22
Con trỏ và hàm

Con trỏ làm kết quả trả về: Thường được dùng
để trả về một xâu kí tự hay một mảng.

class Sinhvien

{

private:

char ten[30];

public:

char* LayTen();

};


char* Sinhvien::LayTen()

{

return ten;

}
23
Con trỏ và hàm

Tham chiếu con trỏ: Được dùng khi muốn thay
đổi giá trị địa chỉ trong con trỏ.

void test(int *&p)

{



}

Con trỏ hàm: (Bài 6)

typedef void (*FunctionType)(int x);
24
Review
1. Biến và con trỏ khác nhau thế nào ?
2. Phân biệt biến tĩnh và biến động ?
3. Nêu các vùng nhớ của chương trình ?
4. Trong C++, mảng là con trỏ như thế nào ?

5. Tham chiếu khác con trỏ như thế nào ?
6. Con trỏ void là gì ?
7. Nêu một số ví dụ về sử dụng con trỏ hàm ?
25
Bài tập về nhà
1. Sử dụng lớp Hinhtron để viết chương trình tạo
hình tròn (cấp phát động) với các lời gọi cấu tử
khác nhau.
2. Hoàn chỉnh lớp Sinhvien đã học với các
phương thức cần thiết.
3. Viết chương trình nhập một số N, sau đó tạo
mảng động N phần tử với giá trị là các số
Fibonacci. In mảng ra màn hình và cuối cùng
giải phóng mảng.

×