Slide pointer sepro

1,045 views

Published on

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

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,045
On SlideShare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
34
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Slide pointer sepro

  1. 1. ĐẠI HỌC CÔNG NGHỆ THÔNG TIN - ĐHQG Tp HCM – SE05 CON TRỎ TRONG NGÔN NGỮ C/C++ SE-PRO GROUP 1
  2. 2. NỘI DUNG:  DẪN NHẬP  CON TRỎ CƠ BẢN  CON TRỎ NÂNG CAO TÀI LIỆU THAM KHẢO 2
  3. 3. DẪN NHẬP Byte 2n Memory (RAM) Win n bit thì Hệ điều hành n bits RAM tối đa 2n byte Code data stack Con trỏ chỉ là một biến kiểu int lưu địa chỉ Byte 0 của biến khác Process Hệ điều program hành nạp code Process lên RAM data *.exe để thực thi quản lý theo stack địa chỉ 3
  4. 4. Con trỏ cơ bản1 Khai báo và cách sử dụng2 Các cách truyền đối số cho hàm3 Con trỏ và mảng một chiều4 Con trỏ và cấu trúc 4
  5. 5. Khai báo con trỏ và cách sử dụng• 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ỏ>; Ví dụ: int a = 5; int *ptr; ptr = &a; a ptr  Tên : a Tên : ptr  Giá tri mà biến lưu Giá trị mà biến lưu trữ : 5 trữ : 1025  Địa chỉ lưu trong  Địa chỉ lưu trong bộ nhớ: 1025(giả bộ nhớ: 5000(giả định) định) 5
  6. 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ỏ>;• Ví dụ: typedef int *pInt; int *p1; pInt p2, p3;Chý ý: • 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. 6
  7. 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. int n; int *p1 = &n; int *p2; // Trỏ đến vùng nhớ kiểu int một cách ngẫu int *p3 = NULL;nhiên p2 NULL Chú ý:  *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. 7
  8. 8. Cách truyền đối số cho hàm• Truyền địa chỉ (con trỏ) 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; } 8
  9. 9. Con trỏ và mảng một chiều• Mảng một chiều int Array[3]; – 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ảng Array == &Array[0] 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 … … Array 9
  10. 10. Con trỏ và mảng một chiều• Con trỏ đến mảng một chiều int Array[3], *pArray; pArray = Array; // Cách 1 pArray = &Array[0]; // Cách 2 18 19 1A 1B 1C 1D 1E 1F … 0B 00 00 00 … pArray 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 … … Array 10
  11. 11. Con trỏ và mảng một chiều Các phép toán số học trên con trỏ• 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 ++ p = Array +2 +1 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 … … int Array[3] 11
  12. 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] –2 –1 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 … … int Array[3] 12
  13. 13. Con trỏ và mảng một chiều// Nhập mảng // Xuất mảngvoid main() void main(){ { int a[10], n = 10, *pa; int a[10], n = 10, *pa; pa = a; // hoặc pa = &a[0]; pa = a; // hoặc pa = &a[0]; for (int i = 0; i<n; i++) for (int i = 0; i<n; i++) scanf(“%d”, &a[i]); printf(“%d”, a[i]); // scanf(“%d”, &pa[i]); // printf(“%d”, pa[i]); // scanf(“%d”, a + i); // printf(“%d”, *(a + i)); // scanf(“%d”, pa + i); // printf(“%d”, *(pa + i)); // scanf(“%d”, a++); // printf(“%d”, *(a++); // scanf(“%d”, pa++); // printf(“%d”, *(pa++));} } &a[i]  (a + i)  a[i]  *(a + i)  (pa + i)  &pa[i]  *(pa + i)  pa[i] 13
  14. 14. Con trỏ và mảng một chiều Đối số mảng truyền cho hàm 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 không phải hằng con trỏ. 14
  15. 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: * / % 15
  16. 16. Con trỏ và cấu trúcTruy xuất bằng 2 cách <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ụ 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; 16
  17. 17. Bài tập con trỏ cơ bảnBài 1: Cho đoạn chương trình sau: float pay; float *ptr_pay; pay=2313.54; ptr_pay = &pay;  Hãy cho biết giá trị của: a. pay b. *ptr_pay c. *pay d. &pay 17
  18. 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; Con trỏ x chưa được khởi *x += y++; tạo printf("%d %d", *x, y); getch(); } 18
  19. 19. Bài tập con trỏ cơ bản• Bài tập 3: Cho biết giá trị xuất ra #include <stdio.h> #include <conio.h> Output: ??? void main() { int x=25; int *ptr=&x; int **temp=&ptr; printf(“%d %d %d”,x,*ptr,**temp); }
  20. 20. Bài tập con trỏ cơ bản• Bài 4: Cho đoạn chương trình: #include <stdio.h> Output: ??? #include <conio.h> void main() { int *ptr=( int *)1000; ptr=ptr+1; printf(" %u",ptr); }
  21. 21. Bài tập con trỏ cơ bản• Bài 5: Cho đoạn chương trình: #include <stdio.h> Output: ??? #include <conio.h> void main() { double *p=( double *)1000; p=p+3; printf(" %u",p); }
  22. 22. 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> Output: ??? 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; }
  23. 23. Con trỏ nâng cao1 Cấp phát động2 Mảng con trỏ3 Mảng động hai chiều4 Con trỏ hàm 23
  24. 24. Cấp phát độngĐể cấp phất động chúng ta sử dụng thư viện <stdlib.h>  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. void *malloc( size ); Số byte cần cấp phát  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. Kích thước một khối nhớ void *calloc( num, size ); Số lượng khối nhớ cần cấp phát 24
  25. 25. Cấp phát độngVí dụ:  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*) malloc ( sizeof(double) ); Tương tự với calloc 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) ); 25
  26. 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. • Khai báo : •Nhập #define max 100; for( int i=0; i<max ; i++) char *pChar[max]; { printf(“Name*%d+= “,i); •Xuất scanf(“%s”,pChar[i]); for( int i=0; i<max ; i++) } { printf(“Name*%d+=%s“,pChar[i]); } 26
  27. 27. Mảng động hai chiềuKhai báo và cấp phát • Khai báo: DataType **Matrix; int Rows, Columns; • 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. Matrix = (DataType**) calloc(Rows , sizeof(DataType*)); • Cấp phát cho mỗi dòng Columns phần tử for (int i=0 ; i<Rows; i++) Matrix[i]=(DataType *) malloc(Columns*sizeof(DataType)); 27
  28. 28. Mảng động hai chiều Sử dụng:typedef int DataType; typedef int DataType;void Nhap(DataType **M,int r,int c) void Xuat(DataType **M,int r,int c){ { int i,j; int i,j; for ( i=0 ; i<r ; i++) for ( i=0 ; i<r ; i++) for ( j=0 ; j<c ; j++) for ( j=0 ; j<c ; j++) { { printf("Nhap M[%d][%d]= ",i,j); scanf("%d",&M[i][j]); printf(“M*%d+*%d+ = %d ", i,j,M[i][j]); // Hoặc *(M+i)+j // Hoặc *(*(M+i)+j) } }} } 28
  29. 29. Mảng động hai chiều Hủy: • Giải phóng từng dòng một for ( i=0 ; i<Rows ; i++) free (Matrix[i]); • Giải phóng Matrix free (Matrix); 29
  30. 30. Con trỏ hàmKhá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 … 11 00 00 00 … p int Cong(int, int) 30
  31. 31. Con trỏ hàmKhai báo tường minh <kiểu trả về> (* <tên biến con trỏ>)(ds tham số); Khai báo không tường minh – bằng typedef 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ỏ>;Ví dụ int (*pt1)(int, int); // Tường minh typedef int (*PhepToan)(int, int); PhepToan pt2, pt3; // Không tường minh 31
  32. 32. Con trỏ hàmGán giá trị cho con trỏ hàm <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ỉ Hàm được gán phải cùng dạng (ds tham số)Ví dụ int Cong( int x, int y); // Hàm int Tru( int x, int y); // Hàm int (*tinhtoan)(int x, int y); // Con trỏ hàm tinhtoan = Cong; // Dạng ngắn gọn tinhtoan = &Tru; // Dạng sử dụng địa chỉ tinhtoan = NULL; // Không trỏ đến đâu cả 32
  33. 33. Thu hoạch Câu nói nào sau đây là đúng ! A. “ Dùng con trỏ để giải bài A” B. “ Giải bài tập B sử dụng con trỏ” C. “ Giải bài tập C bằng con trỏ ” 33
  34. 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. 34

×