SlideShare a Scribd company logo
1 of 22
TRƯỜNG ĐẠI HỌC CÔNG NGHỆ THÔNG TIN
LIÊN CHI ĐOÀN MMT&TT
HỖ TRỢ K7
Môn: Nhập môn lập trình
Con trỏ, các vấn đề liên quan con
trỏ
 ĐỊA CHỈ CỦA BIẾN
• Khái niệm: Địa chỉ của biến là số thứ tự
của byte đầu tiên trong một dãy các byte
liên tiếp mà máy dành cho biến.
• Phân loại địa chỉ biến: địa chỉ kiểu int,
float, double, …
• Lấy địa chỉ của một biến: sử dụng toán
tử &.
Ví dụ:
int x = 5;
 x được cấp phát vùng nhớ có kích thước 4
byte liên tiếp. Giả sử tại địa chỉ 1050, ta
có:
 Địa chỉ của x: &x = 1050, giá trị của x = 5.
5
……
……
1050 x
1053
 KHÁI NIỆM BIẾN CON TRỎ
Con trỏ là kiểu dữ liệu mà một thành phần kiểu
này có thể lưu trữ địa chỉ của một thành phần nào
đó (có thể là biến, hằng, hàm), hoặc ta nói nó trỏ
tới thành phần đó.
 PHÂN LOẠI CON TRỎ
Một con trỏ lưu trữ địa chỉ của một thành kiểu T
thì ta nói p là con trỏ kiểu T, đặc biệt nếu T là một
kiểu con trỏ, hay nói cách khác, p lưu trữ địa chỉ
của một con trỏ khác thì ta nói p là con trỏ trỏ tới
con trỏ.
Cú pháp khai báo con trỏ:
<kiểu dữ liệu> * <tên_con_trỏ>;
Ví dụ:
int *p; // p là con trỏ kiểu int
float * q ; // q là con trỏ kiểu float
char *s ; // s là con trỏ kiểu char hay xâu kí tự
int ** r; // r là con trỏ tới con trỏ kiểu int
Ví dụ:
int *p, *q;
int x = 5;
// gán đ/c biến x cho con trỏ p
p = &x;
// lưu đ/c trong p vào con trỏ q
q = p;
Giả sử địa chỉ của x là 1010 thì p = 1010 và
q = 1010
5
1010
1010
……
……
1010 x
1014
1016
p
q
 Khi giá trị nằm trong p là địa chỉ của a thì ta
nói p trỏ vào a.
 Lúc này thì *p hoàn toàn tương đương với a ,
người ta coi *p là bí danh của a , thao tác với
*p cũng như thao tác với a, thao tác với a
cũng như thao tác với *p.
Ví dụ:
Câu lệnh x=2; hoàn toàn tương đương với câu lệnh *p=2
Câu lệnh x++; hoàn toàn tương đương với (*p)++ // chú ý
khác với *p++ nhé, phải cho *p vào trong đóng mở ngoặc vì
toán tử * có độ ưu tiên thấp hơn ++.
 Lúc này câu lệnh scanf("%d",&a); ta có thể
thay bằng scanf("%d",p);
Để xuất một địa chỉ ô nhớ ra màn hình ta sử
dụng mã định dạng %p.
Ví dụ:
#include <stdio.h>
#include <conio.h>
void main()
{
int a;
int *p;
printf("n Dia chi bien a:%p",&a);
p = &a;
printf("n Dia chi con tro p chua la:
%p", p);
}
Các phép toán trên con trỏ
Phép gán:
• Tất cả các loại con trỏ đều có phép gán.
• Phép gán với con trỏ yêu cầu vế trái là 1 con trỏ và vế phải là 1
địa chỉ.
• Phép gán yêu cầu sự tương xứng về kiểu dữ liệu, nếu ko
tương xứng chúng ta phải ép kiểu.
Ví dụ:
p=(int*)8232;
p có kiểu dữ liệu là int*
còn 8232 là 1 hằng số nguyên, nên phải ép kiểu về int* rồi thực
hiện phép gán.
• Phép gán với 1 con trỏ kiểu void ko cần thiết phải tương
xứng hoản toàn về kiểu dữ liệu, void* có thể tương ứng
với tất cả thậm chí là vượt cấp (vượt hẳn 2 cấp).
Ví dụ:
void *p,**q;
p=&q;
 Phép so sánh
• Phép so sánh ngang bằng dùng để kiểm tra 2 con trỏ
có trỏ vào cùng 1 vùng nhớ hay không, hoặc kiểm tra 1
con trỏ có phải là đang trỏ vào NULL hay không (trong
trường hợp cấp phát động, mở file, mở resource,........).
• Phép so sánh lớn hơn nhỏ hơn : > , < , >= , <= sử dụng
để kiểm tra về độ thấp cao giữa 2 địa chỉ . Con trỏ nào
nhỏ hơn thì trỏ vào địa chỉ thấp hơn.
 Được quyền so sánh mọi con trỏ với 0, vì 0 chính là
NULL.
Ví dụ:
int a=197,*p=&a;
double *x;
p==&a;
p==0;
x==0;
Các phép toán trên con trỏ
 Khi so sánh 2 con trỏ hoặc con trỏ với 1 địa chỉ xác định
(số nguyên) cần có sự tương xứng về kiểu dữ liệu:
Ví dụ:
int a=197,*p=&a;
double b=0,*x=&b;
// so sánh 2 con trỏ
(int)p==(int)x;
p==(int *)x;
(double*)p==x;
(void*)p==(void*)x;
p==(void*)x;
(float*)p==(float*)x;
//so sánh con trỏ với số nguyên
p==(int*)9999;
int(p)==9999;
 Con trỏ void có thể đem ra so sánh với tất cả các con trỏ
khác.
Các phép toán trên con trỏ
 Phép cộng trừ và phép tăng giảm : +, +=, -, -=, ++, --
• Bản chất của việc tăng/ giảm con trỏ p đi 1 đơn vị là
cho p trỏ đến ô nhớ bên cạnh phía dưới/trên.
• Chú ý:
+ Khi tăng giảm con trỏ p đi 1 đơn vị không có nghĩa là
trỏ sang byte bên cạnh.
+ Việc tăng giảm con trỏ đi 1 đơn vị phụ thuộc vào kiểu
dữ liệu và nó trỏ đến, quy tắc là :
p+1 >>> giá trị chứa trong p + sizeof(kiểu dữ liệu của
biến mà p trỏ đến)
+ Không có phép tăng giảm trên con trỏ void.
+ Không có phép cộng 2 con trỏ với nhau.
+ Phép trừ 2 con trỏ trả về độ lệch pha giữa 2 con trỏ.
Các phép toán trên con trỏ
Con trỏ với mảng
 Khi ta khai báo mảng thì tương đương với : xin cấp
phát 1 vùng nhớ có kích thước như bạn khai báo và
khai báo ra 1 hằng con trỏ trỏ vào đầu vùng nhớ đó
Ví dụ:
int a[100]={0,1,2,3};
0
1
2
3
0
1000
1004
1008
1012
1016
a[0]
a[1]
a[0]
a[2]
a[3]
a[4]
 Chú ý : trình biên dịch luôn hiểu a[i] là *(a+i).
• a là 1 hằng con trỏ trỏ vào phần tử thứ 0 của mảng.
• các phép toán nhằm làm a trỏ tới vùng khác (thay đổi giá trị
của a) là không thể (++, --, = ).
• a tương đương với &a[0].
• a+i tương đương với &a[i].
• *a tương đương với a[0].
• *(a+i) tương đương với a[i].
Những con trỏ mà chỉ trỏ cố định vào 1
vùng nhớ , những con trỏ này không có khả
năng trỏ vào vùng nhớ khác, không thay đổi
được
Ví dụ:
char buf[] = "bonjour";
char * const p = buf;
p++; <<<<<<<<<<<<<<<<<<<<<<< báo
lỗi tại đây
p[4]++; <<<<<<<<<<<<<<<<<<<<<<<<< ko
vấn đề, hoàn toàn có thể thay đổi giá
trị vùng nhớ mà p trỏ đến
Hằng con trỏ là gì?
Con trỏ với mảng
int a[100]={0,1,2,3,4,5,6};
printf("%d",2[a]);
2[a] trình biên dịch sẽ hiểu là *(2+a)
*(2+a) hoàn toàn tương đương với *(a+2)
mà *(a+2) chính là a[2]
Vậy 2[a] cũng đơn giản là a[2]
Kết quả đoạn lệnh trên???
Con trỏ với mảng
Mảng 2 chiều
Cho khai báo 1 mảng 2 chiều:
int D[n][m]; // n, m là hằng nguyên
Tức là có n×m phần tử kiểu nguyên, như vậy D được cấp phát một
vùng nhớ liên tiếp, trong vùng đó có n vùng con cho n phần tử
(dòng), trong mỗi vùng con có m ô nhớ (mỗi ô là một phần tử). Hay
nói cách khác các phần tử của mảng được cấp phát liên tiếp, đầu tiên
là phần tử của hàng 0, sau đó là phần tử của hàng 1,...
1000
1004
...
1000 + m*i*4 + j*4
d[0][0]
d[0][1]
...
d[ i ][ j ]
d[n-1][m-1] 1000 + m*(n-1)*4 + (m-1)*4
Con trỏ với mảng
 Cấp phát: để cấp phát bộ nhớ cho một biến con trỏ ta
có thể sử dụng các hàm: malloc, calloc, realloc.
 Thu hồi: để thu hồi bộ nhớ đã cấp phát cho một biến con
trỏ ta dùng hàm free.
 Chú ý là :
• malloc trả về 1 địa chỉ đến 1 vùng nhớ và coi vùng nhớ
này là void *, nên trong câu lệnh malloc luôn đi kèm với
việc ép kiểu:
contro = (ép kiểu) malloc(...)
• Cấp phát là luôn phải đi kèm với giải phóng, ở đâu cũng
thế, malloc là phải free. Code mà để thoát chương trình
rồi chưa giải phóng cho dù là có hệ thống có tự giải
phóng đi nữa vẫn bị coi là bad!!!!
Cấp phát và thu hồi bộ nhớ
Vậy còn new và
delete?
 new và delete không phải là hàm mà là toán tử
nên không còn phải khai báo thư viện như
malloc (thư viện stdlib.h).
 new không có khả năng realloc.
Ví dụ:
int *x=new(int);
.....
delete x;
Con trỏ với hàm
int ham(int *a)
{
*a=2;
a++;
}
void main()
{
int *a;
printf("Truoc : %x",a); //trước và sau khi gọi hàm
ham(a); //con trỏ a trỏ vào đâu
printf("Sau %x",a); // thì nó vẫn trỏ vào đó
getch();
}
Hàm trong C ko hề có tham biến, hàm trong C đều
hoạt động theo nguyên tắc sau :
Khi gọi hàm, 1 bản sao của tham số được tạo ra và
hàm sẽ làm việc với bản sao này.
void nhap(int *a,int n)
{
a=(int*)malloc(n * sizeof(int)); //sai lầm
for(int i=0;i<n;i++)
scanf("%d", &a[i]);
}
void main()
{
int *x;
int n=6;
nhap(x,n);
//xuat
free(x); // sản sinh ra lỗi run-time do x chưa trỏ
vào đâu mà đòi giải phóng
}
Con trỏ với hàm
Dùng con trỏ cấp cao hơn con trỏ hiện tại
Ví dụ:
void ham(int **a)
{
*a=(int*)malloc(100*sizeof(int));
//a[0]=(int*)malloc(100*sizeof(int));
// 2 cach nay nhu nay
}
void main()
{
int *a;
ham(&a);
free(a);
}
Làm thế nào để mà thay đổi giá
trị của 1 con trỏ qua 1 hàm?
Con trỏ với hàm
Con trỏ với cấu trúc
Để truy xuất đến một thành phần của biến con
trỏ cấu trúc ta sử dụng toán tử mũi tên (->)
Ví dụ:
typedef struct tagNode
{
int info;
struct tagNode* pNext;
}NODE;
NODE* tao_pt(int x)
{
NODE* p=new NODE;
if(p==NULL) {
printf("Khong du bo nho");
return p;
}
p->info=x;
p->pNext=NULL;
return p;
}

More Related Content

What's hot (18)

Phong cach lap trinh c++
Phong cach lap trinh c++Phong cach lap trinh c++
Phong cach lap trinh c++
 
Session 13
Session 13Session 13
Session 13
 
Nmlt c09 chuoi_kytu
Nmlt c09 chuoi_kytuNmlt c09 chuoi_kytu
Nmlt c09 chuoi_kytu
 
Bai giangtrenlop
Bai giangtrenlopBai giangtrenlop
Bai giangtrenlop
 
Ctdl C05
Ctdl C05Ctdl C05
Ctdl C05
 
Huong danontapc
Huong danontapcHuong danontapc
Huong danontapc
 
3 Function
3 Function3 Function
3 Function
 
Phan2 chuong5 ctrinhcon
Phan2 chuong5 ctrinhconPhan2 chuong5 ctrinhcon
Phan2 chuong5 ctrinhcon
 
Slide pointer sepro
Slide pointer seproSlide pointer sepro
Slide pointer sepro
 
Giao trinh bai tap c va c++
Giao trinh bai tap c va c++Giao trinh bai tap c va c++
Giao trinh bai tap c va c++
 
Bai 17
Bai 17Bai 17
Bai 17
 
Nmlt c11 con_trocoban-
Nmlt c11 con_trocoban-Nmlt c11 con_trocoban-
Nmlt c11 con_trocoban-
 
Ctdl C01
Ctdl C01Ctdl C01
Ctdl C01
 
Huong dan su dung va debug voi dev c++
Huong dan su dung va debug voi dev c++Huong dan su dung va debug voi dev c++
Huong dan su dung va debug voi dev c++
 
Lập trình C cơ bản cho vi điều khiển
Lập trình C cơ bản cho vi điều khiểnLập trình C cơ bản cho vi điều khiển
Lập trình C cơ bản cho vi điều khiển
 
Các cấu trúc lệnh trong C
Các cấu trúc lệnh trong CCác cấu trúc lệnh trong C
Các cấu trúc lệnh trong C
 
Giáo trình c++ full tiếng việt
Giáo trình c++ full tiếng việtGiáo trình c++ full tiếng việt
Giáo trình c++ full tiếng việt
 
Ctdl C02
Ctdl C02Ctdl C02
Ctdl C02
 

Similar to Pointer

giao trinh c++ Chuong1
giao trinh c++ Chuong1giao trinh c++ Chuong1
giao trinh c++ Chuong1
Bễ Nguyễn
 
Lua introduction Gioi thieu ve Lua
Lua introduction Gioi thieu ve LuaLua introduction Gioi thieu ve Lua
Lua introduction Gioi thieu ve Lua
Da Mi
 

Similar to Pointer (20)

Session 13
Session 13Session 13
Session 13
 
Pointer vn
Pointer vnPointer vn
Pointer vn
 
Chuong 2
Chuong 2Chuong 2
Chuong 2
 
Group 14_pointer_beta2.pptx
Group 14_pointer_beta2.pptxGroup 14_pointer_beta2.pptx
Group 14_pointer_beta2.pptx
 
Tu-Hoc-Python-Co-Ban-Trong-10-Phut-NIIT
Tu-Hoc-Python-Co-Ban-Trong-10-Phut-NIITTu-Hoc-Python-Co-Ban-Trong-10-Phut-NIIT
Tu-Hoc-Python-Co-Ban-Trong-10-Phut-NIIT
 
Thdc3 Lap Trinh C
Thdc3 Lap Trinh CThdc3 Lap Trinh C
Thdc3 Lap Trinh C
 
Ngôn ngữ lập trình pascal (bổ trợ tin 11)
Ngôn ngữ lập trình pascal (bổ trợ tin 11)Ngôn ngữ lập trình pascal (bổ trợ tin 11)
Ngôn ngữ lập trình pascal (bổ trợ tin 11)
 
ưU tiên trong c
ưU tiên trong cưU tiên trong c
ưU tiên trong c
 
Giới thiệu ngôn ngữ lập trình C++
Giới thiệu ngôn ngữ lập trình C++Giới thiệu ngôn ngữ lập trình C++
Giới thiệu ngôn ngữ lập trình C++
 
Session 4
Session 4Session 4
Session 4
 
Lec3. Ham.pdf
Lec3. Ham.pdfLec3. Ham.pdf
Lec3. Ham.pdf
 
344444
344444344444
344444
 
Chuong1 c
Chuong1 c Chuong1 c
Chuong1 c
 
Con trỏ trong C
Con trỏ trong CCon trỏ trong C
Con trỏ trong C
 
temp.pdf
temp.pdftemp.pdf
temp.pdf
 
giao trinh c++ Chuong1
giao trinh c++ Chuong1giao trinh c++ Chuong1
giao trinh c++ Chuong1
 
Lua introduction Gioi thieu ve Lua
Lua introduction Gioi thieu ve LuaLua introduction Gioi thieu ve Lua
Lua introduction Gioi thieu ve Lua
 
Chuong 1
Chuong 1Chuong 1
Chuong 1
 
Book
BookBook
Book
 
Book
BookBook
Book
 

Pointer

  • 1. TRƯỜNG ĐẠI HỌC CÔNG NGHỆ THÔNG TIN LIÊN CHI ĐOÀN MMT&TT HỖ TRỢ K7 Môn: Nhập môn lập trình Con trỏ, các vấn đề liên quan con trỏ
  • 2.  ĐỊA CHỈ CỦA BIẾN • Khái niệm: Địa chỉ của biến là số thứ tự của byte đầu tiên trong một dãy các byte liên tiếp mà máy dành cho biến. • Phân loại địa chỉ biến: địa chỉ kiểu int, float, double, … • Lấy địa chỉ của một biến: sử dụng toán tử &.
  • 3. Ví dụ: int x = 5;  x được cấp phát vùng nhớ có kích thước 4 byte liên tiếp. Giả sử tại địa chỉ 1050, ta có:  Địa chỉ của x: &x = 1050, giá trị của x = 5. 5 …… …… 1050 x 1053
  • 4.  KHÁI NIỆM BIẾN CON TRỎ Con trỏ là kiểu dữ liệu mà một thành phần kiểu này có thể lưu trữ địa chỉ của một thành phần nào đó (có thể là biến, hằng, hàm), hoặc ta nói nó trỏ tới thành phần đó.  PHÂN LOẠI CON TRỎ Một con trỏ lưu trữ địa chỉ của một thành kiểu T thì ta nói p là con trỏ kiểu T, đặc biệt nếu T là một kiểu con trỏ, hay nói cách khác, p lưu trữ địa chỉ của một con trỏ khác thì ta nói p là con trỏ trỏ tới con trỏ.
  • 5. Cú pháp khai báo con trỏ: <kiểu dữ liệu> * <tên_con_trỏ>; Ví dụ: int *p; // p là con trỏ kiểu int float * q ; // q là con trỏ kiểu float char *s ; // s là con trỏ kiểu char hay xâu kí tự int ** r; // r là con trỏ tới con trỏ kiểu int
  • 6. Ví dụ: int *p, *q; int x = 5; // gán đ/c biến x cho con trỏ p p = &x; // lưu đ/c trong p vào con trỏ q q = p; Giả sử địa chỉ của x là 1010 thì p = 1010 và q = 1010 5 1010 1010 …… …… 1010 x 1014 1016 p q
  • 7.  Khi giá trị nằm trong p là địa chỉ của a thì ta nói p trỏ vào a.  Lúc này thì *p hoàn toàn tương đương với a , người ta coi *p là bí danh của a , thao tác với *p cũng như thao tác với a, thao tác với a cũng như thao tác với *p. Ví dụ: Câu lệnh x=2; hoàn toàn tương đương với câu lệnh *p=2 Câu lệnh x++; hoàn toàn tương đương với (*p)++ // chú ý khác với *p++ nhé, phải cho *p vào trong đóng mở ngoặc vì toán tử * có độ ưu tiên thấp hơn ++.  Lúc này câu lệnh scanf("%d",&a); ta có thể thay bằng scanf("%d",p);
  • 8. Để xuất một địa chỉ ô nhớ ra màn hình ta sử dụng mã định dạng %p. Ví dụ: #include <stdio.h> #include <conio.h> void main() { int a; int *p; printf("n Dia chi bien a:%p",&a); p = &a; printf("n Dia chi con tro p chua la: %p", p); }
  • 9. Các phép toán trên con trỏ Phép gán: • Tất cả các loại con trỏ đều có phép gán. • Phép gán với con trỏ yêu cầu vế trái là 1 con trỏ và vế phải là 1 địa chỉ. • Phép gán yêu cầu sự tương xứng về kiểu dữ liệu, nếu ko tương xứng chúng ta phải ép kiểu. Ví dụ: p=(int*)8232; p có kiểu dữ liệu là int* còn 8232 là 1 hằng số nguyên, nên phải ép kiểu về int* rồi thực hiện phép gán. • Phép gán với 1 con trỏ kiểu void ko cần thiết phải tương xứng hoản toàn về kiểu dữ liệu, void* có thể tương ứng với tất cả thậm chí là vượt cấp (vượt hẳn 2 cấp). Ví dụ: void *p,**q; p=&q;
  • 10.  Phép so sánh • Phép so sánh ngang bằng dùng để kiểm tra 2 con trỏ có trỏ vào cùng 1 vùng nhớ hay không, hoặc kiểm tra 1 con trỏ có phải là đang trỏ vào NULL hay không (trong trường hợp cấp phát động, mở file, mở resource,........). • Phép so sánh lớn hơn nhỏ hơn : > , < , >= , <= sử dụng để kiểm tra về độ thấp cao giữa 2 địa chỉ . Con trỏ nào nhỏ hơn thì trỏ vào địa chỉ thấp hơn.  Được quyền so sánh mọi con trỏ với 0, vì 0 chính là NULL. Ví dụ: int a=197,*p=&a; double *x; p==&a; p==0; x==0; Các phép toán trên con trỏ
  • 11.  Khi so sánh 2 con trỏ hoặc con trỏ với 1 địa chỉ xác định (số nguyên) cần có sự tương xứng về kiểu dữ liệu: Ví dụ: int a=197,*p=&a; double b=0,*x=&b; // so sánh 2 con trỏ (int)p==(int)x; p==(int *)x; (double*)p==x; (void*)p==(void*)x; p==(void*)x; (float*)p==(float*)x; //so sánh con trỏ với số nguyên p==(int*)9999; int(p)==9999;  Con trỏ void có thể đem ra so sánh với tất cả các con trỏ khác. Các phép toán trên con trỏ
  • 12.  Phép cộng trừ và phép tăng giảm : +, +=, -, -=, ++, -- • Bản chất của việc tăng/ giảm con trỏ p đi 1 đơn vị là cho p trỏ đến ô nhớ bên cạnh phía dưới/trên. • Chú ý: + Khi tăng giảm con trỏ p đi 1 đơn vị không có nghĩa là trỏ sang byte bên cạnh. + Việc tăng giảm con trỏ đi 1 đơn vị phụ thuộc vào kiểu dữ liệu và nó trỏ đến, quy tắc là : p+1 >>> giá trị chứa trong p + sizeof(kiểu dữ liệu của biến mà p trỏ đến) + Không có phép tăng giảm trên con trỏ void. + Không có phép cộng 2 con trỏ với nhau. + Phép trừ 2 con trỏ trả về độ lệch pha giữa 2 con trỏ. Các phép toán trên con trỏ
  • 13. Con trỏ với mảng  Khi ta khai báo mảng thì tương đương với : xin cấp phát 1 vùng nhớ có kích thước như bạn khai báo và khai báo ra 1 hằng con trỏ trỏ vào đầu vùng nhớ đó Ví dụ: int a[100]={0,1,2,3}; 0 1 2 3 0 1000 1004 1008 1012 1016 a[0] a[1] a[0] a[2] a[3] a[4]  Chú ý : trình biên dịch luôn hiểu a[i] là *(a+i). • a là 1 hằng con trỏ trỏ vào phần tử thứ 0 của mảng. • các phép toán nhằm làm a trỏ tới vùng khác (thay đổi giá trị của a) là không thể (++, --, = ). • a tương đương với &a[0]. • a+i tương đương với &a[i]. • *a tương đương với a[0]. • *(a+i) tương đương với a[i].
  • 14. Những con trỏ mà chỉ trỏ cố định vào 1 vùng nhớ , những con trỏ này không có khả năng trỏ vào vùng nhớ khác, không thay đổi được Ví dụ: char buf[] = "bonjour"; char * const p = buf; p++; <<<<<<<<<<<<<<<<<<<<<<< báo lỗi tại đây p[4]++; <<<<<<<<<<<<<<<<<<<<<<<<< ko vấn đề, hoàn toàn có thể thay đổi giá trị vùng nhớ mà p trỏ đến Hằng con trỏ là gì? Con trỏ với mảng
  • 15. int a[100]={0,1,2,3,4,5,6}; printf("%d",2[a]); 2[a] trình biên dịch sẽ hiểu là *(2+a) *(2+a) hoàn toàn tương đương với *(a+2) mà *(a+2) chính là a[2] Vậy 2[a] cũng đơn giản là a[2] Kết quả đoạn lệnh trên??? Con trỏ với mảng
  • 16. Mảng 2 chiều Cho khai báo 1 mảng 2 chiều: int D[n][m]; // n, m là hằng nguyên Tức là có n×m phần tử kiểu nguyên, như vậy D được cấp phát một vùng nhớ liên tiếp, trong vùng đó có n vùng con cho n phần tử (dòng), trong mỗi vùng con có m ô nhớ (mỗi ô là một phần tử). Hay nói cách khác các phần tử của mảng được cấp phát liên tiếp, đầu tiên là phần tử của hàng 0, sau đó là phần tử của hàng 1,... 1000 1004 ... 1000 + m*i*4 + j*4 d[0][0] d[0][1] ... d[ i ][ j ] d[n-1][m-1] 1000 + m*(n-1)*4 + (m-1)*4 Con trỏ với mảng
  • 17.  Cấp phát: để cấp phát bộ nhớ cho một biến con trỏ ta có thể sử dụng các hàm: malloc, calloc, realloc.  Thu hồi: để thu hồi bộ nhớ đã cấp phát cho một biến con trỏ ta dùng hàm free.  Chú ý là : • malloc trả về 1 địa chỉ đến 1 vùng nhớ và coi vùng nhớ này là void *, nên trong câu lệnh malloc luôn đi kèm với việc ép kiểu: contro = (ép kiểu) malloc(...) • Cấp phát là luôn phải đi kèm với giải phóng, ở đâu cũng thế, malloc là phải free. Code mà để thoát chương trình rồi chưa giải phóng cho dù là có hệ thống có tự giải phóng đi nữa vẫn bị coi là bad!!!! Cấp phát và thu hồi bộ nhớ
  • 18. Vậy còn new và delete?  new và delete không phải là hàm mà là toán tử nên không còn phải khai báo thư viện như malloc (thư viện stdlib.h).  new không có khả năng realloc. Ví dụ: int *x=new(int); ..... delete x;
  • 19. Con trỏ với hàm int ham(int *a) { *a=2; a++; } void main() { int *a; printf("Truoc : %x",a); //trước và sau khi gọi hàm ham(a); //con trỏ a trỏ vào đâu printf("Sau %x",a); // thì nó vẫn trỏ vào đó getch(); } Hàm trong C ko hề có tham biến, hàm trong C đều hoạt động theo nguyên tắc sau : Khi gọi hàm, 1 bản sao của tham số được tạo ra và hàm sẽ làm việc với bản sao này.
  • 20. void nhap(int *a,int n) { a=(int*)malloc(n * sizeof(int)); //sai lầm for(int i=0;i<n;i++) scanf("%d", &a[i]); } void main() { int *x; int n=6; nhap(x,n); //xuat free(x); // sản sinh ra lỗi run-time do x chưa trỏ vào đâu mà đòi giải phóng } Con trỏ với hàm
  • 21. Dùng con trỏ cấp cao hơn con trỏ hiện tại Ví dụ: void ham(int **a) { *a=(int*)malloc(100*sizeof(int)); //a[0]=(int*)malloc(100*sizeof(int)); // 2 cach nay nhu nay } void main() { int *a; ham(&a); free(a); } Làm thế nào để mà thay đổi giá trị của 1 con trỏ qua 1 hàm? Con trỏ với hàm
  • 22. Con trỏ với cấu trúc Để truy xuất đến một thành phần của biến con trỏ cấu trúc ta sử dụng toán tử mũi tên (->) Ví dụ: typedef struct tagNode { int info; struct tagNode* pNext; }NODE; NODE* tao_pt(int x) { NODE* p=new NODE; if(p==NULL) { printf("Khong du bo nho"); return p; } p->info=x; p->pNext=NULL; return p; }