Delphi의 동적 배열(정리)

전통적
Pascal 언어의 배열 크기는 미리 정해져 있습니다. 배열 구조로 데이터 형식을 설명할 때, 배열 요소의 개수를 지정해야 합니다.전문 프로그래머들은 동적 수조의 실현 기술을 알고 있을지도 모른다. 일반적으로 지침을 이용하여 수동으로 필요한 메모리를 분배하고 방출한다.
Delphi 4에 매우 간단한 동적 수조 실현 방법을 추가했고 실현 과정은 내가 앞에서 말한 동적 긴 문자열을 본받았다.긴 문자열과 마찬가지로 동적 그룹의 메모리는 동적 분배와 인용 기수를 지원하지만, 동적 그룹은copy-on-write 기술을 지원하지 않습니다.이것은 큰 문제가 아니다. 왜냐하면 변수 값을nil 방출수 그룹 메모리로 설정할 수 있기 때문이다.
이렇게 하면 원소의 개수를 지정하지 않은 그룹을 설명할 수 있고, SetLength 프로세스로 그룹에 특정한 크기의 메모리를 분배할 수 있으며, SetLength 프로세스는 그 내용에 영향을 주지 않고, 그 외에 일부 문자열 프로세스도 그룹에 사용할 수 있다. 예를 들어 Copy 함수 등이다.
다음 발췌문 코드는 배열을 정의한 후 메모리를 할당한 다음 사용하기 시작해야 한다는 점을 강조합니다.
procedure TForm1.Button1Click(Sender: TObject);
var
  Array1: array of Integer;
begin
  Array1 [1] := 100; // error
  SetLength (Array1, 100);
  Array1 [99] := 100; // OK
  ...
end;

만약 그룹 요소의 개수만 정의한다면, 색인은 항상 0에서 시작합니다.Pascal의 일반 배열은 0이 아닌 아래첨자도 사용할 수 있고 정수가 아닌 아래첨자도 사용할 수 있지만 동적 배열은 두 가지 아래첨자를 지원하지 않습니다.일반 수조와 마찬가지로, 당신은 Length, High, Low 함수를 통해 동적 수조의 상황을 알 수 있지만, 동적 수조에 대해 Low 함수 반환 값은 항상 0이고, High 함수 반환 수조의 크기는 1을 줄인다. 이것은 빈 동적 수조의 함수 High 반환 값은 -1이라는 것을 의미한다. 이것은 매우 이상한 값이다. 왜냐하면 이것은 Low의 반환 값보다 작기 때문이다.
그림8.1: 예: Dynarr 창
이상에서 간단명료하게 소개하였는데, 지금 간단명료한 예를 들면, 예명은 Dynarr이고, 그림8.1 참조.예는 정말 간단하다. 사실 동적 수조는 특별히 복잡한 곳이 없다.나는 이 예를 통해 몇 명의 프로그래머가 범할 수 있는 실수를 설명하고 싶다.프로그램에서 두 개의 전체 배열을 설명하고 Oncreate 이벤트에서 첫 번째 배열을 초기화합니다.
var
  Array1, Array2: array of Integer;

procedure TForm1.FormCreate(Sender: TObject);
begin
  // allocate
  SetLength (Array1, 100);
end;

이렇게 하면 그룹의 모든 값을 0으로 설정합니다.이 코드를 완성하면 메모리 오류를 두려워하지 않고 바로 그룹 요소의 값을 읽을 수 있습니다. 물론 조건은 그룹 상계를 초과한 요소에 접근하려고 하지 않았기 때문입니다.프로그램의 초기화를 위해 배열 요소 값 지정 작업을 수행하는 버튼이 추가되었습니다.
procedure TForm1.btnFillClick(Sender: TObject);
var
  I: Integer;
begin
  for I := Low (Array1) to High (Array1) do
    Array1 [I] := I;
end;

Grow 버튼은 배열 크기를 수정하지만 배열 컨텐트에는 영향을 주지 않습니다.Grow 버튼을 클릭하면 Get value 버튼을 사용하여 다음을 확인할 수 있습니다.
procedure TForm1.btnGrowClick(Sender: TObject);
begin
  // grow keeping existing values
  SetLength (Array1, 200);
end;

procedure TForm1.btnGetClick(Sender: TObject);
begin
  // extract
  Caption := IntToStr (Array1 [99]);
end;

Alias 단추의 OnClick 이벤트 코드는 좀 복잡합니다. 프로그램은: = 산자를 통해 하나의 그룹을 다른 그룹에 복사하여 하나의 별명 (새로운 변수이지만 메모리의 같은 그룹을 참조합니다) 을 효과적으로 만듭니다.여기서 알 수 있듯이, 만약 당신이 그 중의 한 그룹을 바꾸면, 다른 한 그룹도 마찬가지로 바뀔 것이다. 왜냐하면 그들은 같은 메모리 구역을 가리키기 때문이다.
procedure TForm1.btnAliasClick(Sender: TObject);
begin
  // alias
  Array2 := Array1;
  // change one (both change)
  Array2 [99] := 1000;
  // show the other
  Caption := IntToStr (Array1 [99]);

btnAliasClick 이벤트에 두 가지 작업 내용이 추가되었습니다.첫 번째 부분은 수조와 같은 테스트이지만 실제 수조 요소를 테스트하는 것이 아니라 수조가 인용하는 메모리 구역이다. 변수가 메모리에서 같은 수조의 두 가지 별명인지 검사한다.
procedure TForm1.btnAliasClick(Sender: TObject);
begin
  ...
  if Array1 = Array2 then
    Beep;
  // truncate first array
  Array1 := Copy (Array2, 0, 10);
end;

btnAliasClick 이벤트의 두 번째 부분은 Copy 함수를 호출하는 것입니다.이 함수는 데이터를 한 수조에서 다른 수조로 옮길 뿐만 아니라, 함수로 만든 새 수조로 첫 번째 수조를 대체합니다. 결과 변수 Array1은 11개의 요소의 수조를 인용하기 때문에 Getvalue와Setvalue 단추를 누르면 메모리 오류가 발생하고 이상을 터치합니다. (범위 검사range-checking 옵션을 끄지 않으면 오류가 발생하지만 화면에 이상이 나타나지 않습니다.)수정해야 할 배열 요소가 배열의 현재 아래 첨자 범위에 따라 결정되기 때문에 Fill 버튼은 정상적으로 작동합니다.동적 수조가 생기면서 체인 시계는 교과서에 등장한 것을 제외하고는 실제 프로그래밍에서 사용되지 않았다. 사실도 마찬가지다. 수조는 전통적인 체인 시계보다 훨씬 빠르고 편리하다.
Delphi4부터 다양한 종류의 동적 그룹 지원을 내장하기 시작했습니다.그러나 우리에게 동적 그룹 지원은 철저하지 못한 것 같다. 델파이는 삭제, 삽입, 이동 연속 요소의 함수조차 제공하지 않아서 사용하기에 시원치 않다!!!J .프로그래머로서 우리는 당연히 스스로 문제를 해결하는 능력을 가져야 한다. 다음은 델피의 동적 그룹을 간단하게 소개할 것이다.
Delphi에서 배열 유형에는 정적 배열(a:array[0.1024] of integer), 동적 배열(var a:array of integer), 포인터 배열(즉 정적 배열을 가리키는 포인터)과 열린 배열(매개변수 전달에만 사용)이 있습니다.정적 수조, 바늘 수조는 속도가 빠른 장점이 있고 동적 수조는 크기가 변할 수 있는 장점이 있다. 비교해 보면 절충하는 방법이 있다. 그것이 바로 정의된 동적 수조가 필요할 때 바늘로 전환하는 것이다.
동적 그룹 성명 후, 아래의 몇 가지 함수만 가능합니까?o:p>
1. 배열 크기를 설정하면 임의로 배열 크기를 줄이거나 늘릴 수 있습니다
Procedure SetLength(var S ; NewLength : integer);
2. 연속 요소를 꺼내 다른 그룹 변수에 복사
Function Copy(s;Index,Count : integer) : array ;
3. 수조 크기 및 상하한 취득
Function Length(s):integer;
Function High(x):integer;
Function Low(x):integer;
주의해야 할 것은 const나 var 수식이 없는 동적 수조는 형참으로 전달되며, 동적 수조가const 수식으로 수조의 요소를 수정할 수 없다는 것은 아니다. (믿지 않으면 프로그램에서 직접 시도할 수 있다. 또 하나는 하이 함수가 Length 함수를 호출했기 때문에, 우리가 수조의 상한선을 가져올 때 Length (s) 함수를 직접 사용하는 것이 가장 좋다.
동적 그룹은 메모리 공간에서 4바이트를 차지합니다.메모리에서 동적 배열의 할당 테이블은 다음과 같습니다.
오프셋 내용
- 832-bit 참조 개수
- 432-bit 배열 길이
0..배열 길이 *(요소 크기) - 1배열 요소 요소 크기 = Sizeof(요소 유형)
위의 분배 상황에 따라 다음과 같은 결과를 얻을 수 있다.
동적 그룹을 비우려면 '그룹 길이' 와 '인용 계수' 를 비우면 됩니다.위의 한 마디를 인용하면'균형적으로 절충하는 방법이 있다. 그것이 바로 정의된 동적 수조가 필요할 때 지침으로 전환되는 것이다'는 것이다.다음은 동적 배열을 비우는 함수입니다.
procedure DynArraySetZero(var A);
var
  P: PLongint;//32비트 메모리 정렬에 적합한 4바이트 차지
begin
  P := PLongint(A);//A에 대한 주소
  Dec(P);//P 주소 오프셋은 sizeof(A)로 배열 길이를 가리킵니다.
  P^ := 0;//길이 비우기
  Dec(P);//참조 개수
  P^ := 0;//카운트가 비워졌습니다.
end;
위의 함수는 이렇게 간단할 뿐만 아니라 효율도 매우 높다.
다음은 동적 배열에서 요소를 삭제하는 방법을 보여 줍니다. 함수체는 다음과 같습니다.
{************************************
A 변수 유형, elSize = Sizeof(A)
index에서 삭제를 시작한 위치 인덱스, Count 삭제 수량
****************************************}
procedure DynArrayDelete(var A; elSize: Longint; index, Count: Integer);
var
  len, MaxDelete: Integer;
  P : PLongint;//4바이트의 긴 성형 지침
begin
  P := PLongint(A);//찾은 A의 주소
  if P = nil then
    Exit;
  {
다음 문장은 완전히 Dec(P)와 같다.len: = P^ Dec (P) = Pchar (P) – 4 는 4 바이트를 이동하는 편이량이지만, 후자는 바이트로 이동합니다}
len := PLongint(PChar(P) - 4)^;//변수의 길이, 오프셋 - 4
if index > = len then//삭제할 위치가 범위를 벗어나면 종료
    Exit;
  MaxDelete := len - index;//최대 삭제 수
  Count := Min(Count, MaxDelete);//작은 값을 얻다
if Count = 0 then//삭제가 필요하지 않음
    Exit; 
Dec(len, Count);//삭제할 위치로 이동
  MoveMemory(PChar(P)+index*elSize , PChar(P)+(index + Count)*elSize , (len-index)*elSize);//이동 메모리
  Dec(P);//배열 길이 위치 이동
  Dec(P);//참조 수 위치 이동
//메모리 재분배 조정, 렌 새 길이.Sizeof(Longint) * 2 = 2*Dec(P)
  ReallocMem(P, len * elSize + Sizeof(Longint) * 2);
  Inc(P);//지향수 그룹 길이
  P^ := len;//new length
  Inc(P);//배열 요소, 시작 위치 가리키기
  PLongint(A) := P;
end;
 
위의 예에서 주의해야 할 것은elSize 매개 변수입니다. 이것은 반드시 SizeOf (DyArray Name) 이고 요소가 차지하는 바이트 수를 표시해야 합니다.
위의 예를 본 후에 동적 그룹의 복사에 대해 이동도 틀림없이 스스로 실현할 수 있을 거라고 믿는다 J
후속:
사실,델파이는 많은 종류의 메모리에 대한 분배가 매우 비슷하다. 예를 들어string 형식이다. 사실 이것은 동적 그룹과 매우 비슷하다. 우리는 그것을 동적 그룹으로 가져올 수 있다.실질적으로 string은 Pchar의 간단한 버전이다.어쨌든 메모리의 분배를 이해하는 것은 우리 개발자들에게 좋은 점이 있다.

좋은 웹페이지 즐겨찾기