Konuyu Oyla:
  • Derecelendirme: 0/5 - 0 oy
  • 1
  • 2
  • 3
  • 4
  • 5
Offset Kavramı Ve Dinamik Dizi Yapımı (2 ve 3 Boyutlu)
#1
Daha önce Offset Kavramı ve Dinamik Dizi Yapımı isminde bir yazı yazmış ve işaretçiler(Pointer) başka bir deyiş ile adresler ile neler yapabileceğini izah etmeye çalışmıştım.

Dinamik bir diziyi implement etmede izlediğim yol şuydu;
Dinamik bellek yöneten fonksiyonları kullanarak, hafızada bir alan tahsis (allocate) etmek ve sonra, fonksiyonun döndürdüğü adres üzerinden hesaplama yaparak ilgili veriye ulaşmakdı.

Çıkardığım hesaplama formülü ise aşağıdaki gibiydi;
Alıntı:Basit bir hesap ile formülümüz aşağıdaki gibi olacaktır.
Kaç Bayt = index X Veri tipinin kapladığı alan(Byte)
Yeni Adres = Başlangıç adresi + Kaç Byte


Biraz düşünmeyle bulduğum bu formül, sadece 1 boyutlu bir dizinin elemanlarına erişim formülüydü. Şöyle ki;
Alıntı:Element_Adress = Base_Adress  + (Index * Element_Size)
Memory_Size = Element_Count * Element_Size


Sonrasında ise @Tuğrul HELVACI  hocamın (Write Great Code: Volume 1: Write Great Code, Write Great Code, Volume 2: Thinking Low-Level, Writing High-Level) kitaplarını kabaca incelerken, "Composite Data Types and Memory Objects" konusu gözüme çarptı ve doğrudan o konuyu incelemeye başladım.Kadere bakın ki; Pointer'lar, diziler ve çok boyutlu dizilerin elemanlarına erişim formülü yer alıyordu. Shy

2 Boyutlu Dizi Ve Elemanlarına Erişim Formülü
Alıntı:Element_Adress = Base_Adress + (Col_Index * Row_Size + Row_Index) * Element_Size
Memory_Size = Element_Size * (Col_Count * Row_Count)


3 Boyutlu Dizi ve Elemanlarına Erişim Formülü
Alıntı:Element_Adress = Base_Adress + ( (Depth_Index * Col_Size + Col_Index) * Row_Size + Row_Index) * Element_Size
Memory_Size = Element_Size * Depth_Size * (Col_Count * Row_Count)


Formülleri biraz açıklayacak olursak;
Element_Adress hafıza bloğundaki verinin adresini temsil etmektedir.
Base_Adress dinamik bellekte alan tahsis eden fonksiyonların döndürdüğü adresi temsil etmektedir.
Memory_Size ise dizinin hafızada kapladığı alanı temsil etmektedir.
Element_Size ise sizeof(veri_tipi) ile bulduğumuz değerdir.
Col_Size ise dizideki kolon sayını temsil eder.
Row_Size ise dizideki satır sayısını temsil eder.
Depth_Size ise kolon ve satır ikilisinden kaç adet olacağını temsil eder.

Formülleri bilmek hoştur amma, uygulayabilmek başkadır başka diyerek formülü, yine pointer kullanımının mümkün olduğunu bildiğim dillerde kabaca denemeye çalıştım.
Formüller aynı şekilde, farklı sözdizimlerinde(syntax) kodlanmıştır.


2 Boyutlu Dinamik Array implementasyonu (delphi)
{
 Author   : isocan
 Purpose  : How to implement dimensional dynamic array using pointers.
 DateTime : 17.11.2019

 Write Great Code: Volume 1: Understanding the Machine
 Composite Data Types and Memory Objects
 Type variable[Col_Size][Row_Size]
 Element_Adress = Base_Adress + (Col_Index * Row_Size + Row_Index) * Element_Size
}

unit DimensionalArray;

interface

uses
 Winapi.Windows,
 System.Classes,
 System.SysUtils;


type

 TDimensionalArray = class
  const IndexOutOfRangeException = 'IndexOutOfRangeException at %d';
 type
   PT = ^T;
 strict private
   FColCount: NativeInt;
   FRowCount: NativeInt;
   FMemorySize : NativeInt;
   FBaseAdress: PT;
   FPtrWrapper : TPtrWrapper;
 strict private
   procedure RangeCheck(AColIndex, ARowIndex: NativeInt);
   function Offset(AColIndex, ARowIndex: NativeInt): NativeInt;
   function GetElement(AColIndex, ARowIndex: NativeInt): T;
   procedure SetElement(AColIndex, ARowIndex: NativeInt; const Value: T);
   function CalculateElementAdress(AColIndex, ARowIndex: NativeInt): PT;
   procedure CalculateMemorySize();
   procedure SetColAndRowCount(AColCount, ARowCount: NativeInt);
   procedure MemoryAllocate();
   procedure MemoryFree();
 public
   constructor Create(AColCount, ARowCount: NativeInt);
   destructor Destroy();
 public
   procedure ReSize(AColCount, ARowCount: NativeInt);
 public
   property ColCount: NativeInt read FColCount;
   property RowCount: NativeInt read FRowCount;
   property Element[AColIndex, ARowIndex: NativeInt]: T read GetElement write SetElement; default;
 end;

implementation

{ TDimensionalArray }
constructor TDimensionalArray.Create(AColCount, ARowCount: NativeInt);
begin
 SetColAndRowCount(AColCount,ARowCount);
 MemoryAllocate();
 inherited Create;
end;

destructor TDimensionalArray.Destroy;
begin
 TMarshal.FreeMem(FPtrWrapper);
 inherited Destroy;
end;


procedure TDimensionalArray.RangeCheck(AColIndex, ARowIndex: NativeInt);
begin
 if (AColIndex < 0) or (AColIndex > FColCount-1 ) then
    raise Exception.Create(Format(IndexOutOfRangeException,[AColIndex]));

 if (ARowIndex < 0) or (ARowIndex > FRowCount-1 ) then
    raise Exception.Create(Format(IndexOutOfRangeException,[ARowIndex]));
end;

function TDimensionalArray.Offset(AColIndex, ARowIndex: NativeInt)
 : NativeInt;
begin
 RangeCheck(AColIndex,ARowIndex);
 Result := (AColIndex * FRowCount + ARowIndex) * SizeOf(T);
end;

procedure TDimensionalArray.ReSize(AColCount, ARowCount: NativeInt);
begin
 MemoryFree();
 SetColAndRowCount(AColCount,ARowCount);
 CalculateMemorySize();
 FPtrWrapper := TMarshal.ReallocMem(FPtrWrapper,FMemorySize);
 FBaseAdress := FPtrWrapper.ToPointer;
end;

procedure TDimensionalArray.SetColAndRowCount(AColCount, ARowCount: NativeInt);
begin
 FColCount := AColCount;
 FRowCount := ARowCount;
end;

procedure TDimensionalArray.MemoryAllocate();
begin
 CalculateMemorySize();
 FPtrWrapper := TMarshal.AllocMem(FMemorySize);
 FBaseAdress := FPtrWrapper.ToPointer;
end;

procedure TDimensionalArray.MemoryFree;
begin
 TMarshal.FreeMem(FPtrWrapper);
end;

function TDimensionalArray.CalculateElementAdress(AColIndex,
 ARowIndex: NativeInt): PT;
begin
 Result := PT(PByte(FBaseAdress) + Offset(AColIndex, ARowIndex));
end;

procedure TDimensionalArray.CalculateMemorySize();
begin
 FMemorySize := SizeOf(T) * (FColCount * FRowCount);
end;

function TDimensionalArray.GetElement(AColIndex, ARowIndex: NativeInt): T;
begin
 Result := CalculateElementAdress(AColIndex, ARowIndex)^;
end;

procedure TDimensionalArray.SetElement(AColIndex, ARowIndex: NativeInt;
 const Value: T);
begin
 CalculateElementAdress(AColIndex, ARowIndex)^ := Value;
end;

end.


3 Boyutlu Dinamik Array implementasyonu (delphi)
{
 Author   : isocan
 Purpose  : How to implement Three-dimensional dynamic array using pointers.
 DateTime : 21.11.2019

 Write Great Code: Volume 1: Understanding the Machine
 Composite Data Types and Memory Objects

 Type variable[Depth_Size][Col_Size][Row_Size];
 Element_Adress = Base_Adress + ( (Depth_Index * Col_Size + Col_Index) * Row_Size + Row_Index) * Element_Size
}

unit ThreeDimensionalArray;

interface

uses
 Winapi.Windows,
 System.Classes,
 System.SysUtils;

type

 TThreeDimensionalArray = class
  const IndexOutOfRangeException = 'IndexOutOfRangeException at %s %d';
 type
   PT = ^T;
 strict private
   FDepthSize :NativeInt;
   FColCount: NativeInt;
   FRowCount: NativeInt;
   FMemorySize : NativeInt;
   FBaseAdress: PT;
   FPtrWrapper : TPtrWrapper;
 strict private
   function GetMessage(AIndexName:string;AIndex:NativeInt):string;
   procedure RangeCheck(ADepthIndex,AColIndex, ARowIndex: NativeInt);
   function Offset(ADepthIndex,AColIndex, ARowIndex: NativeInt): NativeInt;
   function GetElement(ADepthIndex,AColIndex, ARowIndex: NativeInt): T;
   procedure SetElement(ADepthIndex,AColIndex, ARowIndex: NativeInt; const Value: T);
   function CalculateElementAdress(ADepthIndex,AColIndex, ARowIndex: NativeInt): PT;
   procedure CalculateMemorySize();
   procedure SetDepthAndColAndRowCount(ADepthSize,AColCount, ARowCount: NativeInt);
   procedure MemoryAllocate();
   procedure MemoryFree();
 public
   constructor Create(ADepthSize,AColCount, ARowCount: NativeInt);
   destructor Destroy();
 public
   procedure ReSize(ADepthSize,AColCount, ARowCount: NativeInt);
 public
   property DepthSize: NativeInt read FDepthSize;
   property ColCount: NativeInt read FColCount;
   property RowCount: NativeInt read FRowCount;
   property MemorySize: NativeInt read FMemorySize;
   property Element[ADepthIndex,AColIndex, ARowIndex: NativeInt]: T read GetElement write SetElement; default;
 end;

implementation

{ TDimensionalArray }
constructor TThreeDimensionalArray.Create(ADepthSize,AColCount, ARowCount: NativeInt);
begin
 SetDepthAndColAndRowCount(ADepthSize,AColCount,ARowCount);
 MemoryAllocate();
 inherited Create;
end;

destructor TThreeDimensionalArray.Destroy;
begin
 TMarshal.FreeMem(FPtrWrapper);
 inherited Destroy;
end;

function TThreeDimensionalArray.GetMessage(AIndexName: string;
 AIndex: NativeInt): string;
begin
  Result := Format(IndexOutOfRangeException,[AIndexName,AIndex]);
end;

procedure TThreeDimensionalArray.RangeCheck(ADepthIndex, AColIndex,
 ARowIndex: NativeInt);
begin
 if (ADepthIndex < 0) or (ADepthIndex > Pred(FDepthSize) ) then
    raise Exception.Create(GetMessage('ADepthIndex',ADepthIndex));

 if (AColIndex < 0) or (AColIndex > Pred(FColCount) ) then
    raise Exception.Create(GetMessage('AColIndex',AColIndex));

 if (ARowIndex < 0) or (ARowIndex > Pred(FRowCount) ) then
    raise Exception.Create(GetMessage('ARowIndex',ARowIndex));
end;

function TThreeDimensionalArray.Offset(ADepthIndex,AColIndex, ARowIndex: NativeInt)
 : NativeInt;
begin
 RangeCheck(ADepthIndex,AColIndex, ARowIndex);
 Result := ( (ADepthIndex * FColCount + AColIndex) * FRowCount + ARowIndex) * SizeOf(T);
end;

procedure TThreeDimensionalArray.ReSize(ADepthSize,AColCount, ARowCount: NativeInt);
begin
 MemoryFree();
 SetDepthAndColAndRowCount(ADepthSize,AColCount,ARowCount);
 CalculateMemorySize();
 FPtrWrapper := TMarshal.ReallocMem(FPtrWrapper,FMemorySize);
 FBaseAdress := FPtrWrapper.ToPointer;
end;

procedure TThreeDimensionalArray.SetDepthAndColAndRowCount(ADepthSize,AColCount, ARowCount: NativeInt);
begin
 FDepthSize := ADepthSize;
 FColCount := AColCount;
 FRowCount := ARowCount;
end;

procedure TThreeDimensionalArray.MemoryAllocate();
begin
 CalculateMemorySize();
 FPtrWrapper := TMarshal.AllocMem(FMemorySize);
 FBaseAdress := FPtrWrapper.ToPointer;
end;

procedure TThreeDimensionalArray.MemoryFree;
begin
 TMarshal.FreeMem(FPtrWrapper);
end;

function TThreeDimensionalArray.CalculateElementAdress(ADepthIndex,AColIndex,
 ARowIndex: NativeInt): PT;
begin
 Result := PT(PByte(FBaseAdress) + Offset(ADepthIndex,AColIndex, ARowIndex));
end;

procedure TThreeDimensionalArray.CalculateMemorySize();
begin
 FMemorySize := SizeOf(T) * FDepthSize * (FColCount * FRowCount);
end;

function TThreeDimensionalArray.GetElement(ADepthIndex,AColIndex, ARowIndex: NativeInt): T;
begin
 Result := CalculateElementAdress(ADepthIndex,AColIndex, ARowIndex)^;
end;

procedure TThreeDimensionalArray.SetElement(ADepthIndex,AColIndex, ARowIndex: NativeInt;
 const Value: T);
begin
 CalculateElementAdress(ADepthIndex,AColIndex, ARowIndex)^ := Value;
end;


2 Boyutlu Dinamik Array implementasyonu (C/C++)
/*
 Author   : isocan
 Purpose  : How to implement dimensional dynamic array using pointers.
 DateTime : 17.11.2019

 Write Great Code: Volume 1: Understanding the Machine
 Composite Data Types and Memory Objects
 Type variable[Col_Size][Row_Size]
 Element_Adress = Base_Adress + (Col_Index * Row_Size + Row_Index) * Element_Size
*/
#include <cstdint>
#include <string> 
#include <stdexcept>
#include <sstream>
#include <iostream>

template 
class DimensionalArray{
private:
  const std::string IndexOutOfRangeException = "IndexOutOfRangeException at "; 
  Type* fBaseAdress;  
  int32_t fColCount;
  int32_t fRowCount;
  int32_t fMemorySize; 
private:
  std::string ToString(int32_t value){
     std::string outString;
     std::stringstream ss;
     ss << value;
     outString = ss.str();
     return outString;
  }

  std::string GetMessage(std::string indexName,int32_t index){
     return std::string(IndexOutOfRangeException + indexName + "["+ ToString(index)+"]");
  }

  void RangeCheck(int32_t colIndex, int32_t rowIndex){
    if ((colIndex < 0) || (colIndex > fColCount - 1))
      throw std::out_of_range(GetMessage("colIndex",colIndex).c_str());

    if ((rowIndex < 0) || (rowIndex > fRowCount - 1))
      throw std::out_of_range(GetMessage("rowIndex",rowIndex).c_str());
  }

  int32_t Offset(int32_t colIndex, int32_t rowIndex){
    RangeCheck(colIndex,rowIndex);
    return (colIndex * fRowCount + rowIndex) * sizeof(Type);
  } 

  Type* CalculateElementAdress(int32_t colIndex, int32_t rowIndex){
    return fBaseAdress + Offset(colIndex,rowIndex);
  }

  void CalculateMemorySize(){
    fMemorySize =  sizeof(Type) * (fColCount * fRowCount);
  }
  
  void SetColAndRowCount(int32_t colCount,int32_t rowCount){
     fColCount = colCount;
     fRowCount = rowCount;
  }

  void MemoryAllocate(){
    CalculateMemorySize();
    fBaseAdress = (Type*)malloc(fMemorySize);
  }

  void MemoryFree(){
    free(fBaseAdress);   
  }
public:
 DimensionalArray(int32_t colCount,int32_t rowCount):
   fColCount(colCount),
   fRowCount(rowCount){
   MemoryAllocate();
 }
 ~DimensionalArray() {
   MemoryFree();
 }      
public:
 Type GetElement(int32_t colIndex, int32_t rowIndex){
     Type* elementAdress = CalculateElementAdress(colIndex,rowIndex);
     return *elementAdress;
 }
 
 void SetElement(int32_t colIndex, int32_t rowIndex, Type value){
     Type* elementAdress = CalculateElementAdress(colIndex,rowIndex);
     *elementAdress = value;
 }

 void ReSize(int32_t colCount,int32_t rowCount){
    MemoryFree();
    SetColAndRowCount(colCount,rowCount);
    fMemorySize = CalculateMemorySize();
    fBaseAdress = (Type*)realloc(fBaseAdress,fMemorySize);
 }

 int32_t GetColCount(){
   return fColCount;
 }

 int32_t GetRowCount(){
   return fRowCount;
 }
};


int main(){    
   try{
       DimensionalArray myTwoDimensionArray(2,2); // 2 sütun, 2 satır
       myTwoDimensionArray.SetElement(0,0,31); // 1. kolon, 1. satır.
       myTwoDimensionArray.SetElement(1,0,32); // 2. kolon, 1. satır

       myTwoDimensionArray.SetElement(0,1,33); // 1. kolon, 2. satır
       myTwoDimensionArray.SetElement(1,1,34); // 2. kolon, 2. satır
       
       /*
       int32_t value_0_0 = myTwoDimensionArray.GetElement(0,0); 
       std::cout << "1. kolon, 1. satır Değeri: " << value_0_0 << std::endl;
       int32_t value_1_0 = myTwoDimensionArray.GetElement(1,0); 
       std::cout << "2. kolon, 1. satır Değeri: " << value_1_0 << std::endl;

       int32_t value_0_1 = myTwoDimensionArray.GetElement(0,1); 
       std::cout << "1. kolon, 2. satır Değeri: " << value_0_1 << std::endl;
       int32_t value_1_1 = myTwoDimensionArray.GetElement(1,1);  
       std::cout << "2. kolon, 2. satır Değeri: " << value_1_1 << std::endl;
     */

       // test
       for (size_t colIndex = 0; colIndex < myTwoDimensionArray.GetColCount(); colIndex++){
         for (size_t rowIndex = 0; rowIndex < myTwoDimensionArray.GetRowCount(); rowIndex++){
             int32_t value = myTwoDimensionArray.GetElement(colIndex,rowIndex);
             std::cout << "["<< colIndex << "," << rowIndex <<"]" << value << std::endl;
         }      
       }
   }
   catch(const std::exception& e){
     std::cerr << e.what() << '\n';
   }
   
   system("pause");
   return EXIT_SUCCESS;
}


3 Boyutlu Dinamik Array implementasyonu (C++)
/*
 Author   : isocan
 Purpose  : How to implement Three-dimensional dynamic array using pointers.
 DateTime : 21.11.2019

 Write Great Code: Volume 1: Understanding the Machine
 Composite Data Types and Memory Objects

 Type variable[Depth_Size][Col_Size][Row_Size];
 Element_Adress = Base_Adress + ( (Depth_Index * Col_Size + Col_Index) * Row_Size + Row_Index) * Element_Size
*/
#include <cstdint>
#include <string> 
#include <stdexcept>
#include <sstream>
#include <iostream>

template 
class ThreeDimensionalArray{
private:
  const std::string IndexOutOfRangeException = "IndexOutOfRangeException at "; 
  Type* fBaseAdress;  
  int32_t fColCount;
  int32_t fRowCount;
  int32_t fDepthSize;
  int32_t fMemorySize;
private:
  std::string ToString(int32_t value){
     std::string outString;
     std::stringstream ss;
     ss << value;
     outString = ss.str();
     return outString;
  }

  std::string GetMessage(std::string indexName,int32_t index){
     return std::string(IndexOutOfRangeException + indexName + "["+ ToString(index)+"]");
  }

  void RangeCheck(int32_t depthIndex, int32_t colIndex, int32_t rowIndex){
   if ((depthIndex < 0) || (colIndex > fDepthSize - 1))
      throw std::out_of_range(GetMessage("depthIndex",depthIndex).c_str());

    if ((colIndex < 0) || (colIndex > fColCount - 1))
      throw std::out_of_range(GetMessage("colIndex",colIndex).c_str());

    if ((rowIndex < 0) || (rowIndex > fRowCount - 1))
      throw std::out_of_range(GetMessage("rowIndex",rowIndex).c_str());
  }

  int32_t Offset(int32_t depthIndex, int32_t colIndex, int32_t rowIndex){
    RangeCheck(depthIndex,colIndex,rowIndex);    
    return ( (depthIndex * fColCount + colIndex) * fRowCount + rowIndex) * sizeof(Type);
  } 

  Type* CalculateElementAdress(int32_t depthIndex, int32_t colIndex, int32_t rowIndex){
    return fBaseAdress + Offset(depthIndex, colIndex, rowIndex);
  }

  void CalculateMemorySize(){
    fMemorySize = sizeof(Type) * fDepthSize * (fColCount * fRowCount);
  }
  
  void SetDepthAndColAndRowCount(int32_t depthSize,int32_t colCount,int32_t rowCount){
     fDepthSize = depthSize;
     fColCount = colCount;
     fRowCount = rowCount;
  }

  void MemoryAllocate(){
    CalculateMemorySize();
    fBaseAdress = (Type*)malloc(fMemorySize);
  }

  void MemoryFree(){
    free(fBaseAdress);   
  }
public:
 ThreeDimensionalArray(int32_t depthSize,int32_t colCount,int32_t rowCount):
   fDepthSize(depthSize),
   fColCount(colCount),
   fRowCount(rowCount){
   MemoryAllocate();
 }
 ~ThreeDimensionalArray() {
   MemoryFree();
 }      
public:
 Type GetElement(int32_t depthIndex,int32_t colIndex, int32_t rowIndex){
     Type* elementAdress = CalculateElementAdress(depthIndex,colIndex,rowIndex);
     return *elementAdress;
 }
 
 void SetElement(int32_t depthIndex,int32_t colIndex, int32_t rowIndex, Type value){
     Type* elementAdress = CalculateElementAdress(depthIndex,colIndex,rowIndex);
     *elementAdress = value;
 }

 void ReSize(int32_t depthSize, int32_t colCount,int32_t rowCount){
    MemoryFree();
    SetDepthAndColAndRowCount(depthSize,colCount,rowCount);
    CalculateMemorySize();
    fBaseAdress = (Type*)realloc(fBaseAdress,fMemorySize);
 }

 int32_t GetColCount(){
   return fColCount;
 }

 int32_t GetRowCount(){
   return fRowCount;
 }

 int32_t GetDepthSize(){
   return fDepthSize;
 }

 int32_t GetMemorySize(){
   return fMemorySize;
 }
};

int main(){    
   ThreeDimensionalArray anArray(2,2,2); // 2 adet, 2 sütun, 2 satırlık tablo

   // access elements ( set)
   for (size_t depthIndex = 0; depthIndex < anArray.GetDepthSize(); depthIndex++)
        for (size_t colIndex = 0; colIndex < anArray.GetColCount(); colIndex++)
            for (size_t rowIndex = 0; rowIndex < anArray.GetRowCount(); rowIndex++)
                    anArray.SetElement(depthIndex,colIndex,rowIndex, depthIndex + colIndex + rowIndex);

   // access elements ( get)
   for (size_t depthIndex = 0; depthIndex < anArray.GetDepthSize(); depthIndex++)
        for (size_t colIndex = 0; colIndex < anArray.GetColCount(); colIndex++)
            for (size_t rowIndex = 0; rowIndex < anArray.GetRowCount(); rowIndex++)
                  std::cout <<  anArray.GetElement(depthIndex,colIndex,rowIndex) << std::endl;
 
   system("pause");
   return EXIT_SUCCESS;
}


2 Boyutlu Dinamik Array implementasyonu (C#)
/*
 Author   : isocan
 Purpose  : How to implement dimensional dynamic array using pointers.
 DateTime : 18.11.2019

 Write Great Code: Volume 1: Understanding the Machine
 Composite Data Types and Memory Objects
 Type variable[Col_Size][Row_Size]
 Element_Adress = Base_Adress + (Col_Index * Row_Size + Row_Index) * Element_Size

 https://docs.microsoft.com/en-us/dotnet/.../blittable (Unmanaged type constraint)
*/

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

unsafe class DimensionalArray where T : unmanaged
{
   private int colCount;
   private int rowCount;
   private int memorySize;
   private IntPtr baseAdress;

   public DimensionalArray(int colCount, int rowCount)
   {
       SetColAndRowCount(colCount, rowCount);
       MemoryAllocate();
   }

   private int Offset(int colIndex, int rowIndex)
   {
       return (colIndex * rowCount + rowIndex) * Marshal.SizeOf(typeof(T));
   }

   private IntPtr CalculateElementAdress(int colIndex, int rowIndex)
   {
       IntPtr elementAdress = IntPtr.Add(baseAdress, Offset(colIndex, rowIndex));
       return elementAdress;
   }

   private void CalculateMemorySize()
   {
       memorySize = Marshal.SizeOf(typeof(T)) * (colCount * rowCount);
   }

   private void SetColAndRowCount(int colCount, int rowCount)
   {
       this.colCount = colCount;
       this.rowCount = rowCount;
   }

   private void MemoryAllocate()
   {
       CalculateMemorySize();
       baseAdress = Marshal.AllocHGlobal(memorySize);
   }

   private void ReSize(int colCount, int rowCount)
   {
       /*
        cb:IntPtr
        The new size of the allocated block. 
        This is not a pointer; it is the byte count you are requesting, cast to type IntPtr. 
        If you pass a pointer, it is treated as a size.
        https://docs.microsoft.com/en-us/dotnet/...mework-4.8
        */
       MemoryFree();
       SetColAndRowCount(colCount, rowCount);
       CalculateMemorySize();
       baseAdress = Marshal.ReAllocHGlobal(baseAdress, (IntPtr)memorySize);
   }

   private void MemoryFree()
   {
       Marshal.FreeHGlobal(baseAdress);
   }

   public int ColCount { get { return colCount; } }
   public int RowCount { get { return rowCount; } }

   private T* GetElementAdress(int colIndex, int rowIndex)
   {
       void* unTypedElementAdress = CalculateElementAdress(colIndex, rowIndex).ToPointer();
       T* typedElementAdress = (T*)unTypedElementAdress;
       return typedElementAdress;
   }

   public T this[int colIndex, int rowIndex]
   {
       get
       {
           return *GetElementAdress(colIndex, rowIndex);
       }
       set
       {
           *GetElementAdress(colIndex, rowIndex) = value;
       }
   }

   ~DimensionalArray()
   {
       MemoryFree();
   }
}

class Program
{
   static void Main(string[] args)
   {
       DimensionalArray myTwoDimensionArray = new DimensionalArray(2, 2);
       myTwoDimensionArray[0, 0] = 31;
       myTwoDimensionArray[1, 0] = 32;
       myTwoDimensionArray[0, 1] = 33;
       myTwoDimensionArray[1, 1] = 34;

       // test
       for (int colIndex = 0; colIndex < myTwoDimensionArray.ColCount; colIndex++)
       {
           for (int rowIndex = 0; rowIndex < myTwoDimensionArray.RowCount; rowIndex++)
           {
               int value = myTwoDimensionArray[colIndex, rowIndex];
               MessageBox.Show(value.ToString());
           }
       }
   }
}



3 Boyutlu Dinamik Array implementasyonu (C#)
/*
 Author   : isocan
 Purpose  : How to implement Three-dimensional dynamic array using pointers.
 DateTime : 21.11.2019

 Write Great Code: Volume 1: Understanding the Machine
 Composite Data Types and Memory Objects

 Type variable[Depth_Size][Col_Size][Row_Size];
 Element_Adress = Base_Adress + ( (Depth_Index * Col_Size + Col_Index) * Row_Size + Row_Index) * Element_Size

 https://docs.microsoft.com/en-us/dotnet/.../blittable (Unmanaged type constraint)
*/

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

unsafe class ThreeDimensionalArray where T : unmanaged
{
   private const string IndexOutOfRangeException = "IndexOutOfRangeException at %s %d";

   private int depthSize;
   private int colCount;
   private int rowCount;
   private int memorySize;
   private IntPtr baseAdress;

   public ThreeDimensionalArray(int depthSize, int colCount, int rowCount)
   {
       SetDepthAndColAndRowCount(depthSize, colCount, rowCount);
       MemoryAllocate();
   }

   private string GetMessage(string indexName, int index)
   {
       return string.Format(IndexOutOfRangeException, indexName, index);
   }

   private void RangeCheck(int depthIndex, int colIndex, int rowIndex)
   {
       if ((depthIndex < 0) || (colIndex > depthSize - 1))
           throw new Exception(GetMessage("depthIndex", depthIndex));

       if ((colIndex < 0) || (colIndex > colCount - 1))
           throw new Exception(GetMessage("colIndex", colIndex));

       if ((rowIndex < 0) || (rowIndex > rowCount - 1))
           throw new Exception(GetMessage("rowIndex", rowIndex));
   }

   private int Offset(int depthIndex, int colIndex, int rowIndex)
   {
       RangeCheck(depthIndex, colIndex, rowIndex);
       return ((depthIndex * colCount + colIndex) * rowCount + rowIndex) * Marshal.SizeOf(typeof(T));
   }

   private IntPtr CalculateElementAdress(int depthIndex, int colIndex, int rowIndex)
   {
       IntPtr elementAdress = IntPtr.Add(baseAdress, Offset(depthIndex, colIndex, rowIndex));
       return elementAdress;
   }

   private void CalculateMemorySize()
   {
       memorySize = Marshal.SizeOf(typeof(T)) * this.depthSize * (this.colCount * this.rowCount);
   }

   private void SetDepthAndColAndRowCount(int depthSize, int colCount, int rowCount)
   {
       this.depthSize = depthSize;
       this.colCount = colCount;
       this.rowCount = rowCount;
   }

   private void MemoryAllocate()
   {
       CalculateMemorySize();
       baseAdress = Marshal.AllocHGlobal(memorySize);
   }

   private void ReSize(int depthSize, int colCount, int rowCount)
   {
       /*
        cb:IntPtr
        The new size of the allocated block. 
        This is not a pointer; it is the byte count you are requesting, cast to type IntPtr. 
        If you pass a pointer, it is treated as a size.
        https://docs.microsoft.com/en-us/dotnet/...mework-4.8
        */
       MemoryFree();
       SetDepthAndColAndRowCount(depthSize, colCount, rowCount);
       CalculateMemorySize();
       baseAdress = Marshal.ReAllocHGlobal(baseAdress, (IntPtr)memorySize);
   }

   private void MemoryFree()
   {
       Marshal.FreeHGlobal(baseAdress);
   }

   public int DepthSize { get { return depthSize; } }
   public int ColCount { get { return colCount; } }
   public int RowCount { get { return rowCount; } }
   public int MemorySize { get { return memorySize; } }

   private T* GetElementAdress(int depthIndex, int colIndex, int rowIndex)
   {
       void* unTypedElementAdress = CalculateElementAdress(depthIndex, colIndex, rowIndex).ToPointer();
       T* typedElementAdress = (T*)unTypedElementAdress;
       return typedElementAdress;
   }

   public T this[int depthIndex, int colIndex, int rowIndex]
   {
       get
       {
           return *GetElementAdress(depthIndex, colIndex, rowIndex);
       }
       set
       {
           *GetElementAdress(depthIndex, colIndex, rowIndex) = value;
       }
   }

   ~ThreeDimensionalArray()
   {
       MemoryFree();
   }
}

class Program
{
   static void Main(string[] args)
   {
       ThreeDimensionalArray anArray = new ThreeDimensionalArray(2, 2, 2);
       //anArray.MemorySize;

       // set values
       for (int depthIndex = 0; depthIndex < anArray.DepthSize; depthIndex++)
           for (int colIndex = 0; colIndex < anArray.ColCount; colIndex++)
               for (int rowIndex = 0; rowIndex < anArray.RowCount; rowIndex++)
                   anArray[depthIndex, colIndex, rowIndex] = depthIndex + colIndex + rowIndex;

       // access elements
       for (int depthIndex = 0; depthIndex < anArray.DepthSize; depthIndex++)
       {
           for (int colIndex = 0; colIndex < anArray.ColCount; colIndex++)
           {
               for (int rowIndex = 0; rowIndex < anArray.RowCount; rowIndex++)
               {
                   int value = anArray[depthIndex, colIndex, rowIndex];
               }
           }
       }
   }
}

Kaynak kodlara erişim için;
Dynamic Array Implementation[Dimensional]
Dynamic Array Implementation[Three-Dimensional]

Gözümden kaçan şeyler olabilir.Geri bildirimlerinizi, katkılarınızı ve eleştirinizi bekliyorum.
WWW
Cevapla
#2
Çok teşekkürler elinize saglik çok güzel bir makale olmus
Cevapla


Konu ile Alakalı Benzer Konular
Konular Yazar Yorumlar Okunma Son Yorum
  Record Üzerindeki Verilere Dinamik Erişim narkotik 0 2.072 13-04-2019, Saat: 01:41
Son Yorum: narkotik
  Offset Kavramı ve Dinamik Dizi Yapımı ismailkocacan 14 9.478 07-11-2018, Saat: 08:47
Son Yorum: Tuğrul HELVACI



Konuyu Okuyanlar: 1 Ziyaretçi