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 |
Chia sẻ: putihuynh11 | Lượt xem: 488 | 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