Chương 5 Kỹ thuật lập trình dùng con trỏ - Pdf 63

Chơng V. Kỹ thuật lập trình dùng con trỏ
I. Tổng quan về con trỏ
I.1. Khái niệm và cách khai báo
- Mỗi byte trong bộ nhớ đều đợc đánh địa chỉ, là một con số hệ thập lục phân. Địa chỉ của biến là địa chỉ của
byte đầu tiên trong vùng nhớ dành cho biến.
Thông thờng, khi ta khai báo một biến, máy tính sẽ cấp phát một ô nhớ với kích thớc tơng ứng trong vùng
64Kb dành cho việc khai báo biến (mô hình tiny). Ô nhớ này có thể dùng để lu trữ các giá trị khác nhau, gọi là giá
trị của biến. Bên cạnh đó, mỗi biến còn có một địa chỉ là một con số hệ thập lục phân.
Con trỏ (hay biến con trỏ) là một biến đặc biệt dùng để chứa địa chỉ của các biến
khác.
Nh vậy, con trỏ cũng giống nh biến thờng (tức cũng là một ô nhớ trong bộ nhớ) nhng điểm khác biệt là nó
không thể chứa các giá trị thông thờng mà chỉ dùng để chứa địa chỉ của biến.
Con trỏ cũng có nhiều kiểu (nguyên, thực, ký tự). Con trỏ thuộc kiểu nào chỉ chứa địa chỉ của
biến thuộc kiểu đó.
Cú pháp khai báo:
<Kiểu con trỏ> * <Tên con trỏ>;
Trong đó: <Kiểu con trỏ> có thể là một trong các kiểu chuẩn của C++ hoặc kiểu tự định nghĩa. <Tên
con trỏ> đợc đặt tuỳ ý theo quy ớc đặt tên trong C++.
Ví dụ: dòng khai báo int a, *p; float b, *q; khai báo a và p kiểu nguyên, b và q kiểu thực, trong đó, p và q là
hai con trỏ. Khi đó, p có thể chứa địa chỉ của a và q có thể chứa địa chỉ của b.
I.2. Một số thao tác cơ bản trên con trỏ
Lấy địa chỉ của biến đặt vào con trỏ:
Giả sử a là một biến nguyên và p là một con trỏ cùng kiểu với a. Để lấy địa chỉ của a đặt vào p ta viết:
P = &a;
Toán tử & cho phép lấy địa chỉ của một biến bất kỳ. Khi đó, ta nói p đang trỏ tới a. Một cách tổng quát, để
lấy địa chỉ của một biến đặt vào con trỏ cùng kiểu, ta viết:
<Tên con trỏ> = & <Tên biến>;
Phép gán con trỏ cho con trỏ:
Nếu p và q là hai con trỏ cùng kiểu, ta có thể gán p sang q và ngợc lại, ta viết: p = q; hoặc q = p; Khi đó, địa
chỉ đang chứa trong con trỏ ở vế phải sẽ đợc đặt vào con trỏ ở vế trái và ta nói hai con trỏ cùng trỏ tới một biến.
Ví dụ:


a+i là địa chỉ của a[i]
Nh vậy thì
*a là a[0]
*(a+1) là a[1]
*(a+2) là a[2]

*(a+i) là a[i]
Vậy ta có thể sử dụng cách viết thứ hai cho các phần tử của mảng. Thay vì viết a[i], ta có thể viết *(a+i)
Con trỏ là mảng
Một con trỏ p bất kỳ cũng tơng đơng với một mảng một chiều. Thật vậy, giả sử con trỏ p đang chứa địa chỉ
của một ô nhớ a nào đó, khi đó ta có thể sử dụng p để quản lý một dãy các ô nhớ liên tiếp bắt đầu từ a.
Nh vậy:
p là địa chỉ của a
p+1 là địa chỉ của ô nhớ ngay sau a

p+i là địa chỉ của ô nhớ thứ i kể từ a.
p
a
p+1 p+2
Vậy, với p là con trỏ thì ta có thể coi nó nh mảng một chiều và để truy cập tới phần tử thứ i của p ta có thể
viết *(p+i) hoặc thậm chí viết p[i].
II.2. Con trỏ và hàm
Phân loại đối số
Một hàm trong C++ có thể không trả về giá trị nào mà đơn giản chỉ thực hiện một công việc nào đó (hàm
void). Tuy nhiên, với những hàm có giá trị trả về, giá trị đó sẽ đợc đặt vào tên hàm (trả về thông qua tên hàm) bằng
lệnh return <giá trị trả về>;. Lệnh return này tơng tự nh việc ta gán <tên hàm> = <giá trị trả về>;
Với một hàm, tên hàm chỉ có một nên hàm chỉ có thể trả về duy nhất một giá trị thông qua tên hàm.
Tuy nhiên, có những hàm đòi hỏi phải trả về nhiều hơn một giá trị, chẳng hạn hàm giải phơng trình bậc hai.
Hàm này có các đối vào là các hệ số a, b, c của phơng trình bậc hai và nếu có nghiệm thì hàm sẽ trả về 2 nghiệm x1

{
*x1=(-b+sqrt(DT))/(2*a);
*x2=(-b-sqrt(DT))/(2*a);
return 1;
}
}
void main()
{
float a,b,c;
cout<<"a="; cin>>a;
cout<<"b="; cin>>b;
cout<<"c="; cin>>c;
float x1, x2;
int k=GPTB2(a,b,c,&x1,&x2);
if(k==-1)
cout<<"Phuong trinh vo nghiem";
else
cout<<"Pt co 2 nghiem x1="<<x1<<" x2="<<x2;
getch();
}
Ví dụ 2: Viết hàm trả về đồng thời 3 giá trị là tổng các số chẵn, tổng các số lẻ và tổng các số chia hết cho 3
trong một mảng n phần tử nguyên.
Các đối vào: mảng nguyên a, kích thớc thực tế của mảng n.
Các đối ra: T1- tổng các số chẵn trong mảng; T2- tổng các số lẻ trong mảng; T3- tổng các số chia hết 3 trong
mảng.
void TinhTong(int *a, int n, int *T1, int *T2, int *T3)
{
*T1=*T2=*T3=0;
for(int i=0; i<n; i++)
{

Trong đó, <n> là số ô nhớ cần cấp phát (số phần tử của mảng); <size> là kích thớc của một ô nhớ.
Hàm calloc nếu thực hiện thành công sẽ cấp phát một vùng nhớ có kích thớc <n>*<size> Byte và <con trỏ>
sẽ trỏ tới ô nhớ đầu tiên của vùng nhớ này. Ngợc lại, nếu thực hiện không thành công (do không đủ bộ nhớ hoặc <n>
hoặc <size> không hợp lệ) hàm sẽ trả về giá trị NULL (tức con trỏ trỏ tới NULL).
Giả sử p là một mảng nguyên, khi đó kích thớc mỗi ô nhớ là 2 Byte (tức <size> = 2). Nếu p là mảng thực thì
<size> =4 .v.vToán tử sizeof sẽ cho ta biết kích thớc của mỗi ô nhớ thuộc một kiểu bất kỳ. Muốn vậy ta chỉ cần
viết: sizeof(<kiểu>). Ví dụ sizeof(int) = 2; sizeof(float) = 4; .v.v
Hàm calloc thuộc th viện alloc.h.
Ví dụ 1: Nhập một mảng p gồm n phần tử nguyên, sử dụng hàm calloc cấp phát bộ nhớ động.
int *p, n;
cout<< Nhập n=; cin>>n;
p = (int *) calloc(n, sizeof(int));
if(p==NULL)
cout<< Cap phat bo nho khong thanh cong;
else //Nhap mang


Nhờ tải bản gốc

Tài liệu, ebook tham khảo khác

Music ♫

Copyright: Tài liệu đại học © DMCA.com Protection Status