Chương 5 CON TRỎ (Pointer)

31
Chương 5 CON TRỎ (Pointer) 1

description

Chương 5 CON TRỎ (Pointer). 1. Khái niệm. Một con trỏ là một biến chứa địa chỉ ô nhớ . Địa chỉ này là vị trí của một đối tượng khác trong bộ nhớ . Ví du: f loat x;//x là một biến có kiểu float x=12.5;//x có giá trị là 12.5 - PowerPoint PPT Presentation

Transcript of Chương 5 CON TRỎ (Pointer)

Page 1: Chương 5 CON TRỎ (Pointer)

Chương 5CON TRỎ(Pointer)

1

Page 2: Chương 5 CON TRỎ (Pointer)

1. Khái niệm

Một con trỏ là một biến chứa địa chỉ ô nhớ. Địa chỉ này là vị trí của một đối tượng khác trong bộ nhớ.

Ví du:

float x; //x là một biến có kiểu float

x=12.5; //x có giá trị là 12.5

Và lúc này, biến x chiếm 4 ô nhớ liên tiếp, giả sử mỗi ô nhớ có kích thước 1 byte.

2

Page 3: Chương 5 CON TRỎ (Pointer)

Địa chỉ của ô nhớ Địa chỉ của ô nhớ là số thứ tự của byte đầu tiên trong

một dãy các byte liên tiếp. Địa chỉ này được tính ở hệ đếm 16.

Ví dụ :int a[4];

Mỗi biến kiểu int chiếm 2 bytes, như vậy bộ nhớ sẽ dành 8 ô nhớ cho biến a. Và cách đánh địa chỉ như sau: giả sử địa chỉ của biến a[0] là ffee

3

Page 4: Chương 5 CON TRỎ (Pointer)

int

px

2. Con trỏ Con trỏ là một kiểu dữ liệu đặt biệt dùng để quản lý địa chỉ

của các ô nhớ. Con trỏ kiểu <T> chỉ được dùng để chứa địa chỉ của biến

kiểu <T>; nghĩa là con trỏ kiểu int chỉ được dùng để chứa địa chỉ của biến kiểu int, con trỏ kiểu float chỉ được dùng để chứa địa chỉ của biến kiểu float.

Cách khai báo như sau:<type>* <PointerName>;

Ví dụ: int *pi;

Có thể khai báo con trỏ nhiều cấp, ví dụ:int * *ppi;float * * *pppf;

4

Page 5: Chương 5 CON TRỎ (Pointer)

Phép lấy địa chỉ của một biến

Kí hiệu: & Cách sử dụng:&<VarName> Ví dụ: int *pi=&a; // pi giữ địa chỉ của các biến nguyên aLưu ý:

Trong trường hợp trên, pi là một địa chỉ có giá trị địa chỉ là &a, và &pi cũng là một địa chỉ nhưng giá trị địa chỉ này không phải là &a mà là nơi ghi nhận giá trị &a, khi đó:

int **ppi=&pi; // con trỏ 2 cấp

5

Page 6: Chương 5 CON TRỎ (Pointer)

Phép toán lấy giá trị tại một địa chỉ mà một con trỏ đang trỏ tớiKí hiệu: *Cách sử dụng: *<PointerName>Ví dụ:

int a= 10; // biến a có giá trị 10

int *pi;

pi =&a; //pi giữ địa chỉ của biến a*pi là giá trị của a bà bằng 10

6

Page 7: Chương 5 CON TRỎ (Pointer)

7

a 25 x

y

25int a=25, x;int *y;x=a;y=&a;

y

Ví dụ 1

Page 8: Chương 5 CON TRỎ (Pointer)

int a, *p; a=25; p=&a; m=*p ;

8

Cho biết Giá trị của m ?

Ví dụ 2

Page 9: Chương 5 CON TRỎ (Pointer)

Phép toán lấy thành phần của cấu trúc với con trỏ

Kí hiệu: -> Cách sử dụng:

<Struct_Pointer_Var_Name> -> <Field_Name>

Ví dụ:

T là con trỏ struct gồm 2 thành phần a và b thì T->a và T->b là giá trị các thành phần a,b tại địa chỉ mà T trỏ vào.

Ghi chú: phép toán này chúng ta sẽ nói thêm trong chương cấu trúc

9

Page 10: Chương 5 CON TRỎ (Pointer)

Chú ý

Cần chú ý rằng việc thay đổi giá trị của pi sẽ làm cho giá trị của a thay đổi theo và ngược lại.

Khi ta khai báo:

int a=10;

int *pi=&a; // pi giữ địa chỉ biến a

*pi=*pi +2; sẽ làm cho biến a có giá trị là 12Lưu ý: Việc sử dụng và thao tác trên giá trị tại địa

chỉ của con trỏ chỉ được thực hiện sau khi con trỏ đã có địa chỉ

10

Page 11: Chương 5 CON TRỎ (Pointer)

Các thao tác trên con trỏ Lệnh gán con trỏ

Có thể dùng phép gán để gán giá trị của một con trỏ cho một con trỏ khác có cùng kiểu

Khi ta khai báo:

int x;

int *p1, *p2;

p1 = &x; // p1 giữ địa chỉ biến a

p2 = p1;

cả hai p1 và p2 cùng trỏ đến biến x.

11

Page 12: Chương 5 CON TRỎ (Pointer)

Phép toán số học trên con trỏo Chỉ có 2 phép toán sử dụng trên con trỏ là phép cộng

và trừ

oKhi cộng (+) hoặc trừ (-) 1 con trỏ với 1 số nguyên N; kết quả trả về là 1 con trỏ. Con trỏ này trỏ đến vùng nhớ cách vùng nhớ của con trỏ hiện tại một số nguyên lần kích thước của kiểu dữ liệu của nó.

12

Các thao tác trên con trỏ

Page 13: Chương 5 CON TRỎ (Pointer)

Ví dụ:

char *a;short *b;long *c;

Khi đó:

a = a + 1; // trỏ vào 1 byte tiếp theob = b + 1; // trỏ vào 2 bytes tiếp theoc = c + 1; // trỏ vào 4 bytes tiếp theo

13

Page 14: Chương 5 CON TRỎ (Pointer)

Minh họa

14

Page 15: Chương 5 CON TRỎ (Pointer)

Ví dụ #include <iostream.h>

#include<conio.h>

void main ()

{

int a = 20, b = 15, *pa, *pb, temp;

pa = &a; // con trỏ pa chứa địa chỉ của a

pb = &b; // con trỏ pb chứa địa chỉ của b

temp = *pa;

*pa = *pb;

*pb = temp;

cout << "a = " << a << endl;

cout << “b = ” << b;

}

15

a = 15b = 20

// kết quả xuất ra màn hình ?

Page 16: Chương 5 CON TRỎ (Pointer)

3. Cấp phát bộ nhớ động

Ý nghĩa của việc cấp phát động bộ nhớBiến toàn cục (global variables) được cấp phát bộ nhớ vào lúc biên dịch. Biến cục bộ (local variables) dùng stack. Tuy nhiên, biến toàn cục hay cục bộ không thể được tạo thêm trong khi thực thi chương trình. Một số chương trình cần thêm bộ nhớ khi thực thi giải pháp cho vấn đề này là cấp phát động.Cấp phát động là phương tiện nhờ đó một chương trình có thể dành được thêm bộ nhớ trong khi đang thực thi.

Con trỏ cung cấp sự hổ trợ cho cấp phát bộ nhớ động trong C/C++.

16

Page 17: Chương 5 CON TRỎ (Pointer)

3.1. Cấp phát bộ nhớ động bởi C++C++ cung cấp hai toán tử cấp phát bộ nhớ động: new và delete.

−Toán tử new cấp phát bộ nhớ và trả về một con trỏ đến byte đầu tiên của vùng nhớ được cấp phát.

−Toán tử delete thu hồi vùng nhớ được cấp phát trước đó bởi toán tử new.

17

Page 18: Chương 5 CON TRỎ (Pointer)

Lưu ý: Cần kiểm tra xem việc cấp phát bộ nhớ có thành công hay không. Nếu thành công, con trỏ trỏ đến địa chỉ đầu khối nhớ được cấp phát và lúc này chúng ta mới có thể thực hiện các thao tác trên con trỏ này.Khi ta khai báo:

int *pi;pi= new int; if (pi==NULL){

cout<<"khong du bo nho";exit(0); /* kết thúc CTr, trả về mã lỗi

Code (0) cho hệ thống*/}

18

Page 19: Chương 5 CON TRỎ (Pointer)

Ví dụ:#include <iostream.h>

int main()

{int *p;

p = new int;

if (p==NULL)

{

cout<<"khong du bo nho";

exit(0);

}

*p = 100;

cout << "At " << p << " ";

cout << "is the value " << *p << "\n";

delete p;

return 0;

} 19

Page 20: Chương 5 CON TRỎ (Pointer)

4. Cấp phát bộ nhớ động bởi C

Ngoài ra, C còn cung cấp một hàm cấp phát và giải phóng bộ nhớ động như malloc(), calloc(), free()…

Cú pháp: cấp phát bộ nhớvoid * malloc (unsigned N_bytes); void * calloc(unsigned N_Blocks,unsigned

N_bytes); Hủy bộ nhớ void free (<pointer_var_name>) // hủy bộ

nhớ

(xem giáo trình) 20

Page 21: Chương 5 CON TRỎ (Pointer)

1 2 4 8 10

// kết quả xuất ra màn hình ?

 Cú pháp: sizeof(<type>)Hoặc sizeof(<expression>)

Tác dụng: Cho biết kích thước của kiểu dữ liệu hoặc của biểu thức

Khi ta khai báo:

cout<<sizeof(char); cout<<sizeof(int);cout<<sizeof(float);cout<<sizeof(double);cout<<sizeof(long double);

Từ khóa sizeof

21

Page 22: Chương 5 CON TRỎ (Pointer)

6. Con trỏ void

• Là một lọai con trỏ đặc biệt mà có thể trỏ đến bất kỳ kiểu dữ liệu nào.

• Cú pháp:

void *PointerName;

• Ví dụ:

void *p;

p = &a; // p trỏ đến biến nguyên a

p = &f; //p trỏ đến biến thực f

22

Page 23: Chương 5 CON TRỎ (Pointer)

Tương thích và không tương thích kiểu Kiểu dữ liệu khi khai báo biến con trỏ chính là kiểu dữ liệu của ô

nhớ mà con trỏ có thể trỏ đến. Địa chỉ đặt vào biến con trỏ phải cùng kiểu với kiểu của con trỏ. Tuy

nhiên, ta cũng có thể ép kiểu con trỏ về đúng kiểu tương ứng khi dùng trong các biểu thức.

Ví dụ:

int a;

float f;

int *pa; float *pf;

pa = &a; pf = &f; // hợp lệ

pa = &f; pf = &a; //không hợp lệ

23

Page 24: Chương 5 CON TRỎ (Pointer)

7. Con trỏ null Khi một con trỏ chưa trỏ tới bất kỳ một địa chỉ nào

cả thì con trỏ đó là con trỏ NULL

#include <iostream.h>

void main()

{

int *p; // p la con trỏ NULLcout <<“Gia tri con tro p tro den la: “<<

*p;

}

24

NULL POINTER ASSIGNMENTNULL POINTER ASSIGNMENT

Page 25: Chương 5 CON TRỎ (Pointer)

8. Con trỏ và mảng Giữa mảng và con trỏ có một sự liên hệ rất chặt chẽ:

– Những phần tử của mảng được xác định bằng chỉ số trong mảng và cũng có thể được xác định qua biến con trỏ.

– Tên của một mảng tương đương với địa chỉ phần tử đầu tiên của nó, tương tự một con trỏ tương đương với địa chỉ của phần tử đầu tiên mà nó trỏ tới.

25

Kiểu mảng Ví dụ Kiểu Con trỏ Ví dụ

&<Tên mảng>[0] &A[0] hoặc A

<Tên con trỏ > p

&<Tên mảng> [<Vị trí>] &A[i] <Tên con trỏ> + <Vị trí> P+i

<Tên mảng>[<Vị trí>] A[i] *(< Tên con trỏ > + <Vị trí>) *(p+i)

Page 26: Chương 5 CON TRỎ (Pointer)

Ví dụ 1:

26

p được gán địa chỉ của phần tử đầu tiên của mảng ch.

p = ch; Để tham chiếu phần tử thứ 3 trong mảng ch, ta dùng một

trong 2 cách sau: ch[2] hoặc *(p+2).

Page 27: Chương 5 CON TRỎ (Pointer)

Ví dụ:

27

Numbers

int Numbers[5];

p= Numbers;

int *p; p

*p = 10;

10

p

p++; *p = 20;

20

p = &numbers[2];

p

*p = 30;

20

p = numbers + 3;

p p

*p = 40;

4030 50

p

p = numbers; *(p+4) = 50;

p

Page 28: Chương 5 CON TRỎ (Pointer)

9. Mảng con trỏ

Mỗi biến con trỏ là một biến đơn. Ta có thể tạo mảng của các con trỏ với mỗi phần tử của mảng là một con trỏ.

Cú pháp:

<type> *pointerArray[elements];o type: kiểu dữ liệu mà các con trỏ phần tử trỏ đến.o pointerArray: tên mảng con trỏ.o elements: số phần tử của mảng con trỏ.

28

Page 29: Chương 5 CON TRỎ (Pointer)

Ví dụ:

29

p

a 100

int *p[5];int a=6;p[0] = &a;

100

p[2] = p[0];

100

6int b;

bb = *p[0];

6

P[0] P[1] P[2] P[3] P[4]

Page 30: Chương 5 CON TRỎ (Pointer)

Tìm số lớn nhất của một dãy số nguyên n phần tử nhập từ bàn phím?

int main()

{

int *px;

int n;

cin>>n;

px=new int[n];

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

cin>>*(px+i);

int max=*px;

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

if (*(px+i)>max)

max=*(px+i);

cout<<max;

return 0;

}

 

30

Page 31: Chương 5 CON TRỎ (Pointer)

Thực hiện bài tập chương 5

31