Bài giảng Kỹ thuật lập trình hệ cơ điện tử: Chương 6 - Con trỏ và mảng Khái niệm ngôn ngữ lập trình C/C++; Khai báo mảng trong C/C++; Khởi tạo mảng trong C/C++; Con trỏ tới một mảng trong C++; Truyền mảng như là các tham số hàm trong C++;... Mời các bạn cùng tham khảo bài giảng!
Trang 21. T ng quan v ngôn ng l p trìnhổ ề ữ ậ
2. Gi i thi u s b ngôn ng Cớ ệ ơ ộ ữ
3. Ki u, toán t và bi u th c ể ử ể ứ
Trang 3CH ƯƠ NG 6. Con tr và m ng ỏ ả
6.1 Khái ni m v m ng ệ ề ả
6.2 Khái ni m v con tr ệ ề ỏ
Trang 4Khái ni m v m ng ệ ề ả
1.1 Khái ni m ệ
§ Ngôn ngữ lập trình C/C++ cung cấp cấu trúc dữ liệu gọi là
mảng, được lưu trữ trong một tập hợp các dữ liệu cùng kiểu
với độ dài cố định Một mảng được sử dụng để lưu trữ tập hợp
dữ liệu.
§ Thay vì khai báo biến một cách rời rạc, như biến so0, so1,…
và so99, bạn có thể khai báo một mảng các giá trị như so[0], so[1] và … so[99] để biểu diễn các giá trị riêng biệt Một thành viên cụ thể của mảng có thể được truy cập qua index (chỉ số).
§ Tất cả mảng đều bao gồm các vị trí nhớ liền kề nhau Địa chỉ
Trang 5§ Đây là mảng một chiều Kich_co_mang phải là một số nguyên lớn hơn 0 và Kieu phải hợp lệ trong ngôn ngữ
C/C++ Ví dụ, khai báo một mảng 10 phần tử gọi là balance với kiểu double, sử dụng câu lệnh sau đây:
double balance[ 10 ];
Trang 6Khái ni m v m ng ệ ề ả
1.3 Kh i t o m ng trong C/C++ ở ạ ả
§ Bạn có thể khởi tạo mảng trong C/C++ hoặc từng phần
tử một hoặc sử dụng một câu lệnh như dưới đây:
§ Số lượng các giá trị trong dấu ngoặc kép {} không được lớn hơn số lượng phần tử khai báo trong dấu ngoặc vuông []
Trang 7Khái ni m v m ng ệ ề ả
1.3 Kh i t o m ng trong C/C++ ở ạ ả
được khởi tạo: Bạn sẽ tạo chính xác một chuỗi có giá trị giống hệt chuỗi bên trên bằng cách gán từng phần tử một Dưới đây là một ví
dụ khi gán giá trị cho một phần tử của mảng:
là chỉ số cơ bản và phần tử cuối cùng của mảng có chỉ số bằng độ lớn của mảng trừ đi 1 Dưới đây là cách biểu diễn hình họa cho chuỗi khai báo bên trên thông qua chỉ số:
Trang 8Khái ni m v m ng ệ ề ả
1.3 Truy c p các ph n t m ng trong C/C++ ậ ầ ử ả
§ Một mảng được truy cập bởi cách đánh chỉ số trong tên của mảng Dưới đây là một cách truy cập một giá trị của mảng:
§ Câu lệnh trên lấy phần tử thứ 56 của mảng và gán giá trị này cho biến hocphi
Trang 99Khái ni m v m ng ệ ề ả
Ví dụ
Trang 11§ Ở đây, kieu_du_lieu có thể là bất kỳ kiểu dữ liệu có hiệu
lực nào và ten_mang sẽ là một định danh C++ có hiệu lực
Trang 12Khái ni m v m ng ệ ề ả
M ng hai chi u trong C++ ả ề
§ Một mảng hai chiều có thể như là một bảng mà có x hàng
và y cột Một mảng hai chiều a chứa 3 hàng và 4 cột có thể được hiển thị như sau:
Trang 13Khái ni m v m ng ệ ề ả
Kh i t o m ng hai chi u trong C++ ở ạ ả ề
§ Các mảng đa chiều có thể được khởi tạo bởi xác định các giá trị trong dấu móc vuông cho mỗi hàng Sau đây là một hàng với 3 hàng và mỗi hàng chứa 4 cột
§ Các dấu ngoặc ôm, mà chỉ các hàng giá trị là tùy ý Khởi tạo sau là tương đương với ví dụ trên:
Trang 14Khái ni m v m ng ệ ề ả
Truy c p các ph n t c a m ng hai chi u trong C++ ậ ầ ử ủ ả ề
§ Các phần tử mảng hai chiều được truy cập bởi sử dụng các chỉ số, ví dụ chỉ số hàng và chỉ số cột Ví dụ:
§ Lệnh trên sẽ truy cập vào phần tử thứ 4 từ hàng thứ 3 của mảng Bạn có thể kiểm tra lại nó trong sơ đồ trên
Trang 1515Khái ni m v m ng ệ ề ả
Ví dụ
Trang 16Khái ni m v m ng ệ ề ả
1.5 Con tr t i m t m ng trong C++ ỏ ớ ộ ả
§ Một tên mảng là một con trỏ hằng số tới phần tử đầu tiên của mảng Vì thế, trong khai báo:
§ phithuebao là một con trỏ tới &phithuebao[0], mà là địa
chỉ của phần tử đầu tiên của mảng phithuebao Do vậy,
đoạn chương trình sau gán p địa chỉ của phần tử đầu tiên của phithuebao:
Trang 17Khái ni m v m ng ệ ề ả
1.5 Con tr t i m t m ng trong C++ ỏ ớ ộ ả
§ Sử dụng các tên mảng như là các con trỏ hằng số là hợp
lệ, và ngược lại Vì thế, *(phithuebao + 4) là cách chính thống để truy cập dữ liệu tại phithuebao[4]
§ Một khi bạn lưu địa chỉ của phần tử đầu tiên trong p, bạn
có thể truy cập các phần tử mảng bởi sử dụng *p, *(p+1),
*(p+2), … Dưới đây là ví dụ để chỉ tất cả các khái niệm được đề cập ở trên:
Trang 18Khái ni m v m ng ệ ề ả
Ví dụ
Trang 19Khái ni m v m ng ệ ề ả
1.6 Truy n m ng nh là các tham s hàm trong C++ ề ả ư ố
§ C++ không cho phép truyền cả một mảng như là một tham số tới một hàm Tuy nhiên, bạn có thể truyền một con trỏ tới một mảng bởi việc xác định tên mảng đó mà không cần một chỉ mục
§ Nếu bạn muốn truyền một mảng một chiều như là tham
số trong một hàm, bạn sẽ phải khai báo tham số chính thức của hàm theo một trong 3 cách sau và tất cả 3 cách thức khai báo này đều tạo kết quả giống nhau bởi vì, mỗi cách thức sẽ nói cho bộ biên dịch rằng một con trỏ integer sẽ được nhận
Trang 20Khái ni m v m ng ệ ề ả
Cách 1
§ Các tham số chính thức dưới dạng một con trỏ, như sau:
Trang 21Khái ni m v m ng ệ ề ả
Cách 2
§ Các tham số chính thức dưới dạng một mảng đã định kích cỡ, như sau:
Trang 22Khái ni m v m ng ệ ề ả
Cách 3
§ Các tham số chính thức dưới dạng một mảng chưa định kích cỡ, như sau:
Trang 2323Khái ni m v m ng ệ ề ả
Ví dụ
Trang 24Khái ni m v m ng ệ ề ả
Ví dụ
Trang 25§ Nếu bạn muốn trả về một mảng một chiều từ một hàm, bạn sẽ phải khai báo một hàm trả về một con trỏ như trong ví dụ sau:
Trang 2727Khái ni m v m ng ệ ề ả
Ví dụ
Trang 28Khái ni m v m ng ệ ề ả
Ví dụ
Trang 29C /C++ hoàn thiện Bây giờ hãy bắt đầu bằng những bước đơn giản nhất.
§ Như bạn biết, mỗi biến trong một vùng nhớ nhất định và mỗi vùng nhớ này có địa chỉ có nó được định nghĩa để dễ dàng trong việc truy cập sử dụng toán tử (&) tương ứng với địa chỉ của nó trong bộ nhớ
Trang 30Khái ni m v con tr ệ ề ỏ
2.1 Khái ni m ệ
Trang 31Khái ni m v con tr ệ ề ỏ
2.2 Con tr là gì? ỏ
§ Một con trỏ là một biến mà trong đó giá trị của nó là địa chỉ
của biến khác Ví dụ như địa chỉ của vùng nhớ Giống như các biến và hằng số, bạn phải khai báo con trỏ trước khi bạn có thể sử dụng nó để lưu trữ bất kì địa chỉ của biến nào Dạng tổng quát của việc khai báo con trỏ như sau:
§ Ở đây, kieu_du_lieu là kiểu dữ liệu cơ bản con trỏ, nó là kiểu hợp lệ trong ngôn ngữ C và ten_bien là tên giá trị của con trỏ
Phần ký tự * sử dụng trong khai báo con trỏ giống như việc bạn sử dụng cho phép nhân Mặc dù vậy, trong khai báo này,
ký tự * được thiết kế để sử dụng các biến của con trỏ.
Trang 32Khái ni m v con tr ệ ề ỏ
2.2 Con tr là gì? ỏ
§ Dưới đây là một số cách khai báo hợp lệ của con trỏ:
§ Kiểu dữ liệu thực sự của giá trị của tất cả các con trỏ, có thể là integer, float, character, hoặc kiểu khác, là giống như, một số long hexa biểu diễn một địa chỉ bộ nhớ Điểm khác nhau duy nhất của các con trỏ của các kiểu
Trang 33a) chúng ta định nghĩa biến con trỏ,
b) gán địa chỉ của biến đến một con trở và
c) cuối cùng truy cập các giá trị biến địa chỉ trong biến con
trỏ
Điều này được thực hiện bởi toán tử * trả về giá trị các các biến chứa trong địa chỉ được xác định bởi toán tử này Dưới đây là các sử dụng những phép toán trên:
Trang 34Khái ni m v con tr ệ ề ỏ
Ví dụ
Trang 35gán NULL được gọi là một con trỏ null.
§ Con trỏ NULL là một hằng với một giá trị là 0 được định
nghĩa trong một vài thư viện chuẩn, gồm iostream.
Trang 36Khái ni m v con tr ệ ề ỏ
Ví dụ
Trang 38Khái ni m v con tr ệ ề ỏ
2.5 Con tr s h c trong C/C++ ỏ ố ọ
§ Như đã giải thích trong chương chính, con trỏ trong C/C++ là một địa chỉ, mà là một giá trị số Vì thế, bạn có thể thực hiện các hoạt động số học trên một con trỏ như khi bạn thực hiện với giá trị số Có 4 toán tử số học mà có thể được sử dụng trên các con trỏ: ++, , +, và -
§ Để hiểu con trỏ số học, chúng ta giả sử rằng contro là một con trỏ nguyên mà trỏ tới 1000 địa chỉ Giả sử số nguyên là 32 bit, chúng ta thực hiện thao tác số học trên
Trang 39Khái ni m v con tr ệ ề ỏ
Tăng m t Con tr trong C/C++ ộ ỏ
§ Chúng ta ưa thích sử dụng một con trỏ trong chương trình thay vì sử dụng một mảng bởi vì con trỏ biến có thể tăng, không giống như tên mảng, không thể tăng được, bởi vì nó là một con trỏ hằng số Chương trình sau tăng con trỏ biến để truy cập tới mỗi phần tử của mảng:
Trang 40Khái ni m v con tr ệ ề ỏ
Trang 4141Khái ni m v con tr ệ ề ỏ
Gi m m t Con tr trong C/C++ ả ộ ỏ
Trang 42§ Chương trình sau chỉnh sửa ví dụ trước bởi tăng con trỏ biến để mà địa chỉ mà nó trỏ tới nhỏ hơn hoặc bằng địa chỉ của phần tử cuối cùng của mảng, là &var[MAX - 1]:
Trang 4343Khái ni m v con tr ệ ề ỏ
So sánh Con tr trong C/C++ ỏ
Trang 44Khái ni m v con tr ệ ề ỏ
2.6 Con tr và M ng trong C++ ỏ ả
§ Con trỏ và Mảng có mối liên hệ chặt chẽ Thực tế, con trỏ
và mảng là có thể thay thế cho nhau trong một số trường hợp Ví dụ, một con trỏ mà trỏ tới phần đầu mảng có thể truy cập mảng đó bởi sử dụng: hoặc con trỏ số học hoặc chỉ mục mảng Bạn xét ví dụ sau:
Trang 4545Khái ni m v con tr ệ ề ỏ
2.6 Con tr và M ng trong C++ ỏ ả
Trang 46Khái ni m v con tr ệ ề ỏ
2.6 Con tr và M ng trong C++ ỏ ả
§ Tuy nhiên, con trỏ và mảng không hoàn toàn thay thế được cho nhau Ví dụ, bạn xét chương trình sau:
Trang 47Khái ni m v con tr ệ ề ỏ
2.6 Con tr và M ng trong C++ ỏ ả
§ Việc áp dụng toán tử con trỏ * tới biến mang là hoàn hảo,
nhưng nó không hợp lệ khi sửa đổi giá trị biến mang Lý
do là biến mang là một constant mà trỏ tới phần đầu mảng và không thể được sử dụng như là l-value
§ Bởi vì, một tên mảng tạo một hằng con trỏ, nó có thể vẫn được sử dụng trong các biểu thức con trỏ, miễn là nó không bị sửa đổi Ví dụ sau là một lệnh hợp lệ mà gán mang[2] giá trị 500
Lệnh trên là hợp lệ và sẽ biên dịch thành công bởi vì mang
không bị thay đổi
Trang 49Khái ni m v con tr ệ ề ỏ
2.7 M ng các con tr trong C++ ả ỏ
§ Có một tình huống khi chúng ta muốn duy trì một mảng,
mà có thể lưu giữ các con trỏ tới một kiểu dữ liệu int hoặc char hoặc bất kỳ kiểu nào khác Sau đây là khai báo một mảng của các con trỏ tới một integer:
§ Nó khai báo contro như là một mảng các con trỏ MAX
kiểu integer Vì thế, mỗi phần tử trong contro, bây giờ giữ một con trỏ tới một giá trị int Ví dụ sau sử dụng 3 số integer, mà sẽ được lưu giữ trong một mảng các con trỏ như sau:
Trang 50Khái ni m v con tr ệ ề ỏ
2.7 M ng các con tr trong C++ ả ỏ
Trang 51Khái ni m v con tr ệ ề ỏ
2.7 M ng các con tr trong C++ ả ỏ
§ Bạn có thể sử dụng một mảng các con trỏ tới ký tự để lưu giữ một danh sách các chuỗi như sau:
Trang 52Khái ni m v con tr ệ ề ỏ
2.8 Con tr t i con tr trong C++ ỏ ớ ỏ
§ Một con trỏ tới một con trỏ là một form không định hướng hoặc một chuỗi con trỏ Thông thường, một con trỏ chứa địa chỉ của một biến Khi chúng ta định nghĩa một con trỏ tới một con trỏ, con trỏ đầu tiên chứa địa chỉ của con trỏ thứ hai, mà trỏ tới vị trí mà chứa giá trị thực sự như hiển thị trong sơ đồ dưới đây:
Trang 53Khái ni m v con tr ệ ề ỏ
2.8 Con tr t i con tr trong C++ ỏ ớ ỏ
§ Một biến, mà là một con trỏ tới một con trỏ, phải được khai báo Điều này được thực hiện bởi việc đặt một dấu sao (*) ở trước tên của nó Ví dụ, sau đây là khai báo một con trỏ tới một con trỏ trong kiểu int:
§ Khi một giá trị mục tiêu được trỏ không định hướng bởi một con trỏ tới một con trỏ, truy cập giá trị đó yêu cầu rằng toán tử dấu sao được áp dụng hai lần, như dưới ví dụ:
Trang 54Khái ni m v con tr ệ ề ỏ
2.8 Con tr t i con tr trong C++ ỏ ớ ỏ
Trang 55Khái ni m v con tr ệ ề ỏ
2.9 Truy n con tr t i hàm trong C++ ề ỏ ớ
§ C++ cho phép bạn truyền một con trỏ tới một hàm Để làm điều này, đơn giản bạn chỉ cần khai báo tham số hàm như ở dạng một kiểu con trỏ
§ Ở ví dụ đơn giản dưới đây, chúng ta truyền một con trỏ unsigned long tới một hàm và thay đổi giá trị bên trong hàm, mà phản chiếu trở lại trong khi gọi hàm:
Trang 56Khái ni m v con tr ệ ề ỏ
2.9 Truy n con tr t i hàm trong C++ ề ỏ ớ
Trang 57Khái ni m v con tr ệ ề ỏ
2.9 Truy n con tr t i hàm trong C++ ề ỏ ớ
§ Hàm, mà có thể chấp nhận một con trỏ, cũng có thể chấp nhận một mảng như ví dụ sau:
Trang 58Khái ni m v con tr ệ ề ỏ
2.9 Truy n con tr t i hàm trong C++ ề ỏ ớ
Trang 59§ Điều thứ hai cần ghi nhớ là, nó không là ý kiến tốt để trả
về địa chỉ của một biến cục bộ tới ngoại vi của một hàm,
vì thế bạn sẽ phải định nghĩa biến cục bộ như là biến static
Trang 60Khái ni m v con tr ệ ề ỏ
2.10 Tr v con tr t hàm trong C++ ả ề ỏ ừ
§ Bây giờ, giả sử hàm sau sẽ tạo 10 số ngẫu nhiên và trả
về chúng bởi sử dụng một tên mảng mà biểu diễn một con trỏ, ví dụ, địa chỉ đầu tiên của phần tử mảng đầu tiên
Trang 6161Khái ni m v con tr ệ ề ỏ
2.10 Tr v con tr t hàm trong C++ ả ề ỏ ừ