Con trỏ
Trong chương trước, các biến đã được giải thích là vị trí trong bộ nhớ của máy tính mà có thể được truy cập bằng cách định danh của họ (tên của họ). Bằng cách này, các chương trình không cần quan tâm đến các địa chỉ vật lý của dữ liệu trong bộ nhớ; nó chỉ đơn giản là sử dụng từ định bất cứ khi nào nó cần phải tham khảo các biến. Đối với một chương trình C ++, bộ nhớ của máy tính giống như một chuỗi các tế bào bộ nhớ, mỗi một byte trong kích thước, và từng có một địa chỉ duy nhất. Những tế bào bộ nhớ single-byte được đặt hàng trong một cách mà cho phép trình bày dữ liệu lớn hơn một byte để chiếm các tế bào bộ nhớ có địa chỉ liên tiếp. Bằng cách này, mỗi tế bào có thể được dễ dàng nằm trong bộ nhớ bằng địa chỉ duy nhất của nó. Ví dụ, các tế bào bộ nhớ với địa chỉ 1776 luôn theo ngay sau khi các tế bào với địa chỉ 1775 và đi trước một với năm 1777, và là chính xác một ngàn tế bào sau khi 776 và chính xác một ngàn tế bào trước 2776. Khi một biến được khai báo, các bộ nhớ cần thiết để lưu trữ giá trị của nó được gán một địa điểm cụ thể trong bộ nhớ (địa chỉ bộ nhớ của nó). Nói chung, các chương trình C ++ không chủ động quyết định các địa chỉ bộ nhớ chính xác nơi các biến của nó được lưu trữ. May mắn thay, nhiệm vụ này là trái với các môi trường mà chương trình được chạy - nói chung, một hệ điều hành mà quyết định các vị trí nhớ đặc biệt vào thời gian chạy. Tuy nhiên, nó có thể hữu ích cho một chương trình để có thể có được địa chỉ của một biến trong thời gian chạy để truy cập vào các tế bào dữ liệu mà đang ở một vị trí tương đối nhất định với nó. Địa chỉ-nhà điều hành (&) Địa chỉ của một biến thể thể thu được bằng cách đặt trước tên của một biến với một dấu và (&), được biết đến như là địa chỉ của nhà điều hành. Ví dụ: foo = & myvar; này sẽ gán địa chỉ của biến myvar để foo; bằng cách đặt trước tên của myvar biến với địa chỉ của nhà điều hành (&), chúng ta không còn gán nội dung của biến đó để foo, nhưng địa chỉ của nó. Các địa chỉ thực của một biến trong bộ nhớ có thể không được biết đến trước khi thời gian chạy, nhưng chúng ta hãy giả định, để giúp làm rõ một số khái niệm, myvar được đặt trong thời gian chạy trong các địa chỉ bộ nhớ năm 1776. Trong trường hợp này, hãy xem xét các đoạn mã sau: 1 2 3 myvar = 25; foo = & myvar; bar = myvar; Các giá trị chứa trong mỗi biến sau khi thực hiện điều này được thể hiện trong sơ đồ sau đây:. Đầu tiên, chúng ta gán giá trị 25 để myVar (một biến có địa chỉ trong bộ nhớ chúng ta giả định là 1776) Các câu lệnh thứ hai gán foo địa chỉ của myvar , mà chúng ta đã giả định là năm 1776. Cuối cùng, câu lệnh thứ ba, gán giá trị chứa trong myvar đến quán bar. Đây là một hoạt động chuyển nhượng tiêu chuẩn, như đã được thực hiện nhiều lần trong các chương trước. Sự khác biệt chính giữa các báo cáo thứ hai và thứ ba là sự xuất hiện của các địa chỉ của các nhà điều hành (&). Các biến lưu trữ địa chỉ của một biến khác (như foo trong ví dụ trước) là gì trong C ++ được gọi là một con trỏ. Con trỏ là một tính năng rất mạnh của ngôn ngữ mà có nhiều công dụng trong lập trình cấp thấp hơn. Một lát sau, chúng tôi sẽ xem làm thế nào để khai báo và sử dụng con trỏ. Toán tử tham chiếu (*) Như vừa thấy, một biến mà các cửa hàng địa chỉ của một biến khác được gọi là một con trỏ. Con trỏ được cho là "điểm đến" biến mà địa chỉ của họ lưu trữ. Một tính chất thú vị của con trỏ là chúng có thể được sử dụng để truy cập các biến mà nó trỏ tới trực tiếp. Điều này được thực hiện bằng cách đặt trước tên con trỏ với các toán tử tham chiếu (*). Các nhà điều hành chính nó có thể được đọc là "giá trị được trỏ đến bởi". Vì vậy, sau đây với các giá trị của các ví dụ trước, các phát biểu sau đây: baz = * foo; Điều này có thể được đọc như: "baz bằng giá trị được trỏ đến bởi foo" , và tuyên bố sẽ thực sự gán giá trị 25 để Baz, kể từ foo là năm 1776, và các giá trị được trỏ đến bởi năm 1776 (sau đây ví dụ trên) sẽ là 25. Điều quan trọng là phải phân biệt rõ ràng foo mà đề cập đến giá trị năm 1776, trong khi * foo (với một dấu * trước tên) đề cập đến các giá trị được lưu trữ tại địa chỉ 1776, mà trong trường hợp này là 25. Chú ý sự khác biệt của bao gồm hoặc không bao gồm các toán tử tham chiếu (Tôi đã thêm một lời chú thích của từng người trong số này hai biểu thức có thể đọc được): 1 2 baz = foo; // Baz bằng foo (1776) baz = * foo; // Baz bằng giá trị được trỏ đến bởi foo (25) Các toán tử tham chiếu và tới đích là như vậy, bổ sung: & là địa chỉ của nhà điều hành, và có thể được đọc đơn giản là "địa chỉ của" * là toán tử tham chiếu, và có thể được đọc là "giá trị được trỏ đến bởi". Vì vậy, họ có loại ngược lại ý nghĩa: Một địa chỉ thu được và có thể được dereferenced với * Trước đó, chúng tôi thực hiện hai hoạt động phân cấp như sau: 1 2 myvar = 25; foo = & myvar; Ngay sau khi những hai báo cáo, tất cả các biểu thức sau đây sẽ cung cấp cho đúng kết quả: 1 2 3 4 myvar == 25 & myvar == 1776 foo == 1776 * foo == 25 Những biểu hiện đầu tiên là khá rõ ràng, xem xét rằng các hoạt động chuyển nhượng thực hiện trên myvar là myvar = 25. Điều thứ hai sử dụng các địa chỉ của các nhà điều hành (&), trả về địa chỉ của myvar, mà chúng tôi cho rằng nó có một giá trị của năm 1776. Người thứ ba là phần nào rõ ràng, từ biểu thức thứ hai là sự thật và các hoạt động chuyển nhượng thực hiện trên foo là foo = & myvar. Các biểu hiện thứ tư sử dụng các toán tử tham chiếu (*) có thể được đọc là "giá trị được trỏ đến bởi", và các giá trị được trỏ đến bởi foo thực sự là 25. Vì vậy, sau khi tất cả điều đó, bạn cũng có thể suy ra rằng càng lâu càng địa chỉ trỏ đến bởi foo vẫn không thay đổi, các biểu hiện sau đây cũng sẽ là sự thật: * foo == myvar Khai báo con trỏ Do khả năng của một con trỏ để trực tiếp tham khảo các giá trị mà nó trỏ tới, một con trỏ có đặc tính khác nhau khi nó trỏ tới một char hơn khi nó trỏ tới một int hay float. Khi dereferenced, các loại cần phải được biết đến. . Và cho rằng, tuyên bố của một con trỏ cần phải bao gồm các kiểu dữ liệu con trỏ sẽ trỏ đến Tuyên bố của các con trỏ sau này cú pháp: loại * Tên; trong đó type là kiểu dữ liệu được trỏ đến bởi con trỏ. Loại này không phải là kiểu của con trỏ chính nó, nhưng các kiểu dữ liệu con trỏ trỏ tới. Ví dụ: 1 2 3 int * số; char * nhân vật; double * thập phân; Đây là ba khai báo của con trỏ. Mỗi người được dự định để trỏ đến một kiểu dữ liệu khác nhau, nhưng, trên thực tế, tất cả chúng đều là con trỏ và tất cả chúng có khả năng sẽ chiếm cùng một lượng không gian trong bộ nhớ (kích thước trong bộ nhớ của một con trỏ tùy thuộc vào nền tảng nơi mà các chương trình chạy). Tuy nhiên, những dữ liệu mà chúng trỏ tới không chiếm cùng một lượng không gian cũng không phải là cùng loại: một trong những điểm đầu tiên để một int, điều thứ hai đến một char, và là người cuối cùng một đôi. Vì vậy, mặc dù ba biến ví dụ là tất cả chúng con trỏ, họ thực sự có nhiều loại khác nhau: int *, char *, và đôi * tương ứng, tùy thuộc vào loại chúng trỏ đến. Lưu ý rằng các dấu hoa thị (*) được sử dụng khi khai báo một con trỏ chỉ có nghĩa là nó là một con trỏ (nó là một phần của các loại hợp chất đặc tả của nó), và không nên nhầm lẫn với các toán tử tham chiếu nhìn thấy sớm hơn một chút, nhưng mà cũng được viết với một dấu sao (*). Họ chỉ đơn giản là hai việc khác nhau đại diện cho cùng một dấu. Chúng ta hãy xem một ví dụ về con trỏ: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // con trỏ đầu tiên của tôi #include
using namespace std; int main () {int firstvalue, secondvalue; int * mypointer; mypointer = & firstvalue; * mypointer = 10; mypointer = & secondvalue; * mypointer = 20; cout << "firstvalue là" << firstvalue << ' n '; cout << "secondvalue là" << secondvalue <<' n '; return 0;} firstvalue là 10 secondvalue là 20 Chỉnh sửa & Run Chú ý rằng mặc dù cả hai firstvalue cũng không secondvalue được trực tiếp đặt bất kỳ giá trị trong chương trình, cả hai kết thúc với một giá trị thiết lập một cách gián tiếp thông qua việc sử dụng các mypointer. Đây là cách nó xảy ra: Thứ nhất, mypointer được gán địa chỉ của firstvalue bằng cách sử dụng địa chỉ của nhà điều hành (&). Sau đó, các giá trị được trỏ đến bởi mypointer được gán giá trị là 10. Bởi vì, tại thời điểm này, mypointer đang trỏ đến vị trí nhớ của firstvalue, điều này trong thực tế thay đổi giá trị của firstvalue. Để chứng minh rằng một con trỏ có thể trỏ đến các biến khác nhau trong suốt cuộc đời của mình trong một chương trình, ví dụ lặp đi lặp lại quá trình với secondvalue và rằng cùng một con trỏ, mypointer. Dưới đây là một ví dụ một chút lập hơn: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 // more pointers #include
using namespace std; int main () {int firstvalue = 5, secondvalue = 15; int * p1, * p2; p1 = & firstvalue; // P1 = địa chỉ của firstvalue p2 = & secondvalue; // P2 = địa chỉ của secondvalue * p1 = 10; // Giá trị được trỏ đến bởi p1 = 10 * p2 = * p1; // Giá trị được trỏ đến bởi p2 = giá trị trỏ đến bởi p1 p1 = p2; // P1 = p2 (giá trị của con trỏ được sao chép) * p1 = 20; // Giá trị được trỏ đến bởi p1 = 20 cout << "firstvalue là" << firstvalue << ' n'; cout << "secondvalue là" << secondvalue << ' n'; return 0;} firstvalue là 10 secondvalue là 20 Chỉnh sửa & Run Mỗi hoạt động chuyển nhượng bao gồm một lời nhận xét về cách mỗi dòng có thể được đọc:. tức là, thay thế ký hiệu (&) bởi "địa chỉ của", và dấu hoa thị (*) bằng "giá trị được trỏ đến bởi" Chú ý rằng có biểu thức với các con trỏ p1 và p2, cả hai có và không có các toán tử tham chiếu (*). Ý nghĩa của một biểu thức bằng cách sử dụng toán tử tham chiếu (*) là rất khác nhau từ một trong những điều đó không. Khi điều hành này trước tên biến con trỏ, biểu đề cập đến những giá trị đang được chỉ, trong khi khi một tên con trỏ xuất hiện mà không điều hành này, nó đề cập đến giá trị của con trỏ chính nó (ví dụ, địa chỉ của những gì con trỏ đang trỏ tới). Một điều mà có thể bạn chú ý là dòng: int * p1, * p2; này khai báo hai con trỏ được sử dụng trong ví dụ trước. Nhưng cần chú ý rằng có một dấu sao (*) cho mỗi con trỏ, để cho cả hai để có
đang được dịch, vui lòng đợi..
