C# cho phép sử dụng con trỏ (pointer) trong context unsafe. Truyền con trỏ cho phép thao tác trực tiếp bộ nhớ, hữu ích cho interop, performance critical, hoặc thuật toán thấp cấp.
⚠️ Cảnh báo: Code unsafe bỏ qua an toàn kiểu/bộ nhớ của CLR. Chỉ dùng khi cần thiết (interop, high-perf), bật
AllowUnsafeBlocks trong project.
Cú pháp
public unsafe void MethodName(int* ptr) { ... }
- Method/class/block phải đánh dấu
unsafe. - Con trỏ khai báo:
type* name(ví dụ:int* p). - Lấy địa chỉ:
&variable. - Dereference:
*ptr.
Ví dụ: Swap hai số nguyên qua con trỏ
using System;
class Program
{
// Unsafe method nhận con trỏ
public unsafe void Swap(int* p, int* q)
{
int temp = *p; // Dereference
*p = *q;
*q = temp;
}
public unsafe static void Main()
{
// Cần bật AllowUnsafeBlocks trong .csproj:
// true
Program p = new Program();
int var1 = 10;
int var2 = 20;
// fixed: pin object trong memory (GC không di chuyển)
// int là primitive, không cần fixed, nhưng array/struct cần
int* x = &var1; // Lấy địa chỉ
int* y = &var2;
Console.WriteLine($"Before Swap: var1={var1}, var2={var2}");
p.Swap(x, y);
Console.WriteLine($"After Swap: var1={var1}, var2={var2}");
// Ví dụ với array (cần fixed)
int[] arr = { 1, 2, 3, 4, 5 };
fixed (int* ptr = arr) // Pin mảng
{
Console.WriteLine($"First element via pointer: {*ptr}"); // 1
Console.WriteLine($"Second element: {*(ptr + 1)}"); // 2
} // Unpin tự động ở đây
}
}
Kết quả
Before Swap: var1=10, var2=20 After Swap: var1=20, var2=10 First element via pointer: 1 Second element: 2
Các khái niệm quan trọng
| Khái niệm | Cú pháp | Mô tả |
|---|---|---|
| Khai báo con trỏ | int* p; | Con trỏ đến int |
| Address-of | &var | Lấy địa chỉ biến (chỉ trong unsafe) |
| Dereference | *p | Truy cập giá trị tại địa chỉ |
| Pointer arithmetic | p + 1, p - 1 | Nhảy kích thước kiểu (sizeof(int)=4 bytes) |
| Fixed statement | fixed (int* p = arr) | Pin managed object, ngăn GC move |
| stackalloc | int* p = stackalloc int[100] | Cấp phát trên stack (nhanh, tự free) |
Thay thế an toàn hiện đại (Khuyên dùng)
Span<T>/Memory<T>: Safe, bounds-checked, zero-allocation view vào memory.ref struct: Stack-only types.Unsafeclass:Unsafe.As<T>(),Unsafe.CopyBlock()... không cần unsafe context.Marshalclass cho interop.
// Modern safe swap với ref
public static void Swap(ref int a, ref int b)
{
int temp = a; a = b; b = temp;
}