Tài liệu Kỹ thuật lập trình - Bài 7: Kiểu con trỏ - Ngô Hữu Dũng: Kỹ thuật lập trình
Bài 7 – Kiểu con trỏ
TS. Ngô Hữu Dũng
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017181
Khái niệm con trỏ (pointer)
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017182
 Con trỏ là biến mà giá trị của nó là địa chỉ bộ nhớ
 Địa chỉ bộ nhớ?
 scanf(“%d”,&i); // &i là địa chỉ bộ nhớ của biến i
 Khai báo
 type * variable_name;
 Con trỏ lưu địa chỉ bộ nhớ
 int i = 20;
 int * p; // Khai báo con trỏ p 
 p = &i; // Con trỏ p được gán bằng địa chỉ của biến i
 Ta nói con trỏ p “trỏ vào” biến i
i = 20
Biến Địa chỉ Giá trị
i 0073FB60 20
p 0073FB54 0073FB60
p = 0073FB60
Con trỏ và địa chỉ
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017183
1. int x; // Biến số nguyên x
2. int *p; // Con trỏ p kiểu số nguyên
3. p = &x; // p trỏ vào x
4. x = 20;
5. printf("%d ", x); // Giá trị của x
6. printf("%d ", *p); // Giá trị của x
7. printf("%p ", &x); // Địa chỉ của x
8. printf("%p ", p); // Địa chỉ của x
9. *p = 40;
10...
                
              
                                            
                                
            
 
            
                 30 trang
30 trang | 
Chia sẻ: putihuynh11 | Lượt xem: 648 | Lượt tải: 0 
              
            Bạn đang xem trước 20 trang mẫu tài liệu Kỹ thuật lập trình - Bài 7: Kiểu con trỏ - Ngô Hữu Dũng, để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên
Kỹ thuật lập trình
Bài 7 – Kiểu con trỏ
TS. Ngô Hữu Dũng
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017181
Khái niệm con trỏ (pointer)
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017182
 Con trỏ là biến mà giá trị của nó là địa chỉ bộ nhớ
 Địa chỉ bộ nhớ?
 scanf(“%d”,&i); // &i là địa chỉ bộ nhớ của biến i
 Khai báo
 type * variable_name;
 Con trỏ lưu địa chỉ bộ nhớ
 int i = 20;
 int * p; // Khai báo con trỏ p 
 p = &i; // Con trỏ p được gán bằng địa chỉ của biến i
 Ta nói con trỏ p “trỏ vào” biến i
i = 20
Biến Địa chỉ Giá trị
i 0073FB60 20
p 0073FB54 0073FB60
p = 0073FB60
Con trỏ và địa chỉ
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017183
1. int x; // Biến số nguyên x
2. int *p; // Con trỏ p kiểu số nguyên
3. p = &x; // p trỏ vào x
4. x = 20;
5. printf("%d ", x); // Giá trị của x
6. printf("%d ", *p); // Giá trị của x
7. printf("%p ", &x); // Địa chỉ của x
8. printf("%p ", p); // Địa chỉ của x
9. *p = 40;
10.printf("Gia tri: %d = %d" , *p, x);
11.printf("Dia chi: %p = %p" , p, &x);
Kiểu con trỏ
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017184
 Khai báo: Dùng dấu *
 int *p;
 Địa chỉ của biến mà con trỏ trỏ vào
 p = &x
 Giá trị của biến mà con trỏ trỏ vào: Dùng dấu *
 *p = x
 In ra màn hình địa chỉ: Dùng %p
 printf(“%p = %p”, p, &x);
 Chú ý: Phân biệt các dấu * và các dấu &
Sử dụng con trỏ
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017185
 Chưa trỏ vào biến
 int *p;
 *p = 40; // Run-time error!
 Trỏ vào biến
 int x, *p1, *p2;
 p1 = &x; // Trỏ p1 vào biến x
 *p1 = 40; // x = 40;
 p2 = p1; // gán trực tiếp, tương đương với p2 = &x;
 *p2 = 50; // x = 50; 
 *p1 = 60; // x = 60;
Ví dụ vận dụng
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017186
1. int x, y, *px, *py=NULL;
2. px = &x; // px trỏ vào x
3. py = &y; // py trỏ vào y
4. *px = 10;
5. y = 15;
6. printf("x=%d\ny=%d\n",*px,*py);
7. (*px)++; ++*px;
8. *py += 5;
9. printf("x=%d\ny=%d\n",*px,*py);
10.printf("%d+%d=%d\n",x,y,*px + *py);
11.printf("%d*%d=%d\n",x,y,*px * *py);
12.printf("&x=%p\n&y=%p\n",px,py);
Phạm vi ứng dụng con trỏ
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017187
 Con trỏ có thể trỏ vào bất kỳ dữ liệu nào
 Một kiểu nguyên thủy: int, float, char
 NULL (rỗng, không trỏ đến đâu)
 Một hằng số
 Một đối số của hàm
 Một mảng/chuỗi
 Một cấu trúc struct
 Một hàm
 Một con trỏ khác (con trỏ trỏ vào con trỏ)
 Một ô nhớ cấp phát động
 Một tập tin
Lợi hại của con trỏ
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017188
 Có thể dùng để thao tác với bất kỳ loại dữ liệu nào
 Thuật lợi để truy cập đến cấu trúc dữ liệu lớn
 Sử dụng bộ nhớ linh hoạt
 Cấp phát / giải phóng bộ nhớ động trong quá trình thực thi
 Cấp phát bộ nhớ mới: Hàm malloc trong stdlib.h
 Giải phóng bộ nhớ: Hàm free trong stdlib.h
 Nếu sử dụng con trỏ không cẩn thận
 Dễ nhầm lẫn
 Khó tìm lỗi
Kiểu nguyên thủy
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017189
1. // Con trỏ có thể trỏ vào các kiểu nguyên thủy
2. int i = 10, *pi;
3. float f = 1.2e2, *pf;
4. char c = 'r', *pc;
5. pi = &i;
6. pf = &f;
7. pc = &c;
8. printf("%d,%f,%c\n",*pi,*pf,*pc);
9. // Chú ý dùng đúng kiểu dữ liệu
10.pc = &f; // Warning!
11.pf = &i; // Warning!
12.pi = &c; // Warning!
Con trỏ rỗng - NULL
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017190
 NULL là giá trị đặc biệt của con trỏ
 Không trỏ đến đâu
 #define NULL 0
 Được định nghĩa trong thư viện stdio.h
 Sử dụng
 Khởi tạo con trỏ: int *p = NULL;
 Kiểm tra một con trỏ
 if (p != NULL) printf(“%d”,*p);
 if (p) printf(“%d”, *p);
 Kết thúc một danh sách dữ liệu
Con trỏ và hằng số
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017191
 Con trỏ trỏ vào hằng số
 int m, n;
 const int *ip = &m;
 ip = &n; // OK! Có thể thay đổi giá trị con trỏ
 *ip = 10; // ERROR !!! Không thể thay đổi giá trị của biến
 Con trỏ là hằng số: Chỉ trỏ vào một biến
 int m, n;
 int * const cip = &m;
 *cip = 10; // OK! Có thể thay đổi giá trị của biến
 cip = &n; // ERROR !!! Không thể thay đổi giá trị con trỏ
Con trỏ và đối số của hàm
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017192
1. void swap (int *px, int *py) // Tham biến
2. {
3. int temp = *px; // Dùng dấu *
4. *px = *py; // để truy cập giá trị
5. *py = temp;
6. }
7. int a = 5, b = 7;
8. swap(&a, &b); // Truyền địa chỉ của biến
9. printf("a = %d, b = %d", a, b);
Con trỏ và mảng
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017193
 Con trỏ có thể trỏ vào một mảng
 #define N 7
 int a[N], b[N];
 int *pa, *pb;
 pa = a;
 pb = &b[0];
 int *pc;
 pc = &b[5];
 pa = a; // Mặc định trỏ vào phần tử đầu tiên của mảng, a[0]
a[0] a[1] a[2] a[3] a[4] a[5] a[6]
pa
b[0] b[1] b[2] b[3] b[4] b[5] b[6]
pb pc
Con trỏ và phần tử của mảng
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017194
 Địa chỉ của phần tử thứ i
 pa + i = &a[i]
 Giá trị của phần tử thứ i
 *(pa + i) = pa[i] = a[i]
 Ví dụ
 *pa = 1;
 *(pa+1) = 2;
 pa[2] = 3;
 *pb = 4;
 *(pc-1) = 5;
 *pc = 6;
a[0] a[1] a[2] a[3] a[4] a[5] a[6]
1 2 3
pa
b[0] b[1] b[2] b[3] b[4] b[5] b[6]
4 5 6
pb pc
pa+1
pc-1
Ví dụ vận dụng
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017195
1. #define N 10
2. int a[N];
3. int i, *pa, *pt;
4. pa = a; //Trỏ vào mảng, không dùng &
5. for (i=0;i<N;i++)
6. *(pa+i)=i; // *(pa+i)=a[i]
7. for (pt=pa;pt<pa+N;pt++)
8. printf("%d ",*pt); // *pt=a[i]
9. for (i=0;i<N;i++)
10. printf("%d ",pa[i]); // pa[i]=a[i]
Mảng là con trỏ hằng số (constant pointer)
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017196
 Mảng là con trỏ hằng số
 int a[10];
 int *pa;
 pa = a; // a là con trỏ, pa có thể được gán cho a, không cần &a
 pa++; // Con trỏ pa có thể thay đổi giá trị
 a = pa; // ERROR! a là hằng số
 a++; // ERROR! a là hằng số
 Mảng a là con trỏ trỏ vào phần tử đầu tiên của mảng và không
thể thay đổi giá trị địa chỉ
Truyền đối số là mảng / chuỗi
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017197
 Truyền đối số là một mảng vào một hàm
 void sapxep(int a[], int n)
 Địa chỉ của phần tử đầu tiên của mảng được truyền: &a[0]
 Có thể thay thế bằng con trỏ
 void sapxep(int *a, int n)
 Tương tự với chuỗi
 Tham số function(char s[]){} và function(char *s){} là tương
đương
Ví dụ truyền đối số là mảng/chuỗi
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017198
1. int printArray(int *pa, int n)
2. {
3. int *pt;
4. for (pt=pa;pt<pa+n;pt++) //gán, so sánh, tăng
5. printf("%d ",*pt);
6. } 
7. int stringLength(char *s)
8. {
9. if(*s=='\0')
10. return 0;
11. else
12. return 1 + stringLength(++s);
13. }
Các phép toán của con trỏ
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017199
 Phép gán hai con trỏ cùng kiểu dữ liệu
 int a, *pa, *pb; pa=&a; pb = pa;
 Cộng/trừ con trỏ với số nguyên
 Tăng/giảm giá trị của con trỏ theo sizeof()
 Ví dụ: pb+n tăng giá trị của p lên n x sizeof(int)
 So sánh giữa hai con trỏ trỏ vào phần tử trong cùng một mảng
 Các phép toán ==, !=, >, =, <=
 Phép trừ giữa hai con trỏ trỏ vào phần tử trong cùng một mảng
 Gán hoặc so sánh với NULL (zero)
Ví dụ về các phép toán của con trỏ
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017200
1. int printRevertArray(int *pa, int n)
2. {
3. int *pt = pa+n-1; // Cộng số tự nhiên
4. while (pt>=pa) // Phép so sánh
5. {
6. printf("%d ",*pt); pt--; // Phép toán giảm
7. }
8. }
9. int stringLength(char *s)
10. {
11. char *p = s; // Phép gán
12. while (*p!='\0') 
13. p++; // Phép toán tăng
14. return p - s; // Phép trừ của con trỏ
15. }
Con trỏ và chuỗi
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017201
 Tương tự như với mảng nhưng chuỗi có một đặc điểm khác
 Chuỗi kết thúc bằng ký tự rỗng, ‘\0’
1. void stringCopy(char *s, char *t)
2. {
3. while (*t != '\0') 
4. {
5. *s = *t;
6. s++; 
7. t++;
8. }
9. *s = '\0'; // Ký tự rỗng kết thúc chuỗi
10. }
Con trỏ và chuỗi (tt)
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017202
1. void stringCopy1(char *s, char *t)
2. {
3. while ((*s = *t) != '\0'){ //Gán, so sánh
4. s++; t++; // Tăng
5. }
6. }
7. void stringCopy2(char *s, char *t)
8. {
9. while ((*s++ = *t++) != '\0');//Gán, so sánh, tăng
10. }
11. void stringCopy3(char *s, char *t)
12. {
13. while (*s++ = *t++); // Gán, tăng
14. }
Con trỏ và cấu trúc
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017203
1. struct t_date{
2. int day;
3. int month;
4. int year;
5. };
6. struct t_date today; // Biến cấu trúc
7. struct t_date *ptr; // Con trỏ kiểu cấu trúc
8. ptr = &today; // Trỏ vào cấu trúc
9. (*ptr).day = 15; // Truy cập member, cách 1
10. (*ptr).month = 9; // Dùng dấu ‘.’
11. (*ptr).year = 2016;
12. ptr->day = 15; // Truy cập member, cách 2
13. ptr->month = 9; // Dùng dấu ‘->’
14. ptr->year = 2016;
Con trỏ và cấu trúc (2)
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017204
1. struct t_student{
2. int ID;
3. char *ten;
4. struct t_date birth, *pB;
5. };
6. struct t_student SV, *pSV;
7. pSV = &SV; // Trỏ vào cấu trúc t_stu
8. pSV->ID = 123; // SV.ID
9. pSV->ten = "Nguyen Van A";// SV.ten
10. pSV->birth.day = 16; // SV.birth.day
11. pSV->pB = &SV.birth; // Trỏ vào cấu trúc t_date
12. pSV->pB->month = 4; // SV.birth.month
13. (*pSV->pB).year = 1996; // SV.birth.year
Con trỏ và cấu trúc (3)
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017205
1. ++pSV->ID; // Tăng giá trị ID
2. printf("%d ",pSV->ID);
3. printf("%c",*pSV->ten); //Ký tự đầu tiên ‘N’
4. printf("%c",pSV->ten[1]); //Ký tự thứ 2 ‘g’
5. printf("%s ",pSV->ten+2); //Từ ký tự ‘u’->hết
6. printf("%d ",++pSV->pB->day); //Tăng day
7. printf("%d ",(*pSV->pB).month);
8. printf("%d\n",SV.pB->year);
9. while(*pSV->ten!='\0')
10. printf("%c",*pSV->ten++);
11.printf("\n%s",pSV->ten); // !? Chuỗi rỗng !?
12.printf("%s",--pSV->ten); // !?
Con trỏ và hàm
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017206
 Hàm có thể trả về kiểu con trỏ
 Đối số kiểu con trỏ
1. char * stringCopy4(char *s, char *t)
2. {
3. int count = 0;
4. do 
5. count++;
6. while (*s++ = *t++);
7. return s-count;
8. }
Con trỏ đến con trỏ
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017207
 Con trỏ có thể chứa địa chỉ của con trỏ khác
 char x;
 char * y;
 char ** z;
 x = 'x';
 y = &x;
 z = &y;
'x' 00AFF75F00000078
x x x
00000078 00AFF75F 00AFF750
Con trỏ và cấp phát động
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017208
 Con trỏ có thể được cấp phát bộ nhớ
 Trỏ trực tiếp vào bộ nhớ động
 Không cần thông qua một biến cụ thể
1. #include 
2. int n ,*a , i;
3. scanf("%d", &n);
4. a =(int*)malloc(sizeof(int)*n); // Cấp phát bộ nhớ
5. for(i=0;i<n;i++)
6. a[i]=i;
7. for (i=0;i<n;i++)
8. printf("%d\n",a[i]);
9. free(a); // Giải phóng bộ nhớ
Con trỏ và tập tin
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017209
 Con trỏ có thể trỏ vào tập tin
1. #include <
2. FILE * pFile;
3. pFile = fopen ("myfile.txt","w");
4. if (pFile!=NULL)
5. {
6. fputs ("fopen example",pFile);
7. fclose (pFile);
8. }
9. return 0;
Hết bài 7
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017210
 Khái niệm con trỏ
 Khái quát các ứng dụng của con trỏ
 Kiểu nguyên thủy: int, float, char
 NULL (rỗng, không trỏ đến đâu)
 Hằng số
 Đối số của hàm
 Mảng/chuỗi
 Cấu trúc struct
 Hàm
 Con trỏ trỏ vào con trỏ
 Cấp phát động
 Tập tin
            Các file đính kèm theo tài liệu này:
 bai_giang_ky_thuat_lap_trinh_ts_ngo_huu_dung_ky_thuat_lap_trinh_ngo_huu_dung_bai_07_1973_1985332.pdf bai_giang_ky_thuat_lap_trinh_ts_ngo_huu_dung_ky_thuat_lap_trinh_ngo_huu_dung_bai_07_1973_1985332.pdf