Menu
CoddyTech

Cơ bản về con trỏ trong Go

Thuộc phần Lập trình hướng đối tượng trong hành trình GO của Coddy. Bài học 19 trên 107.

Con trỏ là một biến lưu địa chỉ bộ nhớ của một biến khác. Thay vì lưu trực tiếp một giá trị, nó lưu vị trí của giá trị đó trong bộ nhớ. Con trỏ là nền tảng của Go và rất cần thiết để thao tác dữ liệu hiệu quả.

Để tạo con trỏ, hãy dùng toán tử & để lấy địa chỉ của biến, và toán tử * để khai báo kiểu con trỏ hoặc truy cập giá trị tại địa chỉ đó.

x := 42
p := &x  // p lưu địa chỉ bộ nhớ của x

fmt.Println(p)  // 0xc000018030 (địa chỉ bộ nhớ)
fmt.Println(*p) // 42 (giá trị tại địa chỉ đó)

Toán tử & có nghĩa là “địa chỉ của” và trả về một con trỏ. Toán tử *, khi dùng với con trỏ, có nghĩa là “giá trị tại địa chỉ” và được gọi là giải tham chiếu. Bạn cũng có thể sửa đổi giá trị ban đầu thông qua con trỏ.

x := 10
p := &x

*p = 25         // thay đổi giá trị qua con trỏ
fmt.Println(x)  // 25 (biến ban đầu đã thay đổi)

Kiểu con trỏ được viết là *T, trong đó T là kiểu dữ liệu mà con trỏ trỏ đến. Con trỏ trỏ đến một int có kiểu *int.

var p *int      // khai báo một con trỏ (pointer) trỏ đến kiểu int
x := 100
p = &x          // p hiện trỏ đến x

Giá trị không của con trỏ là nil, nghĩa là nó không trỏ đến đâu cả. Cố gắng giải tham chiếu một con trỏ nil sẽ gây ra lỗi panic khi chạy chương trình, vì vậy hãy luôn khởi tạo con trỏ trước khi sử dụng.

challenge icon

Thử thách

Dễ

Hãy tạo một hàm đơn giản để hoán đổi giá trị, qua đó minh họa sức mạnh của con trỏ trong việc sửa đổi biến thông qua địa chỉ bộ nhớ.

Bạn sẽ sắp xếp code trong hai tệp:

  • swap.go: Tạo một hàm có tên SwapValues nhận hai con trỏ *int làm tham số. Hàm này cần hoán đổi các giá trị mà những con trỏ này trỏ đến. Sau khi gọi hàm, mỗi biến sẽ giữ giá trị ban đầu của biến kia. Hàm không trả về gì, nó sửa đổi trực tiếp các giá trị thông qua con trỏ.
  • main.go: Đọc hai số nguyên từ đầu vào, lưu chúng vào các biến, rồi dùng hàm SwapValues để hoán đổi giá trị của chúng. In cả hai giá trị trước và sau khi hoán đổi để thể hiện sự thay đổi.

Đầu vào sẽ gồm:

  • Dòng 1: Số nguyên thứ nhất
  • Dòng 2: Số nguyên thứ hai

Định dạng đầu ra:

Before: a=[first] b=[second]
After: a=[first] b=[second]

Ví dụ, với 10 và 25, đầu ra của bạn sẽ là:

Before: a=10 b=25
After: a=25 b=10

Nhớ dùng toán tử & khi truyền các biến vào hàm, và toán tử * bên trong hàm để truy cập và sửa đổi các giá trị thực tế.

Tự làm thử

package main

import "fmt"

func main() {
	// Đọc hai số nguyên từ đầu vào
	var a, b int
	fmt.Scanln(&a)
	fmt.Scanln(&b)

	// In ra các giá trị trước khi hoán đổi
	fmt.Printf("Before: a=%d b=%d\n", a, b)

	// TODO: Gọi hàm (function) SwapValues với các con trỏ trỏ đến a và b
	// Nhớ dùng toán tử & để truyền địa chỉ

	// In ra các giá trị sau khi hoán đổi
	fmt.Printf("After: a=%d b=%d\n", a, b)
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Go online