slide pointer sepro

34
CON TRỎ TRONG NGÔN NGỮ C/C++ SE-PRO GROUP 1 ĐẠI HỌC CÔNG NGHỆ THÔNG TIN - ĐHQG Tp HCM – SE05

Upload: anh-le-ngoc

Post on 22-Jun-2015

826 views

Category:

Technology


0 download

DESCRIPTION

Quản lý bộ nhớ hiệu quả bằng Con trỏ trong C/C++

TRANSCRIPT

Page 1: Slide pointer sepro

1

CON TRỎ TRONG NGÔN NGỮC/C++

SE-PRO GROUP

Đ I H C CÔNG NGH THÔNG TIN - ĐHQG Tp HCM – SE05Ạ Ọ Ệ

Page 2: Slide pointer sepro

2

NỘI DUNG:

DẪN NHẬP CON TRỎ CƠ BẢN CON TRỎ NÂNG CAOTÀI LIỆU THAM KHẢO

Page 3: Slide pointer sepro

3

DẪN NHẬP#include <stdio.h>int main(){ int i; float f; double *pD; printf("\ni=%d f=%f\n“,i,f); getch(); return 1;}

Memory(RAM)

Win n bit thì RAM tối đa

2n byte

Code data stack

programcode

data

stack*.exe

Con trỏ chỉ là một biến kiểu int lưu địa chỉcủa biến khác

Loader

Process

Compiler

Hệ điềuhành nạp Process lên RAM để thực thiquản lý theođịa chỉ

Lưu trữ tại

Byte 0

Byte 2n

Hệ điều hành n bits

Page 4: Slide pointer sepro

4

Con trỏ cơ bản

Khai báo và cách sử dụng1

Các cách truyền đối số cho hàm2

Con trỏ và cấu trúc4

Con trỏ và mảng một chiều3

Page 5: Slide pointer sepro

5

• Khai báo: Giống như mọi biến khác, biến con trỏ muốn sử dụng cũng cần phải được khai báo

<kiểu dữ liệu> *<tên biến con trỏ>;

int a = 5;int *ptr;ptr = &a;

Ví dụ:

Khai báo con trỏ và cách sử dụng

a

Tên : a Giá tri mà biến lưu trữ : 5 Địa chỉ lưu trong bộ nhớ: 1025(giả định)

ptr

Tên : ptrGiá trị mà biến lưu trữ : 1025 Địa chỉ lưu trong bộ nhớ: 5000(giả định)

Page 6: Slide pointer sepro

6

Khai báo con trỏ và cách sử dụng

• Sử dụng từ khóa typedef

typedef <kiểu dữ liệu> *<tên kiểu con trỏ>;<tên kiểu con trỏ> <tên biến con trỏ>;

typedef int *pInt;int *p1;pInt p2, p3;

• Ví dụ:

• Giảm bối rối khi mới tiếp xúc với con trỏ.• Nhưng dễ nhầm lẫn với biến thường.

Chý ý:

Page 7: Slide pointer sepro

7

Khai báo con trỏ và cách sử dụng

• Con trỏ NULL– Con trỏ NULL là con trỏ không trỏ vào đâu cả.– Khác với con trỏ chưa được khởi tạo.

p2

int n;int *p1 = &n;int *p2; int *p3 = NULL;

// Trỏ đến vùng nhớ kiểu int một cách ngẫu nhiên

*p1 và n đều chỉ nội dung của biến n. p1 và &n đều chỉ địa chỉ của biến n.

NULLChú ý:

Page 8: Slide pointer sepro

8

• Truyền địa chỉ (con trỏ) cho hàm

Cách truyền đối số cho hàm

#include <stdio.h>

void hoanvi(int *x, int *y);

void main(){

int a = 3; b = 6;hoanvi(&a, &b);printf(“a = %d, b = %d”, a, b);

}void hoanvi(int *x, int *y){

int t = *x; *x = *y; *y = t;}

Page 9: Slide pointer sepro

9

Con trỏ và mảng một chiều

• Mảng một chiều

– Tên mảng Array là một hằng con trỏ không thể thay đổi giá trị của hằng này.

– Giá trị của Array là địa chỉ phần tử đầu tiên của mảngArray == &Array[0]

int Array[3];

……

0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17

Array

Page 10: Slide pointer sepro

10

• Con trỏ đến mảng một chiều

Con trỏ và mảng một chiều

int Array[3], *pArray;

pArray = Array; // Cách 1pArray = &Array[0]; // Cách 2

……

0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17

18 19 1A 1B 1C 1D 1E 1F

0B 00 00 00

pArray

Array

Page 11: Slide pointer sepro

11

• Phép cộng (tăng) + n + n * sizeof(<kiểu dữ liệu>) Có thể sử dụng toán tử gộp += hoặc ++

+2

Các phép toán số học trên con trỏ

……

p = Array

0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17

+1

int Array[3]

Con trỏ và mảng một chiều

Page 12: Slide pointer sepro

12

Con trỏ và mảng một chiều

• Phép trừ (giảm) + n + n * sizeof(<kiểu dữ liệu>) Có thể sử dụng toán tử gộp -= hoặc --

p = &Array[2]

–1

–2

……

0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17

int Array[3]

Page 13: Slide pointer sepro

13

Con trỏ và mảng một chiều// Nhập mảngvoid main(){ int a[10], n = 10, *pa; pa = a; // hoặc pa = &a[0];

for (int i = 0; i<n; i++) scanf(“%d”, &a[i]); // scanf(“%d”, &pa[i]);

// scanf(“%d”, a + i);// scanf(“%d”, pa + i);// scanf(“%d”, a++);// scanf(“%d”, pa++);

} &a[i] (a + i) (pa + i) &pa[i]

// Xuất mảngvoid main(){ int a[10], n = 10, *pa; pa = a; // hoặc pa = &a[0];

for (int i = 0; i<n; i++)printf(“%d”, a[i]);

// printf(“%d”, pa[i]); // printf(“%d”, *(a + i)); // printf(“%d”, *(pa + i)); // printf(“%d”, *(a++); // printf(“%d”, *(pa++));} a[i] *(a + i) *(pa + i) pa[i]

Page 14: Slide pointer sepro

14

Con trỏ và mảng một chiều

void xuat(int _a[10], int n){

for (int i = 0; i<n; i++)printf(“%d”, *(_a++)); // OK

}void main(){

int a[10], n = 10;

for (int i = 0; i<n; i++)printf(“%d”, *(a++)); // Lỗi

}

Đối số mảng truyền cho hàm

Đối số mảng truyền cho hàm không phải hằng con trỏ.

Page 15: Slide pointer sepro

15

Con trỏ và mảng một chiều• Các phép toán khác– Phép so sánh: So sánh địa chỉ giữa hai con trỏ (thứ

tự ô nhớ) == != > >= < <=

– Không thể thực hiện các phép toán: * / %

Page 16: Slide pointer sepro

16

Con trỏ và cấu trúc

Truy xuất bằng 2 cách

typedef struct{

int tu, mau;} PHANSO;PHANSO ps1, *ps2 = &ps1; // ps2 là con trỏ

ps1.tu = 1; ps1.mau = 2;ps2->tu = 1; ps2->mau = 2; (*ps2).tu = 1; (*ps2).mau = 2;

<tên biến con trỏ cấu trúc>-><tên thành phần>(*<tên biến con trỏ cấu trúc>).<tên thành phần>

Ví dụ

Page 17: Slide pointer sepro

17

Bài tập con trỏ cơ bản

float pay;float *ptr_pay;pay=2313.54;ptr_pay = &pay;

Bài 1: Cho đoạn chương trình sau:

Hãy cho biết giá trị của:a. pay b. *ptr_payc. *payd. &pay

Page 18: Slide pointer sepro

18

Bài tập con trỏ cơ bản

• Bài 2: Tìm lỗi#include <stdio.h> #include <conio.h>

void main() {

int *x, y = 2;

*x = y;*x += y++;

printf("%d %d", *x, y);getch();

}

Con trỏ x chưa được khởi tạo

Page 19: Slide pointer sepro

Bài tập con trỏ cơ bản

• Bài tập 3: Cho biết giá trị xuất ra

Output: ???#include <stdio.h> #include <conio.h>

void main() {

int x=25;int *ptr=&x; int **temp=&ptr;printf(“%d %d %d”,x,*ptr,**temp);

}

Page 20: Slide pointer sepro

Bài tập con trỏ cơ bản• Bài 4: Cho đoạn chương trình: #include <stdio.h> #include <conio.h>void main() {

int *ptr=( int *)1000;ptr=ptr+1;printf(" %u",ptr);

}

Output: ???

Page 21: Slide pointer sepro

Bài tập con trỏ cơ bản• Bài 5: Cho đoạn chương trình: #include <stdio.h> #include <conio.h>

void main() {

double *p=( double *)1000;p=p+3;printf(" %u",p);

}

Output: ???

Page 22: Slide pointer sepro

Bài tập con trỏ cơ bản• Bài 6: Cho đoạn chương trình:

#include <stdio.h> #include <conio.h>void calc(int* a, int b)

{ *a = b; *a += b++;

} int main() { int x=5,y=6; calc (&x,y); printf(“%d %d”, x, y); return 0; }

Output: ???

Page 23: Slide pointer sepro

23

Con trỏ nâng cao

Mảng con trỏ2

Mảng động hai chiều3

Con trỏ hàm4

Cấp phát động1

Page 24: Slide pointer sepro

24

Cấp phát độngĐể cấp phất động chúng ta sử dụng thư viện <stdlib.h>

void *malloc( size );

void *calloc( num, size );

HOẶCSố byte cần cấp phát

Kích thước một khối nhớ

Số lượng khối nhớ cần cấp phát

Cấp phát một khối nhớ size bytes trả về con trỏ void trỏ đếnđầu khối nhớ đó và trả về NULL nếu thất bại.

Cấp phát một khối nhớ num*size bytes trả về con trỏ void trỏđến đầu khối nhớ đó và trả về NULL nếu thất bại.

Page 25: Slide pointer sepro

25

Cấp phát độngVí dụ:

double *dVar;dVar = (double*) malloc ( sizeof(double) );

Tương tự với calloc

Dùng con trỏ dVar để quản lý khối nhớ động kiểu double vừa được malloc cấp phát.

double *dVar;dVar = (double*) calloc ( 1 , sizeof(double) );

Để có được một mảng động với n phần tử trong bộ nhớ ta làm như sau:

double *dVar;dVar = (double*) malloc ( n*sizeof(double) );

double *dVar;dVar = (double*) calloc ( n , sizeof(double) );

HOẶC

Page 26: Slide pointer sepro

26

Mảng con trỏĐặt vấn đề

• Khi cần lưu trữ những dãy dữ liệu lớn kích thước không bằng nhau ví dụ như một dãy tên sinh viên chẳng hạn nếu ta dùng mảng hai chiều để lưu trữ sẽ dẫn đến lãng phí do kích thước mỗi tên phải bằng nhau.

Giải quyết vấn đề•Ta dùng một cách lưu trữ mới đó là mảng con trỏ. Với bài toán lưu trữ và xử lý dãy tên sinh viên ta khai báo mảng sau.

for( int i=0; i<max ; i++) { printf(“Name[%d]= “,i); scanf(“%s”,pChar[i]); }

#define max 100;char *pChar[max];

• Khai báo :

for( int i=0; i<max ; i++) { printf(“Name[%d]=%s“,pChar[i]); }

•Xuất

•Nhập

Page 27: Slide pointer sepro

27

Mảng động hai chiều

DataType **Matrix;int Rows, Columns;

• Khai báo:

• Cấp phát Rows dòng cho ma trận thực chất là mảng một chiều gồm Rows con trỏ kiểu DataType.

• Cấp phát cho mỗi dòng Columns phần tử

Matrix = (DataType**) calloc(Rows , sizeof(DataType*));

for (int i=0 ; i<Rows; i++)Matrix[i]=(DataType *) malloc(Columns*sizeof(DataType));

Khai báo và cấp phát

Page 28: Slide pointer sepro

28

Mảng động hai chiều

Sử dụng:typedef int DataType;void Nhap(DataType **M,int r,int c){ int i,j; for ( i=0 ; i<r ; i++) for ( j=0 ; j<c ; j++) {

printf("Nhap M[%d][%d]= ",i,j);scanf("%d",&M[i][j]);

// Hoặc *(M+i)+j }}

typedef int DataType;void Xuat(DataType **M,int r,int c){ int i,j; for ( i=0 ; i<r ; i++) for ( j=0 ; j<c ; j++) {

printf(“M[%d][%d] = %d ", i,j,M[i][j]); // Hoặc *(*(M+i)+j) }}

Page 29: Slide pointer sepro

29

Mảng động hai chiều

Hủy:

for ( i=0 ; i<Rows ; i++) free (Matrix[i]);

• Giải phóng từng dòng một

free (Matrix);

• Giải phóng Matrix

Page 30: Slide pointer sepro

30

Con trỏ hàmKhái niệm– Hàm cũng đuợc lưu trữ trong bộ nhớ, tức là cũng

có địa chỉ.– Con trỏ hàm là con trỏ trỏ đến vùng nhớ chứa

hàm và có thể gọi hàm thông qua con trỏ đó.

……

0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17

p int Cong(int, int)

11 00 00 00

Page 31: Slide pointer sepro

31

Con trỏ hàm

Khai báo tường minh<kiểu trả về> (* <tên biến con trỏ>)(ds tham số);

Ví dụ

typedef <kiểu trả về> (* <tên con trỏ hàm>)(ds tham số);<tên con trỏ hàm> <tên biến con trỏ>;

int (*pt1)(int, int); // Tường minh

typedef int (*PhepToan)(int, int);

PhepToan pt2, pt3; // Không tường minh

Khai báo không tường minh – bằng typedef

Page 32: Slide pointer sepro

32

Con trỏ hàm

Gán giá trị cho con trỏ hàm

Hàm được gán phải cùng dạng (ds tham số)Ví dụ

<biến con trỏ hàm> = <tên hàm>; // Dạng ngắn gọn<biến con trỏ hàm> = &<tên hàm>; // Dạng sử dụng địa chỉ

int Cong( int x, int y); // Hàmint Tru( int x, int y); // Hàmint (*tinhtoan)(int x, int y);// Con trỏ hàm

tinhtoan = Cong; // Dạng ngắn gọntinhtoan = &Tru; // Dạng sử dụng địa chỉtinhtoan = NULL; // Không trỏ đến đâu cả

Page 33: Slide pointer sepro

33

C. “ Giải bài tập C bằng con trỏ ”

Câu nói nào sau đây là đúng !

Thu hoạch

A. “ Dùng con trỏ để giải bài A”

B. “ Giải bài tập B sử dụng con trỏ”

Page 34: Slide pointer sepro

34

Tài liệu tham khảo

• Kĩ thuật lập trình – Đặng Bình Phương – Khoa Công nghệ thông tin - ĐH KHTN.

• Everything you need to know about pointers in C- Version 1.3 - Copyright 2005–2010 Peter Hosey.

• Understanding Pointers In C By Yashwant Kanetkar.