
Những chủ đề tiến bộ trong C#
Các mã không an toàn – Phần 1
Có những trường hợp ta cần truy xuất bộ nhớ trực tiếp khi ta muốn truy xuất
vào các hàm bên ngoài ( không thuộc .NET) mà đòi hỏi con trỏ được truyền
vào như tham số( ví dụ như các hàm API ).hoặc là vì ta muốn truy nhập vào
nội dung bộ nhớ để sửa lỗi....Trong phần này ta sẽ xem xét cách C# đáp ứng
những điều này như thế nào.
Con trỏ
( trình bày vắng tắt )
Con trỏ đơn giản là 1 biến lưu địa chỉ của một thứ khác theo cùng 1 cách
như là 1 tham chiếu. sự khác biệt là cú pháp C# trong tham chiếu không cho
phép ta truy xuất vào địa chỉ bộ nhớ.
3 ưu điểm của con trỏ :
Cải thiện sự thực thi : cho ta biết những gì ta đang làm,đảm bảo rằng
dữ liệu được truy xuất hay thao tác theo cách hiệu quả nhất - đó là lí do mà
C và C++ cho phép dung con trỏ trong ngôn ngữ của mình.

Khả năng tích hợp với các phần trước ( Backward compatibility ) - đôi
khi ta phải sử dụng lại các hàm API cho mục đích của ta.Mà các hàm API
được viết bằng C,ngôn ngữ dùng con trỏ rất nhiều, nghĩa là nhiều hàm lấy
con trỏ như tham số.Hoặc là các DLL do 1 hãng nào đó cung cấp chứa các
hàm lấy con trỏ làm tham số . Trong nhiều trường hợp ta có thể viết các
khai báo DLlImport theo cách tránh sử dụng con trỏ , ví dụ như dùng lớp
System.IntPtr.
Ta có thể cần tạo ra các địa chỉ vùng nhớ có giá trị cho người dùng -
ví dụ nếu ta muốn phát triển 1 ứng dụng mà cho phép người dùng tương tác
trực tiếp đến bộ nhớ, như là 1 debugger.
Nhược điểm :
Cú pháp để lấy các hàm phức tạp hơn
Con trỏ khó sử dụng
Nếu không cẩn thận ta có thể viết lên các biến khác ,làm tràn stack,
mất thông tin, đụng độ ...
C# có thể từ chối thi hành những đoạn mã không an toàn này (đoạn
mã có sử dụng con trỏ)
Ta có thể đánh dấu đoạn mã có sử dụng con trỏ bằng cách dùng từ khoá
unsafe

Ví dụ : dùng cho hàm
unsafe int GetSomeNumber()
{
// code that can use pointers
}
Dùng cho lớp hay struct
unsafe class MyClass
{
// any method in this class can now use pointers
}
Dùng cho 1 trường
class MyClass
{
unsafe int *pX; // declaration of a pointer field in a class
}
Hoặc một khối mã
void MyMethod()
{
// code that doesn't use pointers
unsafe

{
// unsafe code that uses pointers here
}
// more 'safe' code that doesn't use pointers
}
Tuy nhiên ta không thể đánh dấu 1 biến cục bộ là unsafe
int MyMethod()
{
unsafe int *pX; // WRONG
}
Để biên dịch các mã chứa khối unsafe ta dùng lệnh sau :
csc /unsafe MySource.cs
hay
csc -unsafe MySource.cs
Cú pháp con trỏ
int * pWidth, pHeight;
double *pResult;
Lưu ý khác với C++ ,kí tự * kết hợp với kiểu hơn là kết hợp với biến - nghĩa
là khi ta khai báo như ở trên thì pWidth và pHeight đều là con trỏ do có *

sau kiểu int, khác với C++ ta phải khai báo * cho cả hai biến trên thì cả hai
mới là con trỏ.
Cách dùng * và & giống như trong C++ :
& : lấy địa chỉ
* : lấy nội dung của địa chỉ
Ép kiểu con trỏ thành kiểu Int
Vì con trỏ là 1 số int lưu địa chỉ nên ta có thể chuyển tường minh con trỏ
thành kiểu int hay ngược lại.Ví dụ:
int x = 10;
int *pX, pY;
pX = &x;
pY = pX;
*pY = 20;
uint y = (uint)pX;
int *pD = (int*)y;
y là uint.sau đó ta chuyển ngược lại thành biến con trỏ pD
1 lý do để ta phải ép kiểu là Console.WriteLine không có overload nào nhận
thông số là con trỏ do đó ta phải ép nó sang kiểu số nguyên int
Console.WriteLine("Address is" + pX); // wrong - will give a
// compilation error

