Bạn đã được đưa ra rất nhiều câu trả lời tốt cho đến nay, nhưng bắt đầu với câu trả lời mà bạn đang đối phó với con trỏ khi bạn sử dụng chuỗi dài, mảng năng động và đối tượng tài liệu tham khảo bạn nên bắt đầu tự hỏi tại sao bạn sẽ sử dụng con trỏ, thay vì chuỗi dài, mảng động và tham chiếu đối tượng. Có lý do gì để vẫn sử dụng con trỏ, cho rằng Delphi làm một công việc tốt ẩn chúng khỏi bạn, trong nhiều trường hợp?
Hãy để tôi cung cấp cho bạn hai ví dụ về sử dụng con trỏ trong Delphi. Bạn sẽ thấy rằng điều này có lẽ không phù hợp với bạn nếu bạn chủ yếu viết các ứng dụng kinh doanh. Tuy nhiên, nó có thể trở nên quan trọng nếu bạn cần sử dụng các hàm API của Windows hoặc của bên thứ ba mà không được nhập bởi bất kỳ đơn vị Delphi chuẩn nào và không có đơn vị nhập (ví dụ) các thư viện JEDI. Và nó có thể là chìa khóa để đạt được tốc độ cuối cùng cần thiết trong mã xử lý chuỗi.
Con trỏ có thể được sử dụng để đối phó với các kiểu dữ liệu có kích thước khác nhau (chưa biết tại thời gian biên dịch)
xem xét Windows kiểu dữ liệu bitmap. Mỗi hình ảnh có thể có chiều rộng và chiều cao khác nhau và có các định dạng khác nhau từ màu đen và trắng (1 bit trên mỗi pixel) trên 2^4, 2^8, 2^16, 2^24 hoặc thậm chí 2^32 giá trị hoặc màu xám . Điều đó có nghĩa là nó không biết tại thời gian biên dịch bao nhiêu bộ nhớ một bitmap sẽ chiếm.
Trong windows.pas có là TBitmapInfo loại:
type
PBitmapInfo = ^TBitmapInfo;
tagBITMAPINFO = packed record
bmiHeader: TBitmapInfoHeader;
bmiColors: array[0..0] of TRGBQuad;
end;
TBitmapInfo = tagBITMAPINFO;
Các TRGBQuad yếu tố mô tả một điểm ảnh duy nhất, nhưng bitmap không tất nhiên chứa nhiều hơn một pixel.Do đó người ta sẽ không bao giờ sử dụng một biến địa phương của loại TBitmapInfo, nhưng luôn luôn là một con trỏ đến nó:
var
BmpInfo: PBitmapInfo;
begin
// some other code determines width and height...
...
BmpInfo := AllocMem(SizeOf(TBitmapInfoHeader)
+ BmpWidth * BmpHeight * SizeOf(TRGBQuad));
...
end;
Bây giờ sử dụng con trỏ, bạn có thể truy cập vào tất cả các pixel, mặc dù TBitmapInfo không chỉ có một duy nhất. Lưu ý rằng đối với mã như vậy bạn phải vô hiệu hóa kiểm tra phạm vi.
Các nội dung như vậy cũng có thể được xử lý với lớp TMemoryStream, về cơ bản là một trình bao bọc thân thiện xung quanh một con trỏ tới một khối bộ nhớ.
Và tất nhiên, việc tạo một TBitmap và chỉ định định dạng chiều rộng, chiều cao và pixel của nó dễ dàng hơn nhiều. Để nhà nước nó một lần nữa, VCL Delphi loại bỏ hầu hết các trường hợp con trỏ nếu không sẽ là cần thiết.
Con trỏ tới ký tự có thể được sử dụng để tăng tốc độ hoạt động chuỗi
Đây là, giống như hầu hết các tối ưu hóa vi, một cái gì đó chỉ được sử dụng trong những trường hợp cực đoan, sau khi bạn đã cấu hình và tìm thấy mã sử dụng chuỗi để tiêu thụ nhiều thời gian.
Thuộc tính tốt đẹp của chuỗi là chúng được tính tham chiếu. Việc sao chép chúng không sao chép bộ nhớ mà chúng chiếm, nó chỉ làm tăng số lượng tham chiếu thay thế. Chỉ khi mã cố sửa đổi một chuỗi có số tham chiếu lớn hơn 1 thì bộ nhớ sẽ được sao chép, để tạo chuỗi có số tham chiếu là 1, sau đó có thể sửa đổi một cách an toàn.
Thuộc tính không tốt đẹp của chuỗi là chúng được tính tham chiếu. Mọi hoạt động có thể có thể sửa đổi chuỗi phải đảm bảo rằng số tham chiếu là 1, bởi vì nếu không sửa đổi chuỗi sẽ là nguy hiểm. Thay thế một ký tự trong một chuỗi là một sửa đổi như vậy. Để đảm bảo rằng số tham chiếu là 1 cuộc gọi đến UniqueString() được trình biên dịch thêm vào bất cứ khi nào một ký tự trong chuỗi được ghi vào. Bây giờ viết n ký tự của một chuỗi trong một vòng lặp sẽ gây UniqueString() được gọi n lần, mặc dù sau khi lần đầu tiên được được đảm bảo rằng số lượng tài liệu tham khảo là 1. Điều này có nghĩa cơ bản n - 1 cuộc gọi UniqueString() được thực hiện không cần thiết.
Sử dụng con trỏ đến các ký tự là một cách phổ biến để tăng tốc các hoạt động chuỗi liên quan đến vòng lặp. Hãy tưởng tượng bạn muốn (cho mục đích hiển thị) để thay thế tất cả các không gian trong một chuỗi với một dấu chấm nhỏ. Sử dụng xem CPU của debugger và so sánh các mã thực thi mã
procedure MakeSpacesVisible(const AValue: AnsiString): AnsiString;
var
i: integer;
begin
Result := AValue;
for i := 1 to Length(Result) do begin
if Result[i] = ' ' then
Result[i] := $B7;
end;
end;
này với mã này
procedure MakeSpacesVisible(const AValue: AnsiString): AnsiString;
var
P: PAnsiChar;
begin
Result := AValue;
P := PAnsiChar(Result);
while P[0] <> #0 do begin
if P[0] = ' ' then
P[0] := $B7;
Inc(P);
end;
end;
Trong chức năng thứ hai sẽ có chỉ có một cuộc gọi đến UniqueString(), khi địa chỉ của ký tự chuỗi đầu tiên được gán cho con trỏ char.
Hy vọng điều này là đủ thông tin, tôi có thể thêm thông tin nếu bạn muốn. –
+1 Giải thích tuyệt vời. Làm tốt lắm! –
Cảm ơn, tôi muốn giúp đỡ. Nhưng nó luôn luôn là tốt đẹp nếu nó được apreciated. –