2009-04-03 42 views
9

Tôi đã đọc lên về đi ngang qua tham khảo và đểLàm thế nào để bạn vượt qua một mảng bằng cách tham chiếu trong Delphi?

procedure test(var x:integer); 
begin 
    x:=x+5; 
end; 

cập nhật mã để trên 5 bằng cách tham khảo. Tôi giả sử nếu tôi cập nhật mảng bằng tham chiếu, tôi có thể khai báo var X: mảng blah ... có một số lỗi bị ràng buộc và chỉ muốn biết liệu tôi có nên sử dụng loại dữ liệu cho con trỏ tới dữ liệu hay không con trỏ luôn luôn int ... chỉ vì vậy tôi biết nếu đó là cách tôi đang làm của tôi đi qua tham chiếu hoặc cái gì khác trong mã của tôi đó là vấn đề.

Trả lời

19

Nếu bạn chuyển mảng động dưới dạng tham số không phải var, trình biên dịch sẽ tạo một bản sao.

Mẫu mã nhỏ bên dưới cho thấy rằng bằng cách hiển thị 37/42 trong chú thích biểu mẫu.

procedure IncArray1(data: array of integer); 
var i : integer; 
begin 
    for i := Low(data) to High(data) do 
    data[i] := data[i] + 5; 
end; 

procedure IncArray2(var data: array of integer); 
var i : integer; 
begin 
    for i := Low(data) to High(data) do 
    data[i] := data[i] + 5; 
end; 

procedure TForm8.FormCreate(Sender: TObject); 
var 
    data: array of integer; 
begin 
    SetLength(data, 1); 
    data[0] := 37; 
    IncArray1(data); 
    Caption := IntToStr(data[0]); 
    IncArray2(data); 
    Caption := Caption + '/' + IntToStr(data[0]); 
end; 

Nếu chúng ta nhìn vào mã lắp ráp tạo ra, IncArray1 bắt đầu với

004552B4 8BCA    mov ecx,edx 
004552B6 85C9    test ecx,ecx 
004552B8 7807    js $004552c1 
004552BA 8B1C88   mov ebx,[eax+ecx*4] 
004552BD 49    dec ecx 
004552BE 53    push ebx 
004552BF 79F9    jns $004552ba 
004552C1 8BC4    mov eax,esp 

mảng nguồn sao chép mã này vào stack và đặt eax đến địa chỉ của phần tử đầu tiên (= địa chỉ được lưu trữ trong ngăn xếp con trỏ sau lần đẩy cuối cùng). Stack phát triển xuống để mã bắt đầu với phần tử cuối cùng (edx chứa Cao (dữ liệu) khi IncArray1 được gọi) và lặp lại (phần tử đọc; phần tử đẩy; chỉ mục giảm) cho đến khi nó đến phần tử 0.

IncArray2 không chứa mã như vậy. Người gọi lưu trữ địa chỉ của dữ liệu vào thanh ghi eax trước khi gọi IncArray2 và IncArray2 chỉ sử dụng địa chỉ này.

Trong trường hợp bạn không muốn sử dụng 'var' vì bất kỳ lý do gì, bạn có thể chuyển địa chỉ của dữ liệu cho phương pháp của mình. Nhưng vì bạn không thể sử dụng cú pháp 'data:^array of integer' trong khai báo tham số, bạn phải khai báo một kiểu cho dữ liệu của bạn. Và bạn phải sử dụng 'dữ liệu ^' thay vì 'dữ liệu' ở mọi nơi trong phương thức.

type 
    TData = array of integer; 
    PData = ^TData; 

procedure IncArray(data: PData); 
var i : integer; 
begin 
    for i := Low(data^) to High(data^) do 
    data^[i] := data^[i] + 5; 
end; 

procedure TForm8.FormCreate(Sender: TObject); 
var 
    data: TData; 
begin 
    SetLength(data, 2); 
    data[0] := 37; 
    IncArray(@data); 
    Caption := IntToStr(data[0]); 
end; 

Thử nghiệm với Delphi 2007.

+0

Ok vậy có cách nào để làm điều đó, tôi có một mảng lớn mà tôi muốn làm việc trên thông qua tham chiếu. sao chép mảng là xa để comptationaly đắt tiền. – Arthur

+0

Có, giống như IncArray2 thực hiện trong đoạn mã trên - tiền tố 'var' của người dùng. – gabr

+0

@gabr, bạn có thể kiểm tra xem mảng động có được sao chép khi bạn không biến đổi không?Tôi biết rằng các chuỗi là copy-on-write. –

6

câu trả lời Gabr là đúng nhưng điểm mấu chốt được chôn đủ sâu mà tôi sẽ mang nó ra như một bài riêng biệt:

Xác định loại của bạn đầu tiên! Trong trường hợp cụ thể này, trình biên dịch chấp nhận một mảng số nguyên ở đó, nhưng đó chỉ là vì nó có ý nghĩa đặc biệt và nó là KHÔNG những gì bạn mong đợi. Bất kỳ nỗ lực nào khác để xác định một loại trong định nghĩa của quy trình sẽ chỉ thất bại.

Không giống như C, nếu bạn muốn hai điều cần được chuyển nhượng tương thích, bạn phải khai báo chúng như là CÙNG loại, không chỉ đơn thuần là hai loại được xây dựng giống nhau:

Var 
    A : Array [1..4] of Integer; 
    B : Array [1..4] of Integer; 

Begin 
    A := B; 

Sẽ không biên dịch . Thay vào đó:

Type 
    Array4 = array [1..4] of Integer; 

Var 
    A : Array4; 
    B : Array4; 

Begin 
    A := B; 

và trình biên dịch thực hiện những gì bạn mong đợi.

+0

Có chạy đi để thay đổi mã sau khi bài viết của Gabr tôi bây giờ có vấn đề chính xác bạn đang nói ,, nó sẽ không đến đống ,, nó nói các loại chính thức ahve được như nhau .. A và B cho tôi là trong các đơn vị khác nhau .. tôi có thể làm gì? – Arthur

+0

Giả sử rằng đơn vị A "sử dụng" đơn vị B. Khai báo loại chia sẻ trong đơn vị B và cả hai có thể "xem" định nghĩa đó. – Argalatyr

+2

Nếu bạn chạy mã gabr nhưng với tất cả "mảng nguyên" được thay thế bởi TIntArray (trong đó TIntArray = mảng của số nguyên), thì mảng luôn được truyền theo tham chiếu và dữ liệu [0] là 37 + 5 + 5 = 49. Điều đó không kỳ lạ sao? –

Các vấn đề liên quan