Xin chào, và chào mừng trở lại.
Trong bài giảng này, tôi muốn nói về một khái niệm được gọi là truyền qua tham chiếu.
Khi chúng ta lần đầu tiên bắt đầu nói về con trỏ, tôi đã đề cập đến một trong những lợi
thế là bạn không cần phải sử dụng nhiều biến toàn cục.
Bởi vì khi bạn truyền một con trỏ đến
một hàm, các hàm có thể sử dụng tham số đó. Và khi nó sửa đổi tham số đó, dữ liệu
sẽ được sửa đổi bên ngoài hàm.
Vì vậy, đây là một khái niệm có giá trị, có giá trị.
Chúng ta sẽ nói về điều này. Đây là một khái niệm nhiều hơn. C thực sự không sử dụng điều này.
Và tôi sẽ chỉ cho bạn cách và cung cấp cho bạn một số ví dụ
về cơ bản cách thức hoạt động của điều này.
Vì vậy, có khái niệm này về giá trị vượt qua. Điều này có liên quan đến các chức năng.
Chúng ta đã nói về việc truyền dữ liệu cho một hàm, nhưng nó thực sự được truyền như
thế nào về ngôn ngữ trong trình biên dịch.
Vì vậy, có một khái niệm về giá trị vượt qua. Và đây là những gì chúng
ta đã nói đến cho đến bây giờ. Bất cứ khi nào chúng ta
gọi hàm bên cạnh hàm scanf, nhưng bất cứ khi nào chúng ta gọi hàm,
khi bạn sửa đổi dữ liệu đó bên trong hàm, nó sẽ không
bị sửa đổi bên ngoài hàm.
Vì vậy, chúng tôi đã nói về các biến cục bộ, đó là một khái niệm khác.
Nhưng khi bạn truyền dữ liệu cho một hàm, có hai cách bạn có thể chuyển nó.
Bạn có thể chuyển nó theo giá trị, bạn có thể chuyển nó bằng cách tham chiếu.
C chỉ chuyển theo giá trị và java cũng
vậy, tất cả
đều chuyển theo giá trị. Nhưng nó mô phỏng chuyển qua tham chiếu bởi
vì bạn sao chép địa chỉ.
Và vì vậy, mặc dù khái niệm
này chuyển qua tham chiếu không được c sử dụng cụ
thể, nhưng nó mô phỏng nó. Và vì vậy, để hiểu được chuyển qua tham chiếu có nghĩa
là gì và tại sao điều đó lại quan trọng, chúng ta sẽ nói về điều đó.
Nhưng truyền theo giá trị là khi một hàm sao chép giá trị thực của một
đối số vào tham số chính thức của hàm.
Và đây là lý do tại sao nếu bạn có một số
nguyên, một số thực hoặc một số kép và bạn chuyển nó vào làm đối số cho một
hàm, thì biến thực tế đó không bị sửa đổi bên ngoài hàm vì nó đã được sao chép.
Vì vậy, các thay đổi được thực hiện đối với tham số bên trong hàm không ảnh hưởng đến đối số.
Đối số được chuyển vào không được sửa đổi.
Vì vậy, nó gần như hoạt động giống như một biến cục bộ vì nó là một bản sao.
Nó thực sự diễn ra như thế nào là nó đang được sao chép và chuyển đến hàm.
Chương trình C sử dụng lệnh gọi theo giá trị để truyền các đối số.
Mọi thứ được gọi bằng giá trị truyền theo giá trị.
Những điều này được sử dụng thay thế cho nhau.
Vì vậy, một lần nữa, điều này có nghĩa là mã bên trong một hàm không thể thay đổi các đối số được sử dụng để gọi hàm.
Không có thay đổi nào trong các giá trị mặc dù chúng đã được thay đổi bên trong hàm.
Có vẻ như chúng là các biến cục bộ.
Và đó là lý do tại sao sớm hơn cho đến thời
điểm này khi bạn phải tạo dữ liệu toàn cục nếu bạn muốn chia sẻ dữ liệu từ chức năng này sang chức năng tiếp theo.
Và đây là cách c hoạt động.
Nhưng điều gì sẽ xảy ra khi bạn thực sự chuyển một
bản sao của một địa chỉ. Sau đó, nó có thể bắt chước chuyển qua tham chiếu.
Nhưng đây là một ví dụ về cách chúng tôi đã sử dụng truyền theo giá trị, nó được chứng minh rất hay ở đây.
Quy trình hoán đổi này là một trường hợp thường được sử dụng để chứng minh giá trị
chuyển bởi vì những gì nó làm là nó tạo ra một tạm thời và nó hoán đổi các tham
số mà các đối số đang được truyền.
Vì vậy, nếu chúng ta có một hàm gọi là swap nhận hai số nguyên,
chúng ta sẽ tạo một biến cục bộ tạm thời.
Nếu chúng ta gán cho tham số x thành temp,
temp sẽ bằng x. Nếu chúng ta nói x bằng y,
thì bây giờ y sẽ bằng x. Nếu chúng ta nói y bằng temp,
thì y sẽ bằng temp.
Nhưng khi gọi hàm này truyền các giá trị đó, x và
y sẽ là cục bộ của hàm này.
Các biến đó sẽ không được sửa đổi bên ngoài hàm này.
Và hàm này chứng tỏ nó rất hữu ích vì chúng ta đang
gán cho y và chúng ta đang gán cho x.
Và x và y là cục bộ của hàm này vì chúng ta đang truyền giá trị, chúng
không được sửa đổi bên ngoài hàm này và đó là lý do tại sao chúng ta phải sử dụng các biến toàn cục.
Nhưng chúng là số nguyên. Chúng là hai số nguyên x và y. Chúng không phải là địa chỉ,
chúng là số nguyên và điều đó rất quan trọng.
Vì vậy, nếu chúng tôi gọi
swap và chúng tôi thấy nó trông như thế nào, bạn
sẽ nhận thấy rằng các giá trị không thay đổi.
Vì vậy, nếu chúng ta tạo một biến có tên là 100 b với
200 và chúng ta in ra các biến trước khi hoán đổi, 100 và 200
thì chúng ta gọi là hoán đổi, các biến
sẽ không bị thay đổi sau khi chúng
ta in chúng ra một lần nữa.
Vì vậy, chúng ta hãy xem xét điều này trong các khối mã và điều này sẽ chứng minh giá trị vượt qua.
Vì vậy, đây là ví dụ của chúng tôi. Chúng tôi có thói quen hoán đổi của chúng tôi.
Chúng tôi đang hoán đổi các giá trị của dữ liệu được chuyển qua x và y.
Chúng tôi đang gọi nó với 100 200.
Chúng ta sẽ in ra trước khi gọi hàm.
Chúng tôi sẽ in ra sau.
Và những gì bạn sẽ nhận thấy là các biến a và b không bao giờ thay đổi.
Và lý do cho điều này là vì chúng ta đang làm theo giá trị.
Vì vậy, nếu tôi chạy chương trình này,
chúng ta có thể thấy rằng trước khi hoán đổi giá trị của a là 100 sau khi bạn hoán đổi giá trị của a
là 100 và giá trị của b 200 và 200 cũng vậy.
Và lý do cho điều này là bởi vì chúng ta đã vượt qua giá trị. Nếu chúng ta chuyển qua tham chiếu,
các biến a và b đó sẽ thay đổi sau lệnh gọi hoán đổi.
Bây giờ, nếu chúng ta sử dụng cùng một kỹ thuật này, chuyển theo giá trị nhưng
chúng ta sao chép các con trỏ, bạn nghĩ điều gì sẽ xảy ra?
Vì vậy, con trỏ và các hàm khá tốt với nhau.
Bạn có thể truyền một con trỏ làm đối số cho một
hàm và bạn cũng có thể yêu cầu một hàm trả về một con trỏ làm kết quả của nó.
Chúng tôi cũng sẽ hướng dẫn cách làm điều đó.
Nhưng truyền bằng tham chiếu sẽ sao chép địa chỉ của một đối số vào tham số chính thức.
Địa chỉ được sử dụng để truy cập đối số thực tế được sử dụng trong cuộc gọi.
Vì vậy, điều này có nghĩa là những thay đổi được thực hiện
đối với tham số bên trong hàm sẽ ảnh hưởng đến đối số trong lời gọi.
Và vì vậy, mặc dù về mặt kỹ thuật nó không được truyền qua tham chiếu,
nhưng nó bắt chước hoặc mô phỏng chuyển qua tham chiếu.
Chúng tôi đang sao chép địa chỉ. Nếu bạn sao chép địa chỉ,
bạn có một địa chỉ và bộ nhớ mới cho giá trị đó của địa chỉ.
Nhưng nếu bạn cố gắng gán cho địa chỉ đó, nó sẽ gán cho địa chỉ.
Vì vậy, mặc dù nó được truyền theo giá trị, nhưng nó đang sao chép.
Và nếu bạn đang sao chép một số nguyên thông thường, bạn sẽ không thực hiện thay đổi. Nếu bạn đang sao chép một địa chỉ, địa chỉ đó sẽ
nằm trong bộ nhớ nên khi bạn thực hiện thay đổi, bạn sẽ thực hiện thay đổi đối với địa chỉ đó.
Vì vậy, để chuyển giá trị bằng tham
chiếu, các con trỏ đối số được truyền cho các hàm giống như bất kỳ giá trị nào khác.
Bạn cần khai báo các tham số của hàm là kiểu con trỏ có dấu hoa thị.
Những thay đổi bên trong chức năng cũng được phản ánh bên ngoài chức năng.
Bạn không cần phải sử dụng nhiều biến toàn cục.
Không giống như lệnh gọi theo giá trị trong đó các thay đổi không phản ánh bên ngoài hàm.
Chúng tôi vẫn đang sao chép, chúng tôi vẫn đang truyền đi giá trị nó chỉ là giá trị của một bản sao của địa chỉ.
Vì vậy, đây là khái niệm quan trọng cần hiểu.
Bây giờ khi chúng ta tạo hàm
hoán đổi, chúng ta sẽ tạo nó với khai báo bên
trong hàm là asterix, star và star.
Điều đó nói rằng hàm này nhận con trỏ.
Bây giờ khi chúng ta gán bên trong hàm này, chúng ta
thực sự phải sử dụng toán tử hướng dẫn đến dereference vì chúng
ta muốn gán các giá trị. Chúng ta sẽ gán giá
trị x mà x trỏ tới nhiệt độ.
Chúng ta sẽ gán giá trị của x trỏ tới giá trị mà
y trỏ tới và sau đó chúng ta sẽ gán giá trị mà y trỏ tới, cho tạm thời.
Temp là một số nguyên nên chúng ta không cần tham khảo nó.
Bây giờ khi chúng ta
gọi nó với a100 và b200 bằng cách
chuyển vào a và b, a và b không phải là con trỏ, vì vậy chúng ta
phải chuyển vào địa chỉ vì hàm nhận con trỏ.
Bất cứ khi nào bạn có một hàm nhận con trỏ và bạn không khai báo một con
trỏ, bạn phải sử dụng địa chỉ của toán tử và nó giống như cách chúng ta sử dụng scanf.
Nhưng bây giờ bạn sẽ nhận thấy khi chúng ta
gọi điều này sau khi lệnh gọi hoán đổi các biến a và b sẽ được
thay đổi, chúng sẽ được hoán đổi. A sẽ là 200 b sẽ là 100.
Vì vậy, bây giờ chúng ta hãy xem xét ví dụ này với sự thay đổi phương thức hoán đổi của chúng ta thành con trỏ trong các khối mã.
Chúng tôi đang ở trong các khối mã. Chúng tôi đã sửa đổi chức năng hoán đổi để lấy con trỏ.
Vì vậy, chúng tôi phải bỏ qua chúng khi chúng tôi chỉ định chúng.
Bây giờ chúng ta cũng chuyển địa chỉ của a và b vì đây là các số nguyên và
sự hoán đổi bây giờ nhận các con trỏ. Vì vậy, khi chúng tôi chạy điều này, chúng
tôi sẽ thấy rằng cuộc gọi và cuộc gọi bây giờ sẽ được thay đổi.
Vì vậy, trước khi chúng ta gọi swap là a bằng 100 sau khi chúng ta gọi swap là 200.
Trước khi chúng tôi gọi swap cho b, nó là 200. Sau đó, nó là 100.
Vì vậy, chúng tôi có thể thay đổi giá trị của các biến bên trong hàm
vì chúng tôi đang tạo một bản sao của địa chỉ. Rất, rất quan trọng và là một trong những
lợi thế lớn của con trỏ.
Vì vậy, chúng ta hãy tóm tắt cú pháp. Tôi đã làm nhưng chúng ta hãy xem xét chi tiết hơn.
Bạn có thể truyền đạt hai loại thông tin về một biến cho một hàm.
Bạn có thể truyền giá trị
của x và hàm phải được khai báo cùng kiểu với x.
Chúng ta biết rằng. Bất cứ khi nào chúng ta truyền dữ
liệu cho một hàm, chúng ta phải có các kiểu giống nhau khi chúng ta gọi nó.
Và ở đây chúng ta có int function1 để gọi nó và nó được định nghĩa là một int num.
Vì vậy, khi chúng ta truyền giá trị của x trong hàm thì chúng phải được khai báo cùng kiểu.
Và sau đó nếu bạn thực sự muốn gọi một địa chỉ của x,
nó yêu cầu định nghĩa hàm bao gồm một con trỏ đến đúng kiểu.
Vì vậy, bất cứ khi nào bạn sử dụng con trỏ, bạn phải đảm bảo rằng nếu bạn
đang truyền dữ liệu và dữ liệu đó không phải là một con trỏ, bạn phải lấy địa chỉ của nó.
Điều này tóm tắt lại là nếu bạn xác định một hàm không sử dụng con trỏ, bạn
có thể chỉ cần gọi nó và chuyển vào dữ liệu.
Đảm bảo rằng nó không phải là một con trỏ.
Nếu bạn có một hàm sử dụng một con trỏ dấu
hoa thị, khi bạn
gọi nó, bạn phải gọi nó bằng toán tử thêm hoặc con.
Bạn phải chuyển địa chỉ vào.
Đó là cú pháp.
Bây giờ bạn cũng có thể xác định một tham số hàm bằng cách sử dụng từ khóa hằng.
Điều này chỉ ra rằng hàm sẽ coi đối số được truyền vào cho tham số này là một hằng số.
Nó chỉ hữu ích khi tham số là một con trỏ.
Bởi vì nếu bạn đang chuyển qua giá trị và bạn không chuyển vào con trỏ, điều đó không quan trọng vì
nó sẽ không ảnh hưởng đến sự thay đổi bên ngoài hàm, vậy tại sao
bạn lại đặt nó là một hằng số, ai quan tâm nếu bạn thay đổi nó .
Lý do duy nhất bạn tạo một hằng con trỏ là vì bạn không muốn
các giá trị bên ngoài hàm thay đổi.
Và vì vậy bạn có thể áp dụng từ khóa hằng cho một tham số là
một con trỏ để chỉ định rằng hàm sẽ không thay đổi giá trị mà đối số trỏ đến.
Rất quan trọng.
Vì vậy, trong ví dụ này, chúng tôi có một chức năng gửi tin nhắn. Nó cần một con trỏ
tin nhắn p.
Chúng tôi đặt từ khóa không đổi trước dấu sao char.
Vì vậy, loại thông báo p tham số là một con trỏ đến một ký tự hằng.
Đó là giá trị ký tự không đổi, không phải địa chỉ của nó.
Vì vậy, trong trường hợp này, những gì chúng ta đang làm là con trỏ được trỏ đến không thể thay đổi.
Chúng tôi có thể thay đổi địa chỉ, nhưng chúng tôi không thể thay đổi những gì nó trỏ đến giá trị.
Cú pháp tương tự như khi chúng ta tạo hằng số trên các con trỏ khác.
Từ khóa không đổi là từ khóa đầu tiên hiển thị sau đó bạn không thể thay đổi giá trị.
Bây giờ bạn có thể chỉ định bản thân con trỏ là hằng
số, nhưng điều này không có ý nghĩa gì vì địa chỉ được truyền theo giá trị.
Bạn không thể thay đổi con
trỏ kết xuất trong chức năng gọi. Vì vậy, đây chỉ là nếu bạn cố gắng làm cho nó để không thể thay đổi
địa chỉ, điều quan trọng là vì nó đã được chuyển theo giá trị. Vì vậy, bạn thực sự
đang tạo một vị trí bộ nhớ
mới để giữ địa chỉ cụ thể đó. Vì vậy, nếu bạn thay đổi nó, ai quan tâm nó sẽ không thay đổi nó ở bên ngoài.
Bạn chỉ muốn có thể đặt tham số là một
hằng số để bạn không thay đổi giá trị của những gì nó trỏ tới,
bạn không thể thay
đổi con trỏ gốc và hàm gọi bất cứ lúc nào vì nó được truyền
bởi giá trị được truyền qua bản sao.
Trình biên dịch biết rằng một đối số là một con trỏ đến dữ liệu không đổi sẽ
an toàn, vì vậy sẽ có những ưu điểm cho điều này. Bạn không thể vô tình sửa đổi giá trị đang trỏ tới.
Vì vậy, bạn có thể thực hiện lại điều này nếu bạn không muốn các thay đổi được phản ánh bên ngoài hàm.
Nếu bạn truyền một con trỏ đến dữ liệu hằng làm đối số cho một tham
số, thì tham số đó phải được sử dụng như trong phần trên.
Khi bạn gọi hàm và bạn truyền nó vào hằng, thì bạn phải
khai báo hàm cũng nhận một con trỏ ký tự hằng, giống như các
con trỏ thông thường khác là hằng số.
Chúng phải được xác định và các định nghĩa phải phù hợp với nguyên mẫu.
Trả về con trỏ từ một hàm.
Trả về một con trỏ từ một hàm là một khả năng đặc biệt mạnh mẽ.
Nó cung cấp một cách để bạn trả về không chỉ một giá trị đơn lẻ, mà cả một tập hợp các giá trị.
Vì vậy, một trong những ưu điểm khác mà tôi đã đề cập
về con trỏ là giờ đây bạn có thể trả về nhiều dữ liệu hơn từ một hàm.
Trước đây, bạn chỉ có thể trả về một giá trị.
Nhưng với một con trỏ vì một con trỏ có thể trỏ
đến một cấu trúc mà chúng ta chưa nói đến hoặc thậm chí những thứ khác mà
bạn có thể trả về nhiều giá
trị Vì vậy, chúng ta đã biết cách chuyển con trỏ đến các hàm, bây giờ chúng
ta muốn nói về việc trả về con trỏ.
Bạn phải khai báo một hàm trả về một con trỏ. Vì vậy, khai báo hàm phải khớp với nhau.
Nó rất dễ dàng để làm điều đó. Bạn chỉ nói sử dụng dấu hoa thị
khi bạn khai báo hàm hoặc định nghĩa nó và có kiểu trả về cho con trỏ đó là những gì nó trỏ tới.
Vì vậy, hãy cẩn thận mặc dù có những mối nguy hiểm cụ thể liên quan đến việc trả về một con trỏ.
Sử dụng các biến cục bộ để tránh can thiệp vào biến mà đối số trỏ tới.
Nó hơi có vấn đề khi bạn trả về con trỏ bởi vì nếu bạn sửa đổi con trỏ đó bên trong
hàm và sau đó trả lại nó, đó có
thể là điều gì đó mà bạn không định làm.
Vì vậy, hãy luôn sử dụng các biến cục bộ nếu bạn không muốn ảnh hưởng đến một biến
mà đối số của bạn trỏ đến.
Và vì vậy bài giảng này mô tả cách bạn
có thể chuyển con trỏ đến các
hàm và cách bạn có thể trả về con trỏ từ các hàm.
Và bằng cách sử dụng cơ chế chuyển con trỏ
đến một hàm, nó thể hiện hoặc bắt chước việc chuyển qua
tham chiếu vì bạn đang sao chép địa chỉ.
Và khi bạn sao chép một địa chỉ nếu bạn ghi vào địa chỉ đó, bạn sẽ
cập nhật bất cứ thứ gì
đang trỏ đến địa chỉ đó, điều đó có nghĩa là bạn đang thay đổi giá
trị của dữ liệu bên trong hàm, nó sẽ phản ánh nó bên ngoài hàm.
Chúng tôi sử dụng quy trình hoán đổi để chứng minh điều đó.
Đây là một khái niệm rất mạnh mẽ. Và bạn muốn bắt chước chuyển qua tham chiếu, bạn
có thể sử dụng con trỏ để làm điều đó và bạn muốn làm điều đó khi bạn muốn thay đổi những thứ bên ngoài hàm.
Cảm ơn bạn.