Jak przypisać jedna wartosc do kilku zmiennych przy uzyciu array ?

Jak przypisać jedna wartosc do kilku zmiennych przy uzyciu array ?
O2
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 47
0

Cześć mam takie cos, ale nie bangla "działa".

Kopiuj
procedure AssignToOneValue(const value: Integer; var values: array of Integer);
var
  i: Integer;
begin
  for i := 0 to High(values) do
    values[i] := value;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  a, b, c, d: Integer;
begin
  AssignToOneValue(10, [a, b, c, d]);  // Zmiennym a, b, c, d przypisze wartość 10
end;

Delphi wyświetla taki błąd: w lini AssignToOneValue(10, [a, b, c, d]); // Zmiennym a, b, c, d przypisze wartość 10
Constant object cannot be passed as var parameter

Wiem że można zrobić chociazby tak i na bank zadziala, ale nie o to mi chodzi.

Kopiuj
procedure AssignToOneValue(const value: Integer; var a, b, c, d: Integer);
begin
  a := value;
  b := value;
  c := value;
  d := value;
end;

Powiedzmy ze w przyszlym kodzie mam a,b,c,d,e,f,g,h itd zmiennych i chce im przypisac jedna wartosc.

Macie jakies pomysly jak to ogarnac ? I czy jest to w ogole możliwe.

Riddle
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 10227
2

Możesz przekazać samą tablicę, bez var, ale wtedy ta funkcja zmieni wartości w tablicy. Nie zmieni to orginalnych zmiennych.

Kopiuj
procedure TForm1.Button1Click(Sender: TObject);
var
  a, b, c, d: Integer;
  arr: array of Integer
begin
  arr := [a, b, c, d];
  AssignToOneValue(10, arr);
  arr[0]; // 10
  a; // uninitialized
end;

Na moje oko to próbujesz zrobić coś bardzo dziwnego, po co chcesz ustawiać 4 zmienne na tą samą wartość? 🧐

O2
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 47
0
Riddle napisał(a):

Możesz przekazać samą tablicę, bez var, ale wtedy ta funkcja zmieni wartości w tablicy. Nie zmieni to orginalnych zmiennych.

Wiem, że tak można, ale nie o to chodzi, wszystko ma byc w jednej lini kodu 👌

Na moje oko to próbujesz zrobić coś bardzo dziwnego, po co chcesz ustawiać 4 zmienne na tą samą wartość? 🧐

Robie skomplikowana animacje gdzie mam tysiace zmiennych ktore czesto maja ta sama wartosc i chcialem sobie uproscic. Sam Integer dalem dla przykladu.

Riddle
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 10227
0
Observer2323 napisał(a):

Robie skomplikowana animacje gdzie mam tysiace zmiennych ktore czesto maja ta sama wartosc i chcialem sobie uproscic. Sam Integer dalem dla przykladu.

Pokażesz jak to wygląda?

Zdaje mi się że to co próbujesz zrobić, da się ogarnąć bez takich cyrków. Tylko musiałbyś pokazać do tego używasz tych zmiennych.

flowCRANE
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Tuchów
  • Postów: 12269
3

W tej linijce:

Kopiuj
AssignToOneValue(10, [a, b, c, d]);  // Zmiennym a, b, c, d przypisze wartość 10

tworzysz tablicę, która będzie zawierać cztery elementy, o wartościach takich jak zmienne a, b, c i d i ta tablica zostaje przekazana do procedury jako stała. Kompilator wyrzuca błąd, dlatego że procedura ta potrzebuje macierzy przekazanej przez referencję, a tak można przekazywać jedynie zmienne (tzn. można to obejść podając jakikolwiek wskaźnik, ale trzeba wiedzieć co się robi).

Observer2323 napisał(a):

Robie skomplikowana animacje gdzie mam tysiace zmiennych ktore czesto maja ta sama wartosc i chcialem sobie uproscic. Sam Integer dalem dla przykladu.

Naucz się używać wskaźników i wypełniaj bufory jak tylko chcesz. 😉

Jeśli potrzebujesz mieć funkcję, która wypełni cały bufor takimi samymi blokami danych, to wszystko czego potrzebujesz to pointer na początek bufora, pointer na blok (do skopiowania do bufora), rozmiar bloku danych (tzw. stride) oraz liczba bloków wchodzących w skład bufora.

obscurity
  • Rejestracja: dni
  • Ostatnio: dni
3

Nie mam żadnego kompilatora żeby sprawdzić, ale jedyne co mi przychodzi do głowy to żeby przekazać tablicę wskaźników i zrobić coś w stylu:

Kopiuj
procedure AssignToOneValue(const value: Integer; values: array of PInteger);
var
  i: Integer;
begin
  for i := 0 to High(values) do
    values[i]^ := value;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  a, b, c, d: Integer;
begin
  AssignToOneValue(10, [@a, @b, @c, @d]);  // Zmiennym a, b, c, d przypisze wartość 10
end;
Observer2323 napisał(a):

Robie skomplikowana animacje gdzie mam tysiace zmiennych ktore czesto maja ta sama wartosc i chcialem sobie uproscic. Sam Integer dalem dla przykladu.

To nie brzmi dobrze. Masz tysiące zmiennych poza tablicą?

FP
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 37
2

Cześć, podpowiem jakbym ja to zrobił skoro tobie na tym zależy

Najprościej będzie użyć Wskazików

dla przykładu:

Kopiuj
type
  PInteger = ^Integer;

Spróbuj tak:

Kopiuj
// Definiujemy typ PInteger, który jest wskaźnikiem do Integer.
type
  PInteger = ^Integer;

procedure AssignToOneValue(const value: Integer; const values: array of PInteger);
var
  i: Integer;
begin
  for i := Low(values) to High(values) do
    // używamy operatora ^ do dereferencji wskaźnika i przypisania wartości.
    values[i]^ := value; 
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  a, b, c, d: Integer;
begin
{
   W wywołaniu procedury używamy operatora @ do pobrania adresu zmiennych.

   To rozwiązanie pozwala na elastyczne przypisywanie wartości do dowolnej liczby zmiennych. 
   Działa ono, ponieważ przekazujemy adresy zmiennych, a nie same zmienne.
}
  
  AssignToOneValue(10, [@a, @b, @c, @d]);

  // Dla pewności sprawdzimy wartosci
  ShowMessage( Format('Watosc a:%d, b:%d, c:%d, d:%d', [a,b,c,d]) );
end;
flowCRANE
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Tuchów
  • Postów: 12269
0

Najprościej akurat będzie użyć generyków, żeby nie przyspawać procedury tylko do jednego typu danych. 😛

Czy kolejność zmiennych podawanych do tej procedury zawsze jest zgodna z ich kolejnością w pamięci? No i czy wszystkie zmienne są w pamięci obok siebie, czy są porozrzucane w różnych jej miejscach?

Riddle
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 10227
0

Ja bym poprosił @Observer2323 o pokazanie jego przypadku użycia, bo mam wrażenie że to co robi to X/Y, i jego problem można rozwiązać znacznie prościej.

flowCRANE
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Tuchów
  • Postów: 12269
3

Tutaj przykład wykorzystujący generyki (test w FPC dla trybu zgodności z Delphi):

Kopiuj
{$MODE DELPHI}{$H+}

  procedure AssignToOneValue<T>(const Value: T; const Values: array of T);
  var
    I: Integer;
  begin
    for I := 0 to High(Values) do
      Values[I]^ := Value^;
  end;

var
  A: Integer = 7;
  B: Integer = 0;
  C: Integer = 0;
  D: Integer = 0;
begin
  // Content before
  WriteLn('A:', A, ' B:', B, ' C: ', C, ' D:', D);

  // Copy A to B, C and D
  AssignToOneValue<PInteger>(@A, [@B, @C, @D]);

  // Content after
  WriteLn('A:', A, ' B:', B, ' C: ', C, ' D:', D);
end.

Wyjście:

Kopiuj
A:7 B:0 C: 0 D:0
A:7 B:7 C: 7 D:7

Jedna procedura, dzięki której można skopiować dane do dowolnej liczby wolnych zmiennych (w dowolnej ich kolejności), jednocześnie bez przywiązywania jej sygnatury do konkretnego typu danych.

Można też skorzystać z generycznego iteratora i pętli for in:

Kopiuj
procedure AssignToOneValue<T>(const Value: T; const Values: array of T);
var
  I: T;
begin
  for I in Values do
    I^ := Value^;
end;
O2
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 47
0

Panowie czytam wasze odpowiedzii i testuje sobie w delphi. Bez obaw, nikogo nie lekceważe

FP
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 37
2

@Observer2323 Poradziłeś sobie, sprawdziłeś to co dałem wyżej?

Widzę że @furious programming dał dobry patent, a mianowicie programowanie generyczne

furious programming napisał(a):

Można też skorzystać z generycznego iteratora i pętli for in:

Kopiuj
procedure AssignToOneValue<T>(const Value: T; const Values: array of T);
var
  I: T;
begin
  for I in Values do
    I^ := Value^;
end;

Dobry pomysl, ale nie zadziala na starszych wersjach Delphi :) Nie wiem nawet czy i nie na nowych, bo iteracja nie jest do konca poprawna.

Pomogę 🙃

Załóżny że nasza głowna forma (formualrz) nazwiemy MainForm, a przycisk na nim TestBtn

Teraz tak, ważne aby do Uses dodać:

Kopiuj
System.SysUtils, System.Rtti, System.TypInfo;

następnie

Kopiuj
type
  PVariant = ^Variant;

via

Kopiuj
type
  PVariant = ^Variant;

type
  TMainForm = class(TForm)
    TestBtn: TButton;
    procedure TestBtnClick(Sender: TObject);
  private
    { Private declarations }
    procedure AssignToMultipleVars<T>(const Value: T; const Values: array of PVariant);
  public
    { Public declarations }
  end;

Proszę bardzo kod:

Kopiuj
// Generyczna procedura do przypisywania wartości do wielu zmiennych
procedure TMainForm.AssignToMultipleVars<T>(const Value: T; const Values: array of PVariant);
var
  i: Integer;
  ctx: TRttiContext;
  rttiType: TRttiType;
  v: Variant;
  val: TValue;
begin
  ctx := TRttiContext.Create;
  try
    rttiType := ctx.GetType(TypeInfo(T));
    val := TValue.From<T>(Value);

    // Sprawdzenie typu za pomocą RTTI i przypisanie odpowiedniego typu do Variant
    case rttiType.TypeKind of
      tkInteger, tkInt64:                          // Integer
        v := val.AsInteger;
      tkUString, tkString, tkChar, tkWChar:        // String
        v := val.ToString;
      tkFloat:                                    // Float
        v := val.AsExtended;

      // mozemy dodac inne
    else
      raise Exception.Create('Unsupported type for assignment to Variant');
    end;

    // Przypisujemy wartość do zmiennych PVariant
    for i := Low(Values) to High(Values) do
    begin
      if Assigned(Values[i]) then
        Values[i]^ := v;
    end;
  finally
    ctx.Free;
  end;
end;

procedure TMainForm.TestBtnClick(Sender: TObject);
var
  a, b, c, d: Variant;
  s: Variant;
  f: Variant;
  msgTxt: string;
begin
  // Przypisanie wartości 10 do wszystkich zmiennych całkowitych jednocześnie
  AssignToMultipleVars<Integer>(10, [@a, @b, @c, @d]);

  // Przypisanie wartości do zmiennej string
  AssignToMultipleVars<string>('Test', [@s]);

  // Przypisanie wartości do zmiennej zmiennoprzecinkowej
  AssignToMultipleVars<Double>(12.3, [@f]);

  // sprawdzamy wersje Delphi
 {$IF CompilerVersion >= 36} // Delphi 12 Athens lub nowszy

  // Zmiana formatowania z użyciem explicit konwersji
  msgTxt := Format(
    'Wartości a: %d, b: %d, c: %d, d: %d, s: %s, f: %f',
    [Integer(a), Integer(b), Integer(c), Integer(d), string(s), Double(f)]
  );
 {$ELSE}
 // w nowszych wersjach powinno zadzialac
  msgTxt := Format(
    'Wartości a: %d, b: %d, c: %d, d: %d, s: %s, f: %f',
    [a, b, c, d, s, f]

 {$IFEND}

  // wyswietl wartosci
  ShowMessage(msgTxt);
end;

Wrzucilem cały kod, jak ktoś chce może pobrać: KLIK

EDIT:
Jak ktoś ogarnia Assembler'a, możemy użyć ASM

Kopiuj
procedure TMainForm.AssignIntToMultipleVars(const Value: Integer; const Values: array of PVariant);
asm
  // EAX zawiera Value
  // EDX zawiera wskaźnik do tablicy Values
  // ECX zawiera długość tablicy Values

  push esi
  push edi
  mov esi, edx  // ESI wskazuje na tablicę Values
  mov edi, ecx  // EDI to licznik pętli

@loop:
  test edi, edi
  jz @done
  mov edx, [esi]  // Załaduj adres PVariant do EDX
  test edx, edx   // Sprawdź, czy wskaźnik nie jest nil
  jz @next
  mov [edx], eax  // Przypisz wartość (EAX) do Variant

@next:
  add esi, 4      // Przesuń wskaźnik na następny element tablicy
  dec edi         // Zmniejsz licznik
  jmp @loop

@done:
  pop edi
  pop esi
end;
O2
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 47
0

Działa, a nie kompiluje sie

Kopiuj
 msgTxt := Format(
    'Wartości a: %d, b: %d, c: %d, d: %d, s: %s, f: %f',
    [a, b, c, d, s, f]
);

faktycznie trzeba dac tak:

Kopiuj
 msgTxt := Format(
    'Wartości a: %d, b: %d, c: %d, d: %d, s: %s, f: %f',
    [Integer(a), Integer(b), Integer(c), Integer(d), string(s), Double(f)]
  );
FP
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 37
1

Ten sam kod co wyżej, ale pod Lazarus. Implementację daj po swojemu, ja tylko dalem przyklad.

Kopiuj
unit main;

{$MODE DELPHI}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls,
  TypInfo, Variants;

type
  TVariantArray = array of PVariant;

type

  { TMainForm }

  TMainForm = class(TForm)
    TestBtn: TButton;
    procedure TestBtnClick(Sender: TObject);
  private
    procedure AssignToMultipleVars<T>(const Value: T; const Values: TVariantArray);
  public

  end;

var
  MainForm: TMainForm;

implementation

{$R *.lfm}

{ TMainForm }

procedure TMainForm.AssignToMultipleVars<T>(const Value: T;
  const Values: TVariantArray);
var
  TypeInfo: PTypeInfo;
  v: Variant;
  i: Integer;
begin
  TypeInfo := System.TypeInfo(T);

  // Sprawdzenie typu i przypisanie odpowiedniego typu do Variant
  case TypeInfo^.Kind of
    tkInteger, tkInt64:                 // Integer
      v := PInteger(@Value)^;
    tkAString, tkString, tkChar:       // String
      v := PString(@Value)^;
    tkFloat:                           // Float
      v := PExtended(@Value)^;
    // Możemy dodać inne typy w razie potrzeby
  else
    raise Exception.Create('Unsupported type for assignment to Variant');
  end;

  // Przypisujemy wartość do zmiennych PVariant
  for i := Low(Values) to High(Values) do
  begin
    if Assigned(Values[i]) then
      Values[i]^ := v;
  end;
end;

procedure TMainForm.TestBtnClick(Sender: TObject);
var
  a, b, c, d: Variant;
  s: Variant;
  f: Variant;
  msgTxt: string;
begin
  // Przypisanie wartości 10 do wszystkich zmiennych całkowitych jednocześnie
   AssignToMultipleVars<Integer>(10, TVariantArray.Create(@a, @b, @c, @d));

  // Przypisanie wartości do zmiennej string
   AssignToMultipleVars<string>('Test', TVariantArray.Create(@s));

  // Przypisanie wartości do zmiennej zmiennoprzecinkowej
   AssignToMultipleVars<Double>(12.3, TVariantArray.Create(@f));

  // Formatowanie wiadomości
  msgTxt := Format(
    'Wartości a: %d, b: %d, c: %d, d: %d, s: %s, f: %f',
    [Integer(a), Integer(b), Integer(c), Integer(d), string(s), Double(f)]
  );

  // Wyświetl wartości
  ShowMessage(msgTxt);
end;

end.



O2
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 47
0
furious programming napisał(a):

Tutaj przykład wykorzystujący generyki (test w FPC dla trybu zgodności z Delphi):

Jezeli chodzi o FPC, zrobilem tak, dziala 🙂

Kopiuj
{$MODE DELPHI}{$H+}

procedure AssignToOneValue<T>(const Value: T; const Values: array of PPointer);
var
  I: Integer;
begin
  for I := 0 to High(Values) do
    PInteger(Values[I])^ := Value; // Używamy PInteger do dereferencji
end;

var
  A: Integer = 0;
  B: Integer = 0;
  C: Integer = 0;
  D: Integer = 0;
begin
  // Zawartość przed
  WriteLn('A:', A, ' B:', B, ' C:', C, ' D:', D);

  // Przypisanie wartości 10 do A, B, C i D
  AssignToOneValue<Integer>(10, [@A, @B, @C, @D]);

  // Zawartość po
  WriteLn('A:', A, ' B:', B, ' C:', C, ' D:', D);
  
  Readln();
end.

image

flowCRANE
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Tuchów
  • Postów: 12269
3

@Observer2323: wszystko fajnie, tyle że po to używa się generyków, aby mieć wolność co do używanego typu danych, czyli co do specjalizacji wywołania. Ty co prawda zostawiłeś sygnaturę taką jaka była (czyli funkcja jest nadal generyczna), ale wewnątrz niej wykorzystujesz rzutowanie na PInteger, a to sprawia, że tej funkcji — pomimo bycia generyczną — nie da się użyć na zmiennych o innych typach danych niż Integer.

Jeśli interesuje Cię funkcja umożliwiająca przypisanie tej samej wartości do dowolnego zbioru luźnych zmiennych i z możliwością obsługi dowolnych typów danych, to skorzystaj z wersji, którą podałem wcześniej:

Kopiuj
procedure AssignToOneValue<T>(const Value: T; const Values: array of T);
var
  I: Integer;
begin
  for I := 0 to High(Values) do
    Values[I]^ := Value^;
end;

Ona wymaga podania wskaźników tego samego typu zarówno dla Value, jak i dla macierzy Values, nie da się przekazać stałej wartości dla parametru Value (musi to być wskaźnik na zmienną lub dynamicznie zaalokowaną pamięć). W razie czego możesz rozszerzyć sygnaturę o drugi typ generyczny i przekazywać dane przez wartość (w parametrze Value):

Kopiuj
{$mode delphi}{$H+}

  procedure AssignToOneValue<T1, T2>(const Value: T1; const Values: array of T2);
  var
    I: Integer;
  begin
    for I := 0 to High(Values) do
      Values[I]^ := Value;
  end;

var
  A: Integer = 0;
  B: Integer = 0;
  C: Integer = 0;
begin
  WriteLn('A:', A, ' B:', B, ' C:', C);

  AssignToOneValue<Integer, PInteger>(16, [@A, @B, @C]);

  WriteLn('A:', A, ' B:', B, ' C:', C);
end.

BTW: Ta funkcja powinna się nazywać AssignOneToMany — obecna jej nazwa jest nieprawidłowa.

BTW2: Nie wrzucaj zrzutów ekranu kodu, a kod w formie tekstu, tak aby można go było skopiować z posta i samodzielnie sprawdzić w IDE. Natomiast jeśli już potrzebujesz wrzucić obrazek, to wklej go ze schowka bezpośrednio w treści posta (albo załaduj załącznik z pliku). Nigdy nie używaj zewnętrznych hostingów do hostowania forumowych załączników.

O2
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 47
0
furious programming napisał(a):

@Observer2323: wszystko fajnie, tyle że po to używa się generyków, aby mieć wolność co do używanego typu danych, czyli co do specjalizacji wywołania. Ty co prawda zostawiłeś sygnaturę taką jaka była (czyli funkcja jest nadal generyczna), ale wewnątrz niej wykorzystujesz rzutowanie na PInteger, a to sprawia, że tej funkcji — pomimo bycia generyczną — nie da się użyć na zmiennych o innych typach danych niż Integer.

Racja

O2
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 47
0

Dochodzę do wniosku, że najlepszym rozwiazaniem będzie uzycie wskaznikow

Riddle
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 10227
0
Observer2323 napisał(a):

Dochodzę do wniosku, że najlepszym rozwiazaniem będzie uzycie wskaznikow

Albo mógłbyś pokazać przykład użycia tych czterech zmiennych w Twoim kodzie?

O2
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 47
0

@Riddle

Kopiuj

type
  PInteger = ^Integer;
  PDouble = ^Double;
  // inne w razie potrzeby

procedure AssignToOneValue(const value: Integer; const values: array of PInteger); overload;
begin
  for var i := Low(values) to High(values) do
    values[i]^ := value;
end;

procedure AssignToOneValue(const value: Double; const values: array of PDouble); overload;
begin
  for var i := Low(values) to High(values) do
    values[i]^ := value;
end;

procedure TMainForm.OkBtnClick(Sender: TObject);
const
  sLineBreak = {$IFDEF LINUX} AnsiChar(#10) {$ENDIF}
               {$IFDEF MSWINDOWS} AnsiString(#13#10) {$ENDIF};
var
  a, b, c, d: Integer;
  x, y: Double;
  txt: string;
begin
  AssignToOneValue(10, [@a, @b, @c, @d]);  // Integer
  AssignToOneValue(22.5, [@x, @y]);        // Double
   
  txt := 'Wartosci Integer: a:%d, b:%d, c:%d, d:%d' + sLineBreak +
         'Wartosci Double: x:%f, y:%f';

  // sprawdzamy wartosci
  ShowMessage( Format(txt, [a,b,c,d,x,y]) );
end;


Riddle
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 10227
0
Observer2323 napisał(a):
Kopiuj
var
  a, b, c, d: Integer;
  x, y: Double;
  txt: string;
begin
  AssignToOneValue(10, [@a, @b, @c, @d]);  // Integer
  AssignToOneValue(22.5, [@x, @y]);        // Double
   
  txt := 'Wartosci Integer: a:%d, b:%d, c:%d, d:%d' + sLineBreak +
         'Wartosci Double: x:%f, y:%f';

  // sprawdzamy wartosci
  ShowMessage( Format(txt, [a,b,c,d,x,y]) );
end;

Jeśli na prawdę to jest Twój use-case, to moim zdaniem to jest zupełnie niepotrzebne, i to samo mógłbyś załatwić po prostu robiąc:

Kopiuj
txt := 'Wartosci Integer: a:%d, b:%d, c:%d, d:%d' + sLineBreak +
       'Wartosci Double: x:%f, y:%f';

ShowMessage( Format(txt, [10, 10, 10, 10, 22.5, 22.5]) );

Natomiast wydaje mi się że to nie jest Twój use-case, bo wcześniej mówiłeś coś o jakichś obliczeniach

Observer2323 napisał(a):

Robie skomplikowana animacje gdzie mam tysiace zmiennych ktore czesto maja ta sama wartosc i chcialem sobie uproscic. Sam Integer dalem dla przykladu.

Więc jeśli mógłbyś pokazać ten kod? Bo jestem na 99% przekonany że da się to obejść bez tej funkcji AssignToOneValue().

O2
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 47
0

@Riddle Ja dałem tylko przykład jak można użyć, nie kod który pisze.

To co podałeś, zupelnie nie o to mi chodzi. To jest const, nie zmienne, a nie o to chodzi.

Kopiuj
ShowMessage( Format(txt, [10, 10, 10, 10, 22.5, 22.5]) );

Ten kod który dałem wyżej, jest ok, w zupełności mi wystarcza. Fakt że użyłem przeciążenia w funkcjach (void) ale od czego niby jest, jak do korzystanie z niego.

Pozdrawiam.

Riddle
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 10227
0
Observer2323 napisał(a):

@Riddle Ja dałem tylko przykład jak można użyć, nie kod który pisze.

No to pokaż kod który piszesz, jeśli możesz.

Bo jak mówiłem, bardzo trudno mi sobie wyobrazić sensowny case wielokrotnego przypisywania do zmiennych tej samej wartości, który jest na tyle powtarzalny żeby robić do niego aż funkcję która ustawia te zmienne 😐

Moim zdaniem, na 99% to x/y.

O2
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 47
0

Zmienne maja co sekundy inną wartosc, ale w wiekszosci identyczna. Dlatego potrzebowalewam takiego kodu :)

dla przykładu, dodam ze bardzo uproszczony, nie bede wklejal kilka tysicy lini kodu:

Kopiuj

type
  PDouble = ^Double;

  // Struktura obiektu na scenie
  TObject2D = record
    X, Y: Double;      // Pozycja obiektu
    Vx, Vy: Double;    // Prędkość w kierunku X i Y
  end;

var
  obj1, obj2, obj3: TObject2D; // Trzy obiekty na scenie
  pX1, pX2, pX3: PDouble;      // Wskaźniki na pozycje X obiektów
  pY1, pY2, pY3: PDouble;      // Wskaźniki na pozycje Y obiektów
  pVx1, pVx2, pVx3: PDouble;   // Wskaźniki na prędkości X obiektów
  pVy1, pVy2, pVy3: PDouble;   // Wskaźniki na prędkości Y obiektów

procedure UpdateObjectPosition(var obj: TObject2D);
begin
  obj.X := obj.X + obj.Vx;
  obj.Y := obj.Y + obj.Vy;
end;

begin
  // Inicjalizacja obiektów
  obj1 := TObject2D.Create;
  obj2 := TObject2D.Create;
  obj3 := TObject2D.Create;
  
  // Przypisanie wskaźników do pozycji i prędkości
  pX1 := @obj1.X; pY1 := @obj1.Y; pVx1 := @obj1.Vx; pVy1 := @obj1.Vy;
  pX2 := @obj2.X; pY2 := @obj2.Y; pVx2 := @obj2.Vx; pVy2 := @obj2.Vy;
  pX3 := @obj3.X; pY3 := @obj3.Y; pVx3 := @obj3.Vx; pVy3 := @obj3.Vy;
  
  // Pętla animacji (symulujemy 5 klatek)
  for var frame := 1 to 5 do
  begin
    Writeln('Klatka animacji: ', frame);
    
    // Aktualizacja pozycji obiektów na podstawie ich prędkości
    UpdateObjectPosition(obj1);
    UpdateObjectPosition(obj2);
    UpdateObjectPosition(obj3);
    
    // Wyświetlenie pozycji obiektów
    Writeln('  Obiekt 1: X=', obj1.X:0:2, ', Y=', obj1.Y:0:2);
    Writeln('  Obiekt 2: X=', obj2.X:0:2, ', Y=', obj2.Y:0:2);
    Writeln('  Obiekt 3: X=', obj3.X:0:2, ', Y=', obj3.Y:0:2);
    
    // Resetowanie pozycji i prędkości obiektów co klatkę
    AssignToOneValue(0.0, [pX1, pY1, pVx1, pVy1, pX2, pY2, pVx2, pVy2, pX3, pY3, pVx3, pVy3]);

   // itd itd itd...
  end;
end.
Riddle
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 10227
2
Observer2323 napisał(a):

Zmienne maja co sekundy inną wartosc, ale w wiekszosci identyczna. Dlatego potrzebowalewam takiego kodu :)

dla przykładu, dodam ze bardzo uproszczony, nie bede wklejal kilka tysicy lini kodu:

Dzięki za kod! 👋

Czy próbujesz ustawić pozycje obiektów obj1, obj2, obj3 na 0.0? Jeśli tak, to moim zdaniem dużo sensowniej byłoby dodać funkcję do TObject2D która to ustawia, i po prostu ją wywołać (ewentualnie funkcję, która przyjmuje TObject2D jako argument). Skoro i tak bierzesz wskaźniki z tych pól, to czemu nie operować bezpośrednio na obiektach, skoro i tak je już masz w tym miejscu?

Np tak:

Kopiuj
type
  TObject2D = record
    X, Y: Double; 
    Vx, Vy: Double;
  end;

var
  obj1, obj2, obj3: TObject2D;

procedure UpdateObjectPosition(var obj: TObject2D);
begin
  obj.X := obj.X + obj.Vx;
  obj.Y := obj.Y + obj.Vy;
end;

procedure Reset(var obj: TObject2D, var arg: Double);
begin
  obj.X := arg;
  obj.Y := arg;
  obj.Vx := arg;
  obj.Vy := arg;
end;

begin
  obj1 := TObject2D.Create;
  obj2 := TObject2D.Create;
  obj3 := TObject2D.Create;
  
  // Pętla animacji (symulujemy 5 klatek)
  for var frame := 1 to 5 do
  begin
    Writeln('Klatka animacji: ', frame);
    
    // Aktualizacja pozycji obiektów na podstawie ich prędkości
    UpdateObjectPosition(obj1);
    UpdateObjectPosition(obj2);
    UpdateObjectPosition(obj3);
    
    // Wyświetlenie pozycji obiektów
    Writeln('  Obiekt 1: X=', obj1.X:0:2, ', Y=', obj1.Y:0:2);
    Writeln('  Obiekt 2: X=', obj2.X:0:2, ', Y=', obj2.Y:0:2);
    Writeln('  Obiekt 3: X=', obj3.X:0:2, ', Y=', obj3.Y:0:2);
    
    // Resetowanie pozycji i prędkości obiektów co klatkę
    Reset(obj1, 0.0);
    Reset(obj2, 0.0);
    Reset(obj3, 0.0);
  end;
end.

Właściwie to nawet więcej sensu by miało gdyby UpdateObjectPosition nie modyfikowała obiektów, tylko zwracała nowe po modyfikacji, wtedy w ogóle nie musiałbyś robić tych resetów, np tak:

Kopiuj
type
  TObject2D = record
    X, Y: Double; 
    Vx, Vy: Double;
  end;

var
  obj1, obj2, obj3: TObject2D;

function UpdateObjectPosition(var obj: TObject2D): TObject2D;
begin
  Result.X := obj.X + obj.Vx;
  Result.Y := obj.Y + obj.Vy;
end;

procedure Reset(var obj: TObject2D, var arg: Double);
begin
  obj.X := arg;
  obj.Y := arg;
  obj.Vx := arg;
  obj.Vy := arg;
end;

begin
  obj1 := TObject2D.Create;
  obj2 := TObject2D.Create;
  obj3 := TObject2D.Create;
  
  // Pętla animacji (symulujemy 5 klatek)
  for var frame := 1 to 5 do
  begin
    Writeln('Klatka animacji: ', frame);
    
    // Aktualizacja pozycji obiektów na podstawie ich prędkości
    obj1_ = UpdateObjectPosition(obj1);
    obj2_ = UpdateObjectPosition(obj2);
    obj3_ = UpdateObjectPosition(obj3);
    
    Writeln('  Obiekt 1: X=', obj1_.X:0:2, ', Y=', obj1_.Y:0:2);
    Writeln('  Obiekt 2: X=', obj2_.X:0:2, ', Y=', obj2_.Y:0:2);
    Writeln('  Obiekt 3: X=', obj3_.X:0:2, ', Y=', obj3_.Y:0:2);
  end;
end.
flowCRANE
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Tuchów
  • Postów: 12269
1

Wszystkie dane dotyczące danego obiektu powinny się znajdować w jego strukturze. No i zaznaczyć też należy, że rekordy mogą posiadać metody — to w razie gdybyś preferował podejście bliższe typowemu OOP.

O2
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 47
0

Panowie to był tylko przykład, kod jest bardziej skomplikowany, nie chce tu wklejac tysiecy lini kodu. Jeszcze ktoś mój pomysł podłapie, zarobi miliony 😀 żarcik

Przecież równie dobrze mogłem dac klase. Chociażby

Kopiuj
type
  // Klasa do reprezentacji obiektu w animacji 2D
  TObject2D = class
  private
    FPosX, FPosY: Double;  // Pozycja obiektu
    FVelX, FVelY: Double;  // Prędkość obiektu
  public
    constructor Create(AX, AY, AVx, AVy: Double);
    procedure UpdatePosition;   // Aktualizacja pozycji na podstawie prędkości
    procedure Reset;            // Resetowanie pozycji i prędkości do zera
    procedure PrintPosition;    // Wyświetlenie aktualnej pozycji
  end;

Reasumująć, przyda mi sie nie raz funkcja AssignToOneValue, a jej intempletacja to juz inna kwestia.

Riddle
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 10227
0
Observer2323 napisał(a):

Reasumująć, przyda mi sie nie raz funkcja AssignToOneValue, a jej intempletacja to juz inna kwestia.

No właśnie chyba nie 😄

Wymyśliłeś sobie że musisz ustawiać dużo zmiennych na raz, ale jak widać tak nie jest.

Observer2323 napisał(a):

Panowie to był tylko przykład, kod jest bardziej skomplikowany, nie chce tu wklejac tysiecy lini kodu.

Możesz wkleić miejsce gdzie ustawiasz te 4 zmienne, i np. 20 linijek z góry i z dołu. Może faktycznie masz legitny przypadek? 🤔

O2
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 47
0

@Riddle kod który dalem w poscie wyżej, znajomy napisal mi tak

Pomogę uprościć:

Zastąpiłem dwie oddzielne procedury AssignToOneValue jedną generyczną procedurą, która może obsłużyć różne typy danych.

na szybko:

Kopiuj

type
  TGenericPointer = pointer;

// Dodałem parametr typeSize, który pozwala procedurze działać z różnymi rozmiarami typów danych.
procedure AssignToOneValue(const value: TGenericPointer; const values: array of TGenericPointer; typeSize: Integer);
var
  i: Integer;
begin
  for i := Low(values) to High(values) do
    // Użyłem funkcji Move do kopiowania wartości, co jest bardziej wydajne i elastyczne niż bezpośrednie przypisanie.
    Move(value^, values[i]^, typeSize);
end;

procedure TMainForm.OkBtnClick(Sender: TObject);
{
const
  sLineBreak jest zbedne,Delphi ma ten const w System
}
var
  a, b, c, d: Integer;
  x, y: Double;
  intValue: Integer;
  doubleValue: Double;
  txt: string;
begin
  intValue := 10;
  doubleValue := 22.5;

  AssignToOneValue(@intValue, [@a, @b, @c, @d], SizeOf(Integer));
  AssignToOneValue(@doubleValue, [@x, @y], SizeOf(Double));

  txt := Format('Wartosci Integer: a:%d, b:%d, c:%d, d:%d%sWartosci Double: x:%f, y:%f',
                [a, b, c, d, sLineBreak, x, y]);

  // obczajamy wartosci
  ShowMessage(txt);
end;

Ten kod jest bardziej zwięzły i elastyczny, pozwalając na łatwe rozszerzenie o nowe typy danych bez konieczności tworzenia nowych przeciążeń procedury AssignToOneValue.

Riddle
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 10227
0
Observer2323 napisał(a):

@Riddle kod który dalem w poscie wyżej, znajomy napisal mi tak

[...]

Ten kod jest bardziej zwięzły i elastyczny, pozwalając na łatwe rozszerzenie o nowe typy danych bez konieczności tworzenia nowych przeciążeń procedury AssignToOneValue.

To jest ten sam przykład co podałeś wcześniej, i tutaj też nie potrzebujesz tej funkcji AssignToOneValue bo możesz po prostu przekazać 10 do Format().

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.