slide pointer sepro

Post on 22-Jun-2015

824 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

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

TRANSCRIPT

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Ạ Ọ Ệ

2

NỘI DUNG:

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

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

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

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)

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ý ý:

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ú ý:

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;}

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

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

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

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]

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]

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ỏ.

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: * / %

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ụ

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

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

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);

}

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: ???

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: ???

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: ???

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

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.

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

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

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

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) }}

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

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

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

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ả

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ỏ”

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.

top related