Lập trình C++ bai 8
Chia sẻ bởi Đặng Anh Tuấn |
Ngày 29/04/2019 |
66
Chia sẻ tài liệu: lập trình C++ bai 8 thuộc Tin học 9
Nội dung tài liệu:
Chương 8: Quản lý bộ nhớ
Nội dung chính
Con trỏ (Pointer)
Tham chiếu (Reference)
Sử dụng tham chiếu hay con trỏ
1. Con trỏ
Con trỏ được sử dụng để:
Truy nhập vào các thành phần của mảng
Truyền tham số cho hàm theo kiểu truyền biến
Truyền mảng và xâu ký tự cho hàm
Lấy thông tin từ bộ nhớ của hệ thống
Tạo ra những cấu trúc dữ liệu như: danh sách liên kết
Con trỏ …
Mỗi biến trong chương trình chiếm một vùng nhớ, ví dụ biến kiểu int chiếm 4 byte nhớ.
Vị trí của vùng nhớ được gọi là địa chỉ của biến
Biến con trỏ
Biến con trỏ là biến lưu giá trị của địa chỉ vùng nhớ.
Mỗi kiểu dữ liệu có một biến con trỏ riêng: con trỏ kiểu int, con trỏ kiểu char…
C++ sử dụng:
Toán tử & để lấy địa chỉ của biến
Toán tử * để lấy nội dung của biến được trỏ.
Ví dụ:
int i=17;
int* ptr; // khai báo biến trỏ kiểu int
ptr= &i; // gán địa chỉ của biến i cho con trỏ ptr
cout << *ptr << endl; // hiển thị nội dung của biến i
Biến con trỏ …
Biến con trỏ …
int v; // khai báo biến v kiểu int
int w; // khai báo biến w kiểu int
int* p; // khai báo biến p kiểu con trỏ trỏ tới kiểu int
p=&v; // gán địa chỉ của v cho con trỏ p
v=3; // gán giá trị 3 cho v
*p=7; // gán giá trị 7 cho v
p=&w; // gán địa chỉ của w cho con trỏ p
*p=12; // gán giá trị 12 cho w
Sử dụng toán tử * để lấy nội dung của biến còn được gọi là tham chiếu ngược tới con trỏ.
Con trỏ hằng
Khai báo hằng:
const int result = 5; // result là hằng
result = 10; // sau đó gán lại giá trị thì C++ sẽ báo lỗi
Khai báo con trỏ hằng:
const char* answer_ptr = "Forty-Two";
// answer_ptr là con trỏ trỏ tới hằng kiểu char
Dữ liệu được trỏ bởi con trỏ hằng thì không thể thay đổi nhưng con trỏ thì có thể.
answer_ptr = "Fifty-One"; // đúng (answer_ptr là biến con trỏ)
*answer_ptr = `X`; // sai (*answer_ptr là hằng)
Con trỏ hằng …
Nếu khai báo:
char *const nameptr = "Test"; //name_ptr là con trỏ hằng
nameptr = "New"; // sai (name_ptr là hằng)
*nameptr = `B`; // đúng (*nameptr là char)
Nếu khai báo như sau thì không thể thay đổi được cả con trỏ và nội dung của con trỏ:
const char* const titleptr = "Title";
Con trỏ là tham số của hàm
C++ cung cấp 3 cách truyền tham số:
Truyền tham trị: void f(int x);
Truyền tham chiếu: void f(int& x);
Truyền con trỏ: void f(int* x);
Con trỏ là tham số của hàm …
void swap( double& x, double& y)
{
double tmp=x;
x=y;
y=tmp;
}
void swap( double* ptr1, double* ptr2)
{
double tmp=*ptr1;
*ptr1=*ptr2;
*ptr2=tmp;
}
double a=3.0;
double b=5.0
swap(a,b); // gọi tham chiếu của biến a và b
swap(&a, &b); // sử dụng địa chỉ của biến a và b
Con trỏ là tham số của hàm…
void bsort (double* ptr, int n)
{
int j,k;
for (j=0; j for(k=j+1; k if(*(ptr+j) > *(ptr+k))
swap(ptr+j,ptr+k);
}
double array[6] = { 2.3, 4.5, 1.2, 6.8, 0.8, 4.9 };
bsort(array,n);
Quản lý bộ nhớ
Toán tử new được sử dụng để tạo ra các đối tượng trên vùng nhớ heap.
Date* CreateDate()
{
int day, month, year;
char dummy;
cout << ”Enter dd/mm/yyyy :”;
cin >> day >> dummy >> month >> dummy >> year;
Date* tmpptr = new Date date(day, month, year);
return tmpptr;
}
Date* ptr;
ptr=CreateDate();
cout << ”You entered ” << *ptr << endl;
Quản lý bộ nhớ …
Toán tử new cũng được sử dụng để cấp phát các block nhớ.
Toán tử delete được sử dụng để giải phóng vùng nhớ được cấp phát bởi toán tử new.
#include
char* str =”This is an old C-style string”;
int len=strlen(str); // xác định kích thước của str
char* ptr;
ptr = new char[len+1]; // cấp phát vùng nhớ
strcpy(ptr,str);
cout << ”ptr=” << ptr << endl;
delete [] ptr; // giải phóng vùng nhớ
Toán tử new được sử dụng trong hàm tạo
class String
{
private:
char* str;
public:
String(char* s)
{
int length=strlen(s);
str = new char[length+1];
strcpy(str,s);
}
~String()
{ delete [] str; }
void Display() { cout << str << endl; }
};
String mystring=”This is my string of Type String”;
mystring.Display();
Con trỏ trỏ tới đối tượng
Con trỏ trỏ tới các đối tượng cũng tương tự như các kiểu built-in khác.
Truy nhập tới các thành phần thông qua toán tử ->
Date date;
date.Set(12,3,1996);
date.Display();
Date* dateptr;
dateptr=new Date;
dateptr->Set(9,12,1999);
dateptr->Display();
(*dateptr).Display();
Ví dụ: Linked List
struct link // định nghĩa một phần tử trong danh sách
{
int data; // data item
link* next; // con trỏ trỏ tới phần tử kế tiếp
};
class linklist
{
private:
link* first; // con trỏ trỏ tới phần tử đầu tiên trong danh sách
public:
linklist() { first = NULL;} // hàm tạo không có tham số
void additem(int d); // bổ sung thêm một phần tử vào danh sách
void display(); // hiển thị danh sách
} ;
Ví dụ: Linked List …
void linklist::additem(int d)
{
link* newlink = new link; // tạo ra một phần tử mới trong danh sách
newlink->data = d; // gán dữ liệu
newlink->next=first; // trỏ vào phần tử đầu tiên
first = newlink; // thay đổi con trỏ first
}
void linklist::display()
{
link* current=first; // bắt đầu từ phần tử đầu tiên
while(current != NULL) // đến khi kết thúc danh sách
{
cout << current->data << ” ”;
current=current->next; // di chuyển đến phần tử kế tiếp
}
}
Cấu trúc tự trỏ
Một lớp có thể chứa con trỏ trỏ tới đối tượng của chính lớp đó, nhưng không thể chứa đối tượng của lớp đó.
class someclass
{
someclass* ptr; // đúng
};
class someclass
{
someclass obj; //sai
};
Ví dụ: Sử dụng cấu trúc tự trỏ
class LinkList
{
private:
int data;
LinkList *next, *first;
public:
LinkList();
void Insert(int d);
void Show();
};
Ví dụ: Sử dụng cấu trúc tự trỏ …
LinkList :: LinkList(){f=NULL;}
void LinkList :: Insert(int d)
{
LinkList* n = new LinkList();
n->data=d;
n->next=first;
first=next;
}
void LinkList :: Show()
{
LinkList* p=first;
while (p!=NULL)
{
cout<data< p=p->next;
}
}
2. Tham chiếu
Tham chiếu là một bí danh (alias)
Khi ta tạo ra một tham chiếu, khởi tạo nó bằng tên của một đối tượng khác (đối tượng đích)thì tham chiếu đóng vai trò là một cái tên khác của đích.
Bất kỳ việc gì được thực hiện trên tham chiếu cũng tức là được thực hiện trên đích.
Khai báo tham chiếu:
int& rSomeRef = someInt;
Tham chiếu …
Nếu ta yêu cầu một tham chiếu tham chiếu tới địa chỉ của nó, thì tham chiếu sẽ trả về địa chỉ của đối tượng đích của nó.
Ví dụ:
int intOne;
int& rSomeRef = intOne;
cout << "&intOne: " << &intOne << endl;
cout << "&rSomeRef: " << &rSomeRef << endl;
Tham chiếu tới đối tượng
Bất kỳ đối tượng nào cũng được tham chiếu, kể cả các đối tượng do người sử dụng định nghĩa.
Tham chiếu tới các đối tượng thường được sử dụng như chính đối tượng đó.
Dữ liệu thành phần và các phương thức được truy nhập bằng cách sử dụng toán tử “.”, tham chiếu đóng vai trò là bí danh của đối tượng.
Ví dụ:
int& rIntRef = int; // sai
int howBig = 200;
int& rIntRef = howBig;
Tương tự, không thể khởi tạo một tham chiếu tới lớp CAT:
CAT& rCatRef = CAT; // sai
Phải khởi tạo rCatRef tới một đối tượng CAT cụ thể
CAT frisky;
CAT& rCatRef = frisky;
Con trỏ Null và tham chiếu Null
Khi con trỏ không được khởi tạo hoặc bị xoá thì chúng đều được gán bằng Null.
Tuy nhiên, một tham chiếu không thể là Null
Một chương trình có tham chiếu tới một đối tượng Null thì bị coi là chương trình không hợp lệ và không thể kiểm soát được hết tất cả các lỗi trong chương trình.
3. Sử dụng tham chiếu hay con trỏ
Người lập trình C++ thích tham chiếu hơn con trỏ.
Tham chiếu thường rõ ràng, dễ sử dụng hơn và thực hiện nhiệm vụ che dấu thông tin tốt hơn.
Không thể gán lại tham chiếu. Nếu ta cần trỏ tới một đối tượng và sau đó lại trỏ tới một đối tượng khác, thì ta phải sử dụng con trỏ.
Tham chiếu không thể null, cho nên nếu có trường hợp đối tượng có thể là null thì ta phải sử dụng con trỏ.
Ví dụ:
int* pInt = new int;
if (pInt != NULL) int& rInt = *pInt;
Sử dụng tham chiếu hay con trỏ …
Ta có thể khai báo cả con trỏ và tham chiếu trong cùng một danh sách các tham số của hàm, cùng với các đối tượng truyền trị khác.
Ví dụ:
CAT * SomeFunction (Person& theOwner, House* theHouse, int age);
SomeFunction có 3 tham số:
Tham số thứ nhất là tham chiếu tới đối tượng Person
Tham số thứ hai là con trỏ tới đối tượng House
Tham số thứ ba là một số nguyên.
Hàm trả về một con trỏ trỏ tới đối tượng CAT.
Trước khi truyền tham chiếu cho hàm hoặc trả về một tham chiếu thì ta phải đặt ra câu hỏi “Tham chiếu sẽ là bí danh của đối tượng nào và nó có tồn tại mỗi khi tham chiếu được sử dụng không?”
Nội dung chính
Con trỏ (Pointer)
Tham chiếu (Reference)
Sử dụng tham chiếu hay con trỏ
1. Con trỏ
Con trỏ được sử dụng để:
Truy nhập vào các thành phần của mảng
Truyền tham số cho hàm theo kiểu truyền biến
Truyền mảng và xâu ký tự cho hàm
Lấy thông tin từ bộ nhớ của hệ thống
Tạo ra những cấu trúc dữ liệu như: danh sách liên kết
Con trỏ …
Mỗi biến trong chương trình chiếm một vùng nhớ, ví dụ biến kiểu int chiếm 4 byte nhớ.
Vị trí của vùng nhớ được gọi là địa chỉ của biến
Biến con trỏ
Biến con trỏ là biến lưu giá trị của địa chỉ vùng nhớ.
Mỗi kiểu dữ liệu có một biến con trỏ riêng: con trỏ kiểu int, con trỏ kiểu char…
C++ sử dụng:
Toán tử & để lấy địa chỉ của biến
Toán tử * để lấy nội dung của biến được trỏ.
Ví dụ:
int i=17;
int* ptr; // khai báo biến trỏ kiểu int
ptr= &i; // gán địa chỉ của biến i cho con trỏ ptr
cout << *ptr << endl; // hiển thị nội dung của biến i
Biến con trỏ …
Biến con trỏ …
int v; // khai báo biến v kiểu int
int w; // khai báo biến w kiểu int
int* p; // khai báo biến p kiểu con trỏ trỏ tới kiểu int
p=&v; // gán địa chỉ của v cho con trỏ p
v=3; // gán giá trị 3 cho v
*p=7; // gán giá trị 7 cho v
p=&w; // gán địa chỉ của w cho con trỏ p
*p=12; // gán giá trị 12 cho w
Sử dụng toán tử * để lấy nội dung của biến còn được gọi là tham chiếu ngược tới con trỏ.
Con trỏ hằng
Khai báo hằng:
const int result = 5; // result là hằng
result = 10; // sau đó gán lại giá trị thì C++ sẽ báo lỗi
Khai báo con trỏ hằng:
const char* answer_ptr = "Forty-Two";
// answer_ptr là con trỏ trỏ tới hằng kiểu char
Dữ liệu được trỏ bởi con trỏ hằng thì không thể thay đổi nhưng con trỏ thì có thể.
answer_ptr = "Fifty-One"; // đúng (answer_ptr là biến con trỏ)
*answer_ptr = `X`; // sai (*answer_ptr là hằng)
Con trỏ hằng …
Nếu khai báo:
char *const nameptr = "Test"; //name_ptr là con trỏ hằng
nameptr = "New"; // sai (name_ptr là hằng)
*nameptr = `B`; // đúng (*nameptr là char)
Nếu khai báo như sau thì không thể thay đổi được cả con trỏ và nội dung của con trỏ:
const char* const titleptr = "Title";
Con trỏ là tham số của hàm
C++ cung cấp 3 cách truyền tham số:
Truyền tham trị: void f(int x);
Truyền tham chiếu: void f(int& x);
Truyền con trỏ: void f(int* x);
Con trỏ là tham số của hàm …
void swap( double& x, double& y)
{
double tmp=x;
x=y;
y=tmp;
}
void swap( double* ptr1, double* ptr2)
{
double tmp=*ptr1;
*ptr1=*ptr2;
*ptr2=tmp;
}
double a=3.0;
double b=5.0
swap(a,b); // gọi tham chiếu của biến a và b
swap(&a, &b); // sử dụng địa chỉ của biến a và b
Con trỏ là tham số của hàm…
void bsort (double* ptr, int n)
{
int j,k;
for (j=0; j
swap(ptr+j,ptr+k);
}
double array[6] = { 2.3, 4.5, 1.2, 6.8, 0.8, 4.9 };
bsort(array,n);
Quản lý bộ nhớ
Toán tử new được sử dụng để tạo ra các đối tượng trên vùng nhớ heap.
Date* CreateDate()
{
int day, month, year;
char dummy;
cout << ”Enter dd/mm/yyyy :”;
cin >> day >> dummy >> month >> dummy >> year;
Date* tmpptr = new Date date(day, month, year);
return tmpptr;
}
Date* ptr;
ptr=CreateDate();
cout << ”You entered ” << *ptr << endl;
Quản lý bộ nhớ …
Toán tử new cũng được sử dụng để cấp phát các block nhớ.
Toán tử delete được sử dụng để giải phóng vùng nhớ được cấp phát bởi toán tử new.
#include
char* str =”This is an old C-style string”;
int len=strlen(str); // xác định kích thước của str
char* ptr;
ptr = new char[len+1]; // cấp phát vùng nhớ
strcpy(ptr,str);
cout << ”ptr=” << ptr << endl;
delete [] ptr; // giải phóng vùng nhớ
Toán tử new được sử dụng trong hàm tạo
class String
{
private:
char* str;
public:
String(char* s)
{
int length=strlen(s);
str = new char[length+1];
strcpy(str,s);
}
~String()
{ delete [] str; }
void Display() { cout << str << endl; }
};
String mystring=”This is my string of Type String”;
mystring.Display();
Con trỏ trỏ tới đối tượng
Con trỏ trỏ tới các đối tượng cũng tương tự như các kiểu built-in khác.
Truy nhập tới các thành phần thông qua toán tử ->
Date date;
date.Set(12,3,1996);
date.Display();
Date* dateptr;
dateptr=new Date;
dateptr->Set(9,12,1999);
dateptr->Display();
(*dateptr).Display();
Ví dụ: Linked List
struct link // định nghĩa một phần tử trong danh sách
{
int data; // data item
link* next; // con trỏ trỏ tới phần tử kế tiếp
};
class linklist
{
private:
link* first; // con trỏ trỏ tới phần tử đầu tiên trong danh sách
public:
linklist() { first = NULL;} // hàm tạo không có tham số
void additem(int d); // bổ sung thêm một phần tử vào danh sách
void display(); // hiển thị danh sách
} ;
Ví dụ: Linked List …
void linklist::additem(int d)
{
link* newlink = new link; // tạo ra một phần tử mới trong danh sách
newlink->data = d; // gán dữ liệu
newlink->next=first; // trỏ vào phần tử đầu tiên
first = newlink; // thay đổi con trỏ first
}
void linklist::display()
{
link* current=first; // bắt đầu từ phần tử đầu tiên
while(current != NULL) // đến khi kết thúc danh sách
{
cout << current->data << ” ”;
current=current->next; // di chuyển đến phần tử kế tiếp
}
}
Cấu trúc tự trỏ
Một lớp có thể chứa con trỏ trỏ tới đối tượng của chính lớp đó, nhưng không thể chứa đối tượng của lớp đó.
class someclass
{
someclass* ptr; // đúng
};
class someclass
{
someclass obj; //sai
};
Ví dụ: Sử dụng cấu trúc tự trỏ
class LinkList
{
private:
int data;
LinkList *next, *first;
public:
LinkList();
void Insert(int d);
void Show();
};
Ví dụ: Sử dụng cấu trúc tự trỏ …
LinkList :: LinkList(){f=NULL;}
void LinkList :: Insert(int d)
{
LinkList* n = new LinkList();
n->data=d;
n->next=first;
first=next;
}
void LinkList :: Show()
{
LinkList* p=first;
while (p!=NULL)
{
cout<
}
}
2. Tham chiếu
Tham chiếu là một bí danh (alias)
Khi ta tạo ra một tham chiếu, khởi tạo nó bằng tên của một đối tượng khác (đối tượng đích)thì tham chiếu đóng vai trò là một cái tên khác của đích.
Bất kỳ việc gì được thực hiện trên tham chiếu cũng tức là được thực hiện trên đích.
Khai báo tham chiếu:
int& rSomeRef = someInt;
Tham chiếu …
Nếu ta yêu cầu một tham chiếu tham chiếu tới địa chỉ của nó, thì tham chiếu sẽ trả về địa chỉ của đối tượng đích của nó.
Ví dụ:
int intOne;
int& rSomeRef = intOne;
cout << "&intOne: " << &intOne << endl;
cout << "&rSomeRef: " << &rSomeRef << endl;
Tham chiếu tới đối tượng
Bất kỳ đối tượng nào cũng được tham chiếu, kể cả các đối tượng do người sử dụng định nghĩa.
Tham chiếu tới các đối tượng thường được sử dụng như chính đối tượng đó.
Dữ liệu thành phần và các phương thức được truy nhập bằng cách sử dụng toán tử “.”, tham chiếu đóng vai trò là bí danh của đối tượng.
Ví dụ:
int& rIntRef = int; // sai
int howBig = 200;
int& rIntRef = howBig;
Tương tự, không thể khởi tạo một tham chiếu tới lớp CAT:
CAT& rCatRef = CAT; // sai
Phải khởi tạo rCatRef tới một đối tượng CAT cụ thể
CAT frisky;
CAT& rCatRef = frisky;
Con trỏ Null và tham chiếu Null
Khi con trỏ không được khởi tạo hoặc bị xoá thì chúng đều được gán bằng Null.
Tuy nhiên, một tham chiếu không thể là Null
Một chương trình có tham chiếu tới một đối tượng Null thì bị coi là chương trình không hợp lệ và không thể kiểm soát được hết tất cả các lỗi trong chương trình.
3. Sử dụng tham chiếu hay con trỏ
Người lập trình C++ thích tham chiếu hơn con trỏ.
Tham chiếu thường rõ ràng, dễ sử dụng hơn và thực hiện nhiệm vụ che dấu thông tin tốt hơn.
Không thể gán lại tham chiếu. Nếu ta cần trỏ tới một đối tượng và sau đó lại trỏ tới một đối tượng khác, thì ta phải sử dụng con trỏ.
Tham chiếu không thể null, cho nên nếu có trường hợp đối tượng có thể là null thì ta phải sử dụng con trỏ.
Ví dụ:
int* pInt = new int;
if (pInt != NULL) int& rInt = *pInt;
Sử dụng tham chiếu hay con trỏ …
Ta có thể khai báo cả con trỏ và tham chiếu trong cùng một danh sách các tham số của hàm, cùng với các đối tượng truyền trị khác.
Ví dụ:
CAT * SomeFunction (Person& theOwner, House* theHouse, int age);
SomeFunction có 3 tham số:
Tham số thứ nhất là tham chiếu tới đối tượng Person
Tham số thứ hai là con trỏ tới đối tượng House
Tham số thứ ba là một số nguyên.
Hàm trả về một con trỏ trỏ tới đối tượng CAT.
Trước khi truyền tham chiếu cho hàm hoặc trả về một tham chiếu thì ta phải đặt ra câu hỏi “Tham chiếu sẽ là bí danh của đối tượng nào và nó có tồn tại mỗi khi tham chiếu được sử dụng không?”
* Một số tài liệu cũ có thể bị lỗi font khi hiển thị do dùng bộ mã không phải Unikey ...
Người chia sẻ: Đặng Anh Tuấn
Dung lượng: |
Lượt tài: 0
Loại file:
Nguồn : Chưa rõ
(Tài liệu chưa được thẩm định)