Con Trỏ Cơ Bản Trong C++: Khái Niệm, Cách Sử Dụng và Bài Tập

Tài liệu nghiên cứu Bai11 contro trong c p1, tổng hợp lý thuyết và thực hành, cung cấp kiến thức chuyên sâu về ., phục vụ nghiên cứu và ứng dụng thực tiễn

Trường đại học

Trường Đại Học

Chuyên ngành

Công Nghệ Thông Tin

Người đăng

Ẩn danh

Thể loại

bài giảng

2023

57
1
0

Phí lưu trữ

30 Point

Mục lục chi tiết

1. CHƯƠNG 1: Khái niệm và cách sử dụng con trỏ

1.1. Biến và vùng nhớ

1.2. Khái niệm con trỏ

1.3. Khai báo con trỏ

1.4. Con trỏ và toán tử &, *

1.5. Con trỏ NULL

1.6. Toán tử sizeof

1.7. Từ khóa const và con trỏ

1.8. Con trỏ và hàm

1.9. Bài tập

1.10. Một số lưu ý

2. CHƯƠNG 2: Con trỏ và Mảng 1 chiều

2.1. Mảng 1 chiều và cách lấy địa chỉ

2.2. Mảng 1 chiều và hằng con trỏ

2.3. Các phép toán số học trên con trỏ

2.4. Con trỏ và mảng 1 chiều

2.5. Truyền mảng 1 chiều cho hàm

2.6. Bài tập

Tóm tắt

I. Khám Phá Khái Niệm Con Trỏ Trong C Cách Hiểu Đúng

Khái niệm con trỏ trong C++ là một trong những chủ đề quan trọng và phức tạp nhất trong lập trình. Con trỏ là một biến lưu trữ địa chỉ của một biến khác, cho phép thao tác trực tiếp với bộ nhớ. Việc hiểu rõ về khái niệm con trỏ giúp lập trình viên quản lý bộ nhớ hiệu quả hơn và tối ưu hóa hiệu suất chương trình. Trong phần này, sẽ trình bày tổng quan về con trỏ, cách khai báo và sử dụng chúng trong C++.

1.1. Khái Niệm Về Biến và Vùng Nhớ Trong C

Bộ nhớ máy tính được chia thành nhiều ô nhớ, mỗi ô có địa chỉ duy nhất. Khi khai báo biến, máy tính sẽ cấp phát một vùng nhớ cho biến đó. Việc hiểu rõ cách quản lý biếnvùng nhớ là rất cần thiết để sử dụng con trỏ hiệu quả.

1.2. Cách Khai Báo Con Trỏ Trong C

Để khai báo một con trỏ, cú pháp sử dụng là <kiểu dữ liệu>* <tên biến con trỏ>;. Việc khai báo đúng cách giúp lập trình viên có thể sử dụng con trỏ để trỏ tới các biến khác trong chương trình.

II. Tìm Hiểu Vấn Đề Thường Gặp Khi Sử Dụng Con Trỏ Trong C

Mặc dù con trỏ mang lại nhiều lợi ích, nhưng cũng có nhiều vấn đề phát sinh khi sử dụng chúng. Một trong những vấn đề phổ biến là việc sử dụng con trỏ chưa được khởi tạo, dẫn đến lỗi không lường trước được. Phần này sẽ đề cập đến những thách thức và cách giải quyết chúng.

2.1. Lỗi Thường Gặp Khi Sử Dụng Con Trỏ NULL

Con trỏ NULL là con trỏ không trỏ vào đâu cả. Việc sử dụng con trỏ NULL mà không kiểm tra có thể dẫn đến lỗi nghiêm trọng trong chương trình. Cần phải kiểm tra con trỏ trước khi sử dụng để tránh lỗi.

2.2. Quản Lý Bộ Nhớ Khi Sử Dụng Con Trỏ

Quản lý bộ nhớ là một thách thức lớn khi làm việc với con trỏ. Việc cấp phát và giải phóng bộ nhớ không đúng cách có thể dẫn đến rò rỉ bộ nhớ. Cần phải nắm rõ cách sử dụng các hàm như newdelete để quản lý bộ nhớ hiệu quả.

III. Phương Pháp Sử Dụng Con Trỏ Trong C Để Tối Ưu Hóa Chương Trình

Sử dụng con trỏ đúng cách có thể giúp tối ưu hóa hiệu suất của chương trình. Phần này sẽ trình bày các phương pháp và kỹ thuật để sử dụng con trỏ một cách hiệu quả.

3.1. Cách Sử Dụng Con Trỏ Để Thao Tác Với Mảng

Con trỏ có thể được sử dụng để thao tác với mảng một cách linh hoạt. Việc sử dụng con trỏ giúp truy cập và thay đổi giá trị của các phần tử trong mảng một cách dễ dàng và hiệu quả.

3.2. Con Trỏ và Hàm Tối Ưu Hóa Tham Số Truyền Vào

Sử dụng con trỏ để truyền tham số vào hàm giúp tiết kiệm bộ nhớ và tăng tốc độ thực thi. Thay vì truyền toàn bộ biến, chỉ cần truyền địa chỉ của biến, giúp giảm thiểu chi phí sao chép dữ liệu.

IV. Ứng Dụng Thực Tiễn Của Con Trỏ Trong Lập Trình C

Con trỏ không chỉ là một khái niệm lý thuyết mà còn có nhiều ứng dụng thực tiễn trong lập trình. Phần này sẽ trình bày một số ứng dụng cụ thể của con trỏ trong C++.

4.1. Quản Lý Bộ Nhớ Động Với Con Trỏ

Con trỏ cho phép lập trình viên quản lý bộ nhớ động, giúp tạo ra các cấu trúc dữ liệu linh hoạt như danh sách liên kết, cây, và đồ thị. Việc sử dụng con trỏ trong quản lý bộ nhớ động là rất quan trọng.

4.2. Tối Ưu Hóa Hiệu Suất Chương Trình

Sử dụng con trỏ giúp tối ưu hóa hiệu suất chương trình bằng cách giảm thiểu việc sao chép dữ liệu và cho phép truy cập nhanh hơn đến các biến và cấu trúc dữ liệu.

V. Kết Luận Tương Lai Của Con Trỏ Trong Lập Trình C

Con trỏ là một phần không thể thiếu trong lập trình C++. Việc hiểu và sử dụng con trỏ một cách hiệu quả sẽ giúp lập trình viên phát triển các ứng dụng mạnh mẽ và tối ưu. Tương lai của con trỏ trong C++ vẫn còn nhiều điều thú vị để khám phá.

5.1. Xu Hướng Phát Triển Của Con Trỏ Trong Các Ngôn Ngữ Mới

Nhiều ngôn ngữ lập trình mới đang phát triển các khái niệm tương tự như con trỏ, nhưng với cách tiếp cận an toàn hơn. Việc so sánh và học hỏi từ các ngôn ngữ này sẽ giúp cải thiện kỹ năng lập trình.

5.2. Tầm Quan Trọng Của Con Trỏ Trong Lập Trình Hiện Đại

Con trỏ vẫn giữ vai trò quan trọng trong lập trình hiện đại, đặc biệt trong các ứng dụng yêu cầu hiệu suất cao và quản lý bộ nhớ phức tạp. Việc nắm vững con trỏ sẽ là một lợi thế lớn cho lập trình viên.

11/07/2025
Bai11 contro trong c p1

Trích đoạn nội dung tài liệu

CON TRỎ CƠ BẢN CĐR buổi học • Sau khi học xong buổi học, sinh viên có khả năng: • Hiểu được khái niệm con trỏ, địa chỉ của biến và quản lý các biến trong C++. • Sử dụng con trỏ trong lập trình • Biết được một số thuật ngữ và tiếng Anh tương ứng 2 Bảng các thuật ngữ Việt- Anh liên quan nội dung con trỏ Thuật ngữ tiếng Việt Thuật ngữ tiếng Anh Con trỏ Pointer Hằng con trỏ Constant pointer Địa chỉ bộ nhớ Memory Address Toán tử & Address-of Operator Dereferencing Operator, or: Indirection Toán tử * Operator Cấp phát bộ nhớ Memory Allocation Giải phóng bộ nhớ De-Allocate Memory Cấp phát tĩnh Static Memory Allocation Cấp phát động Dynamic Memory Allocation Biến động Dynamic Variable Phép toán số học trên con trỏ Pointer Arithmetic NMLT - CON TRỎ CƠ BẢN 3 Nội dung 1. Khái niệm và cách sử dụng con trỏ 2. Con trỏ và mảng 1 chiều 3.

Bài tập NMLT - Con trỏ và cấp phát động 4 1. Khái niệm và cách sử dụng 1.1 Biến và vùng nhớ 1.2 Khái niệm con trỏ 1.3 Khai báo con trỏ 1.4 Con trỏ và toán tử &, * 1.5 Con trỏ NULL 1.6 Kích cỡ con trỏ 1.7 Từ khóa const và con trỏ 1.8 Con trỏ và hàm Bài tập Một số lưu ý NMLT - CON TRỎ CƠ BẢN 5 ? Chương trình C/C++ quản lý các biến như thế nào? NMLT - CON TRỎ CƠ BẢN 6 1.1 Biến và vùng nhớ • Bộ nhớ máy tính Địa chỉ 1 byte • Bộ nhớ RAM chứa rất nhiều ô nhớ, ô nhớ 0 mỗi ô nhớ có kích thước 1 byte. 1 2 • Mỗi ô nhớ có địa chỉ duy nhất và địa 3 chỉ này được đánh số từ 0 trở đi. 4 5 • RAM để lưu trữ mã chương trình và 6 dữ liệu trong suốt quá trình thực thi.

… Memory Layout (bytes) NMLT - CON TRỎ CƠ BẢN 7 1.1 Biến và vùng nhớ • Khi khai báo biến, máy tính sẽ dành riêng một vùng nhớ để lưu biến đó. • Khi tên biến được gọi, máy tính sẽ thực hiện 2 bước sau: • Tìm kiếm địa chỉ ô nhớ của biến. • Truy xuất hoặc thiết lập giá trị của biến được lưu trữ tại ô nhớ đó. NMLT - CON TRỎ CƠ BẢN 8 1.1 Biến và vùng nhớ • Ví dụ: Địa chỉ ô nhớ 0 1 x ch 2 3 a int main() { 4 char ch=‘x’; 5 7 int a = 7; 6 } 7.

… Memory Layout (bytes) NMLT - CON TRỎ CƠ BẢN 9 Toán tử & và * • Toán tử & (Address-of Operator) đặt trước tên biến và cho biết địa chỉ của vùng nhớ của biến. • Toán tử * (Dereferencing Operator hay Indirection Operator) đặt trước một địa chỉ và cho biết giá trị lưu trữ tại địa chỉ đó. NMLT - CON TRỎ CƠ BẢN 10 Toán tử & và * int value; 0x50 value value = 3200; 3200 Memory Layout cout << " value = " << value; => value = 3200; cout << " &value = " << &value; => &value = 0x50; cout << " *(&value) = " << *(&value); => *(&value) = 3200; NMLT - CON TRỎ CƠ BẢN 11 1.2 Khái niệm con trỏ • Khái niệm: Con trỏ (Pointer) là một biến lưu trữ địa chỉ của một địa chỉ bộ nhớ. Địa chỉ này thường là địa chỉ của một biến khác.

VD: Biến x chứa địa chỉ của biến y. Vậy ta nói biến x “trỏ tới” y. • Phân loại con trỏ: Con trỏ kiểu int dùng để chứa địa chỉ của các biến kiểu int. Tương tự ta có con trỏ kiểu float, double, … NMLT - CON TRỎ CƠ BẢN 12 1.3 Khai báo con trỏ • Khai báo • Giống như mọi biến khác, biến con trỏ muốn sử dụng cũng cần phải được khai báo.

<kiểu dữ liệu> *<tên biến con trỏ>; • Ví dụ Memory Layout 0x50 char char1; 0x80 char1 int *ptrI; ptrI float *ptrF; 0x10 ptrF NMLT - CON TRỎ CƠ BẢN 13 1.4 Con trỏ và toán tử &, * • Toán tử & dùng trong khởi tạo giá trị cho con trỏ <kiểu dữ liệu> *<tên biến con trỏ> = & <tên biến>; • Ví dụ: 0x34 a 0x90 int a; int *ptr = &a; ptr 0x34 Memory Layout ? double a; int *ptr = &a; NMLT - CON TRỎ CƠ BẢN 14 1.4 Con trỏ và toán tử &, * • Toán tử * đặt trước biến con trỏ cho phép truy xuất đến giá trị ô nhớ mà con trỏ trỏ đến. • Ví dụ int a = 1000; 0x34 int *ptr = &a; a 3201 3200 1000 cout << ptr << “ ” << *ptr; // a = 3200 *ptr = 3200; 0x90 cout << *ptr; ptr 0x34 (*ptr) ++; Memory Layout NMLT - CON TRỎ CƠ BẢN 15 Ví dụ #include <iostream> using namespace std; int main() { int a; int *ptr; int value; a = 3200; ptr = &a; value = --(*ptr); } Memory Layout NMLT - CON TRỎ CƠ BẢN 16 Ví dụ #include <iostream> using namespace std; 0x34 int main() { a 3199 3200 int a; int *ptr; 0x90 int value; ptr 0x34 a = 3200; ptr = &a; 0x50 value = --(*ptr); value 3199 } Memory Layout NMLT - CON TRỎ CƠ BẢN 17 Ví dụ value = 3199 ptr = 0x34 0x34 a = 3199 a 3199 &value = 0x50 &ptr = 0x90 0x90 &a = 0x34 ptr 0x34 *ptr = 3199 0x50 &(*ptr) = 0x34 value 3199 *(*ptr) = error *(&(*ptr)) = 3199 Memory Layout NMLT - CON TRỎ CƠ BẢN 18 Phép gán con trỏ • Có thể gán biến con trỏ: int *p1, *p2; p2 = p1; Þ Gán một con trỏ cho con trỏ khác Þ “Chỉ định p2 trỏ tới nơi mà p1 đang trỏ tới“ Dễ bị lẫn với: *p2 = *p1; Þ Gán “giá trị trỏ bởi p1” cho “giá trị trỏ bởi p2” NMLT - CON TRỎ CƠ BẢN 19 Ví dụ p1 27 p1 27 p1 = p2 p2 5 p2 5 p1 27 p1 5 *p1 = *p2 p2 5 p2 5 NMLT - CON TRỎ VÀ CẤP PHÁT ĐỘNG 20 1.5 Con trỏ NULL • Khái niệm • Con trỏ NULL là con trỏ không trỏ vào đâu cả. • Khác với con trỏ chưa được khởi tạo. int n; int *p1 = &n; int *p2; // unreferenced local variable int *p3 = NULL; NULL NMLT - CON TRỎ CƠ BẢN 21 1.6 Toán tử sizeof • Để xác định kích thước (bytes) của một kiểu dữ liệu ta dùng toán tử sizeof.

Cú pháp: sizeof (type) hoặc sizeof value Trong đó type là kiểu dữ liệu, value là tên biến • Kích thước của kiểu dữ liệu không giống nhau cho tất cả máy tính. Nên dùng toán tử sizeof để biết chính xác kích thước của dữ liệu. • Con trỏ chỉ lưu địa chỉ nên kích thước của mọi con trỏ là như nhau. (Kết quả sau mang tính chất tham khảo) int a; sizeof a = 4 sizeof(int) = 4 double b; sizeof(b) = 8 sizeof(double) = 8 char c; sizeof(c) = 1 sizeof(char) = 1 int *pa; sizeof pa = 4 sizeof(int*) = 4 double *pb; sizeof pb = 4 sizeof(double*)= 4 char *pc; sizeof(pc)= 4 sizeof(char*) = 4 NMLT - CON TRỎ CƠ BẢN 22 1.7 Từ khóa const và con trỏ • Hằng số dùng trong khai báo một biến cho biết giá trị của biến không được phép thay đổi trong quá trình thực hiện chương trình.

• Tùy thuộc vào vị trí đặt từ khóa const dùng trong khái báo biến con trỏ, mà quy định giá trị hằng cho con trỏ hay cho vùng nhớ con trỏ trỏ tới. • Có 3 trường hợp trong khai báo biến con trỏ và từ khóa const. NMLT - CON TRỎ CƠ BẢN 23 Từ khóa const và con trỏ • Ví dụ: int x; // non-const pointer to non-const int int * p1 = &x; // non-const pointer to const int const int * p2 = &x; // const pointer to non-const int int * const p3 = &x; // const pointer to const int const int * const p4 = &x; NMLT - CON TRỎ CƠ BẢN 24 Bài tập • Tìm lỗi sai trong đoạn code sau: int a = 12; int a1 = 9; int * const pa = &a; pa = &a1; const int * pb = &a; *pb = a1; const int * const pc = &a; (*pc) = a1; NMLT - CON TRỎ CƠ BẢN 25 1.7 Con trỏ và hàm • Xét ví dụ sau: Hãy viết hàm để nhập giá trị cho 1 biến. Cách viết nội dung hoàn toàn ở hàm main như sau: int main() { int a; cout << "Nhap gia tri vao"; cin >> a; cout << a; 0x50 } a NMLT - CON TRỎ CƠ BẢN 26 1.7 Con trỏ và hàm // Cách 1: int NhapGiaTri(){ int b; 0x50 cout << "Nhap gia tri vao"; a cin >> b; return b; int NhapGiaTri() } 0x100 int main() { b int a; 5 a = NhapGiaTri(); cout << a; } NMLT - CON TRỎ CƠ BẢN 27 1.7 Con trỏ và hàm // Cách 2 void NhapGiaTri(int *b) { cout << "Nhap gia tri vao"; cin >> *b; } int main() { int a; NhapGiaTri(&a); cout << a; } NMLT - CON TRỎ CƠ BẢN 28 1.7 Con trỏ và hàm // Cách 3 void NhapGiaTri(int &b) { cout << "Nhap gia tri vao"; cin >> b; } int main() { int a; NhapGiaTri(a); cout << a; } NMLT - CON TRỎ CƠ BẢN 29 Bài tập 1 • Tìm lỗi sai trong đoạn chương trình sau: int main() { int x, *p; x = 10; *p = x; return 0; } NMLT - CON TRỎ CƠ BẢN 30 Bài tập 2 Dùng C++ viết một đoạn #include <iostream> chương trình với 2 biến: using namespace std; + Biến i có kiểu int với giá trị khởi đầu là 12 int main() { + Biến p1 là một con trỏ int i = 12; trỏ tới vùng nhớ kiểu int.

int *p1; // i = 24; ? Hãy dùng biến p1 để thay p1 = &i; đổi giá trị của biến i từ 12 *p1 = 24; sang 24. cout << *p1 << " " << i << endl; } NMLT - CON TRỎ CƠ BẢN 31 Bài tập 3 • Hãy viết hàm hoán đổi giá trị của 2 tham số • Giải: // Cách 1 //Cách 2 void Swap(int *a, int *b) { void Swap(int &a, int &b) { int temp = *b; int temp = b; *b = *a; b = a; *a = temp; a = temp; } } int main() { int main() { int x=7, y=8; int x=7, y=8; Swap(&x, &y); Swap(x, y); cout << "x= "<< x << ", cout << "x= "<< x << ", y= " << y; y= " << y; } } NMLT - CON TRỎ CƠ BẢN 32 Một số lưu ý • Con trỏ là khái niệm quan trọng và khó nhất trong C++. Mức độ thành thạo C++ được đánh giá qua mức độ sử dụng con trỏ. • Nắm rõ quy tắc sau, ví dụ int a, *pa = &a; • *pa và a đều chỉ nội dung của biến a.

• pa và &a đều chỉ địa chỉ của biến a.

Nội dung được bảo vệ bản quyền — Tải xuống đầy đủ

Tài liệu "Khám Phá Con Trỏ Cơ Bản Trong C++" cung cấp một cái nhìn tổng quan về khái niệm con trỏ trong ngôn ngữ lập trình C++. Nó giải thích cách thức hoạt động của con trỏ, cách khai báo và sử dụng chúng, cũng như những lợi ích mà con trỏ mang lại cho lập trình viên, như quản lý bộ nhớ hiệu quả và khả năng thao tác với dữ liệu một cách linh hoạt. Đọc tài liệu này, bạn sẽ nắm vững các khái niệm cơ bản và có thể áp dụng chúng vào các dự án lập trình thực tế.

Nếu bạn muốn mở rộng kiến thức của mình về con trỏ và lập trình C++, hãy tham khảo tài liệu Tổng hợp các bài tập môn kĩ thuật lập trình, nơi bạn có thể tìm thấy các bài tập thực hành hữu ích. Ngoài ra, tài liệu Bai12 contro trong c p2 sẽ giúp bạn hiểu rõ hơn về sự khác biệt giữa con trỏ và việc cấp phát động trong C. Những tài liệu này sẽ là cơ hội tuyệt vời để bạn đào sâu hơn vào chủ đề và nâng cao kỹ năng lập trình của mình.