[gelöst]Funktionen richtig verwenden?

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
heheracer
Beiträge: 54
Registriert: Mo 17. Nov 2014, 16:45

[gelöst]Funktionen richtig verwenden?

Beitrag von heheracer »

Hi,
ich wollte mir mal Funktionen anschauen, da ich glaube das sie sehr sinnvoll sind.
Im Internet hab ich aber nicht wirkliche Anleitungen gefunden, nur so 5 zeilige Beispiele quasi ohne Variablen.

Zur Übersichtlichkeit halber will ich meine Funktionen in eine extra Unit machen, damit ich sie auch in anderen Programmen benutzen kann.

Wie ich es mir fast schon gedacht habe will Lazarus die Unit aber nicht kompilieren.

Zuerst meint Lazarus, dass ich unbedingt "function xy: typ" machen muss.
Aber wieso brauche ich diese Ausgabe (wenn ich das so richtig sehe)?

Zum zweiten akzeptiert er meinen mehrdimensionalen Array nicht.
Ohne diesen ist das nutzlos.

Als drittes finde ich leider nirgends eine richtige Anleitung wie ich die Länge von mehrdimensionalen Arrays festlege.
Gut, evtl. liegt es daran, dass man nicht im Code "Array von x nach y" machen kann aber sonst wüsste ich auch nicht wie ich für alle Elemente der ersten Dimension die gleiche Menge an Elementen für die zweite Dimension festlege ohne eine for do Schleife zu benutzen.

MfG und danke im Vorraus,
9Strike

PS: Die Funktionen dienen dazu einer "Map" aus einem zweidimensionalen Array (MapSizeInit) zufällig verteilte Werte zu geben (MapRanCreate) und diese dann zu "glätten" (MapSmooth) das es keine große Differenzen zwischen zwei Feldern gibt. Zu Debug zwecken soll man sich die Werteverteilung in einer Textdatei speichern können um die Anzahl der Glättvorgänge besser anzupassen (MapOutput).

Code: Alles auswählen

unit Cube;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils;
 
var
  nmax, nmin, emax, emin: integer;
 
implementation
 
function Cube_MapSizeInit(map: array of array of integer; xmin, xmax, ymin, ymax: integer);
begin
  emin:=xmin;
  emax:=xmax;
  nmin:=ymin;
  nmax:=ymax;
  setlength(map, xmin..xmax,ymin..ymax);
end;
 
function Cube_MapRanCreate(map: array of array of integer; p, x: integer; a, b: real);
var
  n, e: integer;
begin
  for n:=nmax downto nmin do
    for e:=emin to emax do
      if random(a*100)>p-1
      then
        map[e,n]:=trunc(b*x)
      else
        map[e,n]:=0;
end;
 
function Cube_MapSmooth(map: array of array of integer, x: integer);
var
  t, n, e: integer;
  smap: array of array of integer;
begin
  setlength(smap, emin..emax,nmin..nmax);
  smap[emax,nmax]:=map[emax,nmax];
  smap[emax,nmin]:=map[emax,nmin];
  smap[emin,nmax]:=map[emin,nmax];
  smap[emin,nmin]:=map[emin,nmin];
  for e:=emin+1 to emax-1 do
    begin
      smap[e,nmax]:=trunc((map[e-1,nmax]+map[e,nmax]+map[e+1,nmax])/3);
      smap[e,nmin]:=trunc((map[e-1,nmin]+map[e,nmin]+map[e+1,nmin])/3);
    end;
  for n:=nmax[n-1]-1 downto nmin+1 do
    begin
      smap[emin,n]:=trunc((map[emin,n-1]+map[emin,n]+map[emin,n+1]])/3);
      smap[emax,n]:=trunc((map[emax,n-1]+map[emax,n]+map[emax,n+1]])/3);
    end;
  for t:=1 to x do
    for n:=nmax-1 downto nmin+1 do
      for e:=emin+1 to emax-1 do
        smap[e,n]:=trunc((map[e-1,n+1]+map[e,n+1]+map[e+1,n+1]+map[e-1,n]+map[e,n]*2+map[e+1,n]+map[e-1,n-1]+map[e,n-1]+map[e+1,n-1])/10);
  for n:=nmax downto nmin do
    for e:=emin to emax do
      map[e,n]:=smap[e,n];
end;
 
function Cube_MapOutput(map: array of array of integer; filename: string);
var
  n, e: integer;
  tf: textfile;
begin
  assignfile(tf, filename);
  rewrite(tf);
  for n:=nmax downto nmin do
    begin
      for e:=emin to emax do
        write(tf, map[e,n]:4);
      writeln(tf);
    end;
  closefile(tf);
end;
 
end.
 
Zuletzt geändert von heheracer am Di 19. Mai 2015, 19:33, insgesamt 1-mal geändert.

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2817
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Funktionen richtig verwenden?

Beitrag von m.fuchs »

Hm,

wenn du keinen Rückgabewert benutzen willst, dann solltest du Prozeduren einsetzen (http://www.marcocantu.com/EPascal/German/ch06procde.htm).
Aber eine Funktion wäre da schon sinnvoller.

Für dein Array, musst du vorher einen eigenen Typen deklarieren:

Code: Alles auswählen

type
  TIntTable = array of array of Integer;  
(* ... *)
procedure Cube_MapSizeInit(map: TIntTable; xmin, xmax, ymin, ymax: integer);
(* ... *)
procedure Cube_MapRanCreate(map: TIntTable; p, x: integer; a, b: real);
(* ... *)
procedure Cube_MapSmooth(map: TIntTable; x: integer);
(* ... *)
procedure Cube_MapOutput(map: TIntTable; filename: string);
Ansonsten sehe ich da noch einiges an Fehlern. Die Funktionen/Prozeduren kannst du gar nicht außerhalb der Unit nutzen, da sie nicht öffentlich sind. Deine SetLength-Aufrufe sind unverständlich, etc.
Vielleicht doch noch mal ein wenig Grundlagensammlung betreiben?
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

wp_xyz
Beiträge: 5154
Registriert: Fr 8. Apr 2011, 09:01

Re: Funktionen richtig verwenden?

Beitrag von wp_xyz »

Die Länge eines 1-dim dynamischen Arrays setzt man mit "SetLength(a, N)"; N ist die Anzahl der Arrayelemente. Der Index von a beginnt immer mit 0 und läuft daher bis maximal N-1.

Bei einem 2-dim Array ist der Aufruf entsprechend "SetLength(a, N, M)", hier erstreckt sich das Array über die Elemente a[0, 0]...a[N-1, M-1]

heheracer
Beiträge: 54
Registriert: Mo 17. Nov 2014, 16:45

Re: Funktionen richtig verwenden?

Beitrag von heheracer »

wp_xyz hat geschrieben:Die Länge eines 1-dim dynamischen Arrays setzt man mit "SetLength(a, N)"; N ist die Anzahl der Arrayelemente. Der Index von a beginnt immer mit 0 und läuft daher bis maximal N-1.

Bei einem 2-dim Array ist der Aufruf entsprechend "SetLength(a, N, M)", hier erstreckt sich das Array über die Elemente a[0, 0]...a[N-1, M-1]
Ok danke, ich dachte das muss man irgendwie mit den eckigen Klammern machen. Ich werde es morgen ausprobieren.

Warf
Beiträge: 2122
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Funktionen richtig verwenden?

Beitrag von Warf »

Eine Unit ist eine Pascal Struktur, bestehend aus einem Kopf (unit UnitName), dem Interface Teil, die Schnittstelle zwischen den Units, alles was dort steht ist für andere Units sichtbar, und nur das kann von außen genutzt werden, und dem Implementation Teil, hier kommt der Code rein (auf den der Interface teil verweist) sowie alle Informationen die nicht Global nötig sind (variablen, Konstanten, Uses, die nur intern verwendet werden)
wenn ich das richtige sehe hat

Code: Alles auswählen

 
var
  nmax, nmin, emax, emin: integer;
relativ wenig im Interface Teil verloren, schmeiß dass in den Implementation Teil.
Desweiteren kannst du von außen nicht auf Methoden zugreifen, welche nur im Implementation Teil stehen, daher muss ein verweis darauf in den Interface Teil (so nach dem Motto Schau das habe ich zu bieten). Als verweis musst du einfach nochmal den Kopf der Methode (also z.b. function Cube_MapRanCreate(map: array of array of integer; p, x: integer; a, b: real);) in den Interface Teil schreiben.

Methoden werden in Pascal strikt zwischen Prozeduren(procedure) und Funktionen (function) getrennt, Funktionen müssen einen Rückgabewert haben, Prozeduren dürfen keinen haben.

Außerdem können Dynamische Arrays keine Wertebereiche als Länge haben, der Anfangsindex ist dabei immer 0, und der Max index ist Length(Array)-1, wodurch sich auch eine Redundanz deiner Variablen emin und nmin und nmax und emax ergibt. Nutze lieber 0 als Startindex, und verwende eine feste Größe (die sich per Length(arr) abfragen lässt).

Außerdem versuchst du variablen zu verändern über Call By Value, verwende stattdessen Call by Reference mit dem Keyword Var oder Out

Code: Alles auswählen

unit Cube;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils;
 
type  // Für die Datenübergabe an die Methoden
  TIntMap = array of array of integer;
// Verweise auf die Methoden
 
procedure Cube_MapSizeInit(var map: TIntMap; const LenX, LenY: cardinal); inline;
procedure Cube_MapRanCreate(map: TIntMap; p, x: integer; a, b: real);
procedure Cube_MapSmooth(map: TIntMap; x: integer);
procedure Cube_MapOutput(map: TIntMap; filename: string);
 
implementation
 
const
  emin = 0;
  nmin = 0;
 
procedure Cube_MapSizeInit({Call By Reference}var map: TIntMap;
  {Call by Value} const LenX, LenY: cardinal);
begin
  SetLength(map, LenX, LenY);
end;
 
procedure Cube_MapRanCreate(map: TIntMap; p, x: integer; a, b: real);
var
  n, e: integer;
begin
  for n := Length(map[0]) - 1 downto 0 do
    for e := 0 to Length(map) - 1 do
      if random(trunc(a * 100)) > p - 1 then
        map[e, n] := trunc(b * x)
      else
        map[e, n] := 0;
end;
 
procedure Cube_MapSmooth(map: TIntMap; x: integer);
var
  t, n, e: integer;
  emax, nmax: cardinal;
  smap: TIntMap;
begin
  emax := Length(map) - 1;
  nmax := Length(map[0]) - 1;
  setlength(smap, emax + 1, nmax + 1);
  smap[emax, nmax] := map[emax, nmax];
  smap[emax, nmin] := map[emax, nmin];
  smap[emin, nmax] := map[emin, nmax];
  smap[emin, nmin] := map[emin, nmin];
  for e := emin + 1 to emax - 1 do
  begin
    smap[e, nmax] := (map[e - 1, nmax] + map[e, nmax] + map[e + 1, nmax]) div 3;
    smap[e, nmin] := (map[e - 1, nmin] + map[e, nmin] + map[e + 1, nmin]) div 3;
  end;
  for n := nmax - 1 downto nmin + 1 do
  begin
    smap[emin, n] := (map[emin, n - 1] + map[emin, n] + map[emin, n + 1]) div 3;
    smap[emax, n] := (map[emax, n - 1] + map[emax, n] + map[emax, n + 1]) div 3;
  end;
  for t := 1 to x do
    for n := nmax - 1 downto nmin + 1 do
      for e := emin + 1 to emax - 1 do
        smap[e, n] := (map[e - 1, n + 1] + map[e, n + 1] + map[e + 1, n + 1] + map[e - 1, n] +
          map[e, n] * 2 + map[e + 1, n] + map[e - 1, n - 1] + map[e, n - 1] + map[e + 1, n - 1]) div 10;
  for n := nmax downto nmin do
    for e := emin to emax do
      map[e, n] := smap[e, n];
end;
 
procedure Cube_MapOutput(map: TIntMap; filename: string);
var
  n, e: integer;
  tf: textfile;
begin
  assignfile(tf, filename);
  rewrite(tf);
  for n := nmax downto nmin do
  begin
    for e := emin to emax do
      Write(tf, map[e, n]: 4);
    writeln(tf);
  end;
  closefile(tf);
end;
 
end.

heheracer
Beiträge: 54
Registriert: Mo 17. Nov 2014, 16:45

Re: Funktionen richtig verwenden?

Beitrag von heheracer »

@Warf und m.fuchs

Danke für die Antworten, ihr habt mein Verständnis für Unit/Prozeduren/Funktionen enorm gesteigert. Top.

Ich werde es morgen mal ausprobieren und gucken was hin bekomme.

MfG

heheracer
Beiträge: 54
Registriert: Mo 17. Nov 2014, 16:45

Re: Funktionen richtig verwenden?

Beitrag von heheracer »

Ok, ich habe noch ein hier und da ein paar Verbesserungen einfließen lassen und habe jetzt das hier daraus gemacht:

Code: Alles auswählen

unit Cube;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils;
 
type
  TCubeMap = array of array of array of integer;
 
procedure Cube_MapSizeInit(Map: TCubeMap; NumberOfMaps, LengthX, LengthY: integer);
procedure Cube_MapRanCreate(Map: TCubeMap; MapNumber, Percentage, Value: integer; a, b: real);
procedure Cube_MapSmooth(Map: TCubeMap; MapNumber, n: integer);
procedure Cube_MapOutput(Map: TCubeMap; MapNumber: integer; filename: string);
 
implementation
 
var
  lx, ly: integer;
 
procedure Cube_MapSizeInit(Map: TCubeMap; NumberOfMaps, LengthX, LengthY: integer); //X: 0..LengthX; Y: 0..LengthY; NumberOfMaps = 3  -> 1,2,3;
begin
  lx:=LengthX;
  ly:=LengthY;
  setlength(Map, lx+1, ly+1, NumberOfMaps);
end;
 
procedure Cube_MapRanCreate(Map: TCubeMap; MapNumber, Percentage, Value: integer; a, b: real); //Percentage*a; Value*b
var
  x, y: integer;
begin
  MapNumber:=MapNumber-1;
  randomize;
  for x:=0 to lx do
    for y:=0 to ly do
      if random(trunc(100/a))<Percentage
      then
        map[x,y,MapNumber]:=trunc(b*Value)
      else
        map[x,y,MapNumber]:=0;
end;
 
procedure Cube_MapSmooth(Map: TCubeMap; MapNumber, n: integer);
var
  s, x, y: integer;
  smap: TCubeMap;
begin
  MapNumber:=MapNumber-1;
  setlength(smap, lx+1, ly+1, 1);
  smap[lx,ly,0]:=map[lx,ly,MapNumber];
  smap[lx,0,0]:=map[lx,0,MapNumber];
  smap[0,ly,0]:=map[0,ly,MapNumber];
  smap[0,0,0]:=map[0,0,MapNumber];
  for x:=1 to lx-1 do
    begin
      smap[x,ly,0]:=trunc((map[x-1,ly,MapNumber]+map[x,ly,MapNumber]+map[x+1,ly,MapNumber])/3);
      smap[x,0,0]:=trunc((map[x-1,0,MapNumber]+map[x,0,MapNumber]+map[x+1,0,MapNumber])/3);
    end;
  for y:=1 to ly-1 do
    begin
      smap[0,n,0]:=trunc((map[0,n-1,MapNumber]+map[0,n,MapNumber]+map[0,n+1,MapNumber])/3);
      smap[ly,n,0]:=trunc((map[ly,n-1,MapNumber]+map[ly,n,MapNumber]+map[ly,n+1,MapNumber])/3);
    end;
  for s:=1 to n do
    for x:=1 to lx-1 do
      for y:=1 to ly-1 do
        smap[x,y,0]:=trunc((map[x-1,y+1,MapNumber]+map[x,y+1,MapNumber]+map[x+1,y+1,MapNumber]+map[x-1,y,MapNumber]+map[x,y,MapNumber]*2+map[x+1,y,MapNumber]+map[x-1,y-1,MapNumber]+map[x,y-1,MapNumber]+map[x+1,y-1,MapNumber])/10);
  for x:=0 to lx do
    for y:=0 to ly do
      map[x,y,MapNumber]:=smap[x,y,0];
end;
 
procedure Cube_MapOutput(Map: TCubeMap; MapNumber: integer; filename: string);
var
  x, y: integer;
  tf: textfile;
begin
  MapNumber:=MapNumber-1;
  assignfile(tf, filename);
  rewrite(tf);
  for x:=lx downto 0 do
    begin
      for y:=0 to ly do
        write(tf, map[x,y,MapNumber]:4);
      writeln(tf);
    end;
  closefile(tf);
end;
 
end.
Lazarus kompiliert, gibt aber den Hinweis

Cube.pas(37,30) Hint: Converting the operands to "Int64" before doing the subtract could prevent overflow errors.

Dieser muss relativ wichtig sein, denn bei meinem Testdurchlauf haut er mich bei Zeile 40 raus bei else.

Code meines Testprogramms

Code: Alles auswählen

unit Unit1;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  Cube;
 
type
 
  { TForm1 }
 
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;
 
var
  Form1: TForm1;
  map: TCubeMap;
 
implementation
 
{$R *.lfm}
 
{ TForm1 }
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  Cube_MapSizeInit(map, 2, 10, 10);
  Cube_MapRanCreate(map, 1, 50, 10, 1, 1);
  Cube_MapOutput(map, 1, 'map1s0.txt');
  Cube_MapRanCreate(map, 2, 90, 4, 1, 1);
  Cube_MapOutput(map, 2, 'map2s0.txt');
  Cube_MapSmooth(map, 1, 1);
  Cube_MapOutput(map, 1, 'map1s1.txt');
  Cube_MapSmooth(map, 1, 3);
  Cube_MapOutput(map, 1, 'map1s2.txt');
  Cube_MapSmooth(map, 2, 1);
  Cube_MapOutput(map, 2, 'map2s1.txt');
  Cube_MapSmooth(map, 2, 3);
  Cube_MapOutput(map, 2, 'map2s2.txt');
  showmessage('Finish');
end;
 
end.
PS: Ich hab noch eine Frage, bei Lazaurs heißen die Typen immer TButton, TLabel, TForm, etc., steht T in dem Fall für type?

PPS: Noch eine, wie schaff ich es diese Unit in Lazarus reinzupacken wie z. B. SysUtils, also ohne jedes mal die Unit in den Ordner zu kopieren und dem Projekt hinzuzufügen?

EDIT:

Ich habe nachdem ich einen debg-compile-Modus hinzugefügt habe ich rausbekommen das es ein RunError(201) ist, also Stack Overflow / Range Check Error in Zeile 41 (map:=0). Eigentlich habe ich else unterbunden da ich zum testen die Warscheinlichkeit auf über 100% gesetzt habe.

EDIT2:

Auch in Zeile 39 kommt es zum Range Check Error

Warf
Beiträge: 2122
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Funktionen richtig verwenden?

Beitrag von Warf »

Diese Warning bedeutet letztlich dass du einen Int64 in einen Int32 impliziet castest. Int32 (oder auch integer) hat 32 Bit, kann also zahlen von -2^31 bis (2^31)-1 (c.a -2.1 MRD .. +2.1 MRD) wenn der Int64 außerhalb dieses Wertebereiches liegt kommt es zu Overflow, da heißt die vorderen Bits werden Abgeschnitten. Das sollte möglichst verhindert werden.
PS: Ich hab noch eine Frage, bei Lazaurs heißen die Typen immer TButton, TLabel, TForm, etc., steht T in dem Fall für type?

PPS: Noch eine, wie schaff ich es diese Unit in Lazarus reinzupacken wie z. B. SysUtils, also ohne jedes mal die Unit in den Ordner zu kopieren und dem Projekt hinzuzufügen?
Bei Pascal ist die Namenkonvention für Typen recht Simpel: Ordinaltypen und Klassen fangen mit T an, Pointer mit P, Exceptions mit E.

Der FPC durchsucht nach Units und Methoden Das Projektverzeichnis, die Units im Compiler Pfad und dann alle andere Unit Pfade (-Fu). Lazarus besitzt zudem noch ein Package System (aber in diesem Fall Irrelevant). Du könntest den Pfad zur Unit einfach in der fpc.cfg unter -Fu hinzufügen.

Zu deinem Range Check Problem: Ein Array ist eine Sammlung an Speicherblöcken die einfach hintereinander im Speicher stehen. Über Array[Index] wird dir einfach das Element an der Stelle Index gegeben, dafür wird die Start Position benutzt (@Array[0]) (welche bei Dynamischen Arrays in der Variable gespeichert wird) um die Adresse auf Index auszurechnen dafür gilt IndexElement = ArrayBasisAdresse + Index * SizeOf(ArrayTyp). Nimmst du jetzt einen Index der größer ist als der Array, dann versuchst du aus unbestimmten Speicher zu lesen und zu schreiben.

Im Besten Fall bekommst du nur eine Zugriffsverletzung, und das Programm Crasht, Du kannst aber auch das Problem bekommen und irgendwelche wichtigen Daten überschreiben, wie andere Variablen, oder im Worst Case die Rücksprungsaddresse. Durch die Debuggereinstellungen Meckert der Debugger zwar, aber ohne die kann es Passieren das du sehr schnell ausersehen dinge Überschrieben hast (ohne Fehler zu bekommen) und damit dann dein Komplettes Programm zerschießt. Unter diversen Umständen kann es sogar Passieren dass du Speicher Anderer Prozesse bearbeitest, und somit noch viel Größeren Schaden anrichtest (war bis windows 98 möglich, unter Linux glaube ich geht das auch als sudo).

Daher musst du immer Überprüfungen durchführen mit High(Array), gibt den Höchsten Nutzbaren Index, Low(Array), den niedrigsten möglichen Index und Length(Array) gibt die Anzahl an Elementen (bei Dynamischen ist das High(array)+1)

heheracer
Beiträge: 54
Registriert: Mo 17. Nov 2014, 16:45

Re: Funktionen richtig verwenden?

Beitrag von heheracer »

Warf hat geschrieben:Diese Warning bedeutet letztlich dass du einen Int64 in einen Int32 impliziet castest. Int32 (oder auch integer) hat 32 Bit, kann also zahlen von -2^31 bis (2^31)-1 (c.a -2.1 MRD .. +2.1 MRD) wenn der Int64 außerhalb dieses Wertebereiches liegt kommt es zu Overflow, da heißt die vorderen Bits werden Abgeschnitten. Das sollte möglichst verhindert werden.

Über Array[Index] wird dir einfach das Element an der Stelle Index gegeben, dafür wird die Start Position benutzt (@Array[0]) (welche bei Dynamischen Arrays in der Variable gespeichert wird) um die Adresse auf Index auszurechnen dafür gilt IndexElement = ArrayBasisAdresse + Index * SizeOf(ArrayTyp). Nimmst du jetzt einen Index der größer ist als der Array, dann versuchst du aus unbestimmten Speicher zu lesen und zu schreiben.

Daher musst du immer Überprüfungen durchführen mit High(Array), gibt den Höchsten Nutzbaren Index, Low(Array), den niedrigsten möglichen Index und Length(Array) gibt die Anzahl an Elementen (bei Dynamischen ist das High(array)+1)
Wie Array funktioniert dachte ich eigentlich zu wissen. Heißt das also (sihe Fett gedrucktes) das es nur zu einem Fehler kommt weil er den falschen Int-Typ verwendet? Eigentlich verlasse ich den Bereich des Arrays auch nicht. Gibt es da eine Umwandlungsfunktion?

MfG

Komoluna
Beiträge: 565
Registriert: So 26. Aug 2012, 09:03
OS, Lazarus, FPC: Windows(10), Linux(Arch)
CPU-Target: 64Bit

Re: Funktionen richtig verwenden?

Beitrag von Komoluna »

Was meinst du mit Umwandlung?

MFG

Komoluna
Programmer: A device to convert coffee into software.

Rekursion: siehe Rekursion.

heheracer
Beiträge: 54
Registriert: Mo 17. Nov 2014, 16:45

Re: Funktionen richtig verwenden?

Beitrag von heheracer »

Komoluna hat geschrieben:Was meinst du mit Umwandlung?

MFG

Komoluna
Wenn ich es richtig interpretiere stürzt das Programm ab weil er die Zahl irgendwie abschneidet (siehe Warf) und er deswegen einen falschen Wertebereich aufruft und abstürzt, den 0 oder 1 ist auf jeden Fall ein Teil des Arrays.

Kann auch sein das ich das falsch interpretiere und das Programm abstürzt weil der Array nicht richtig initialisiert wurde. Aber eigentlich habe ich das ja mit setlength.

MfG

EDIT:

Ok, hab grade einen kleinen Test gemacht. Das höchste Element von Map ist -1... wieso? Es müsste doch lx, also im Testprogramm 10, sein. Hab ich da irgendwas falsch gemacht?

Code: Alles auswählen

setlength(Map, lx+1, ly+1, NumberOfMaps);

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: Funktionen richtig verwenden?

Beitrag von Michl »

Ich glaube, einfacher wäre es, dein Projekt oder besser ein Minimalbeispiel (ohne Exe) als Zip hier hoch zu laden. Dann könnte jemand, der Lust hat, dieses starten und debuggen und dir den richtigen Hinweis geben (eine Durchsicht des recht umfangreichen geposteten Codes per Browser machen hier wahrscheinlich nicht viele).

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

Warf
Beiträge: 2122
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Funktionen richtig verwenden?

Beitrag von Warf »

Die Auflösung ist recht simpel:

Code: Alles auswählen

procedure Cube_MapSizeInit(var Map: TCubeMap; const NumberOfMaps, LengthX, LengthY: integer);
procedure Cube_MapRanCreate(var Map: TCubeMap; const MapNumber, Percentage, Value: integer;  
statt

Code: Alles auswählen

procedure Cube_MapSizeInit(Map: TCubeMap; NumberOfMaps, LengthX, LengthY: integer);
procedure Cube_MapRanCreate(Map: TCubeMap; MapNumber, Percentage, Value: integer;  
Ich zitiere mich mal kurz selbst:
Außerdem versuchst du variablen zu verändern über Call By Value, verwende stattdessen Call by Reference mit dem Keyword Var oder Out
Wenn du eine Variable über einen Parameter übergeben willst welche bearbeitet werden soll musst du Call By Reference verwenden mit:
procedure Name(var CallByReferenceParameter: Type);
Oder du musst einen Pointer verwenden, aber Call by Reference ist einfacher

Bei Call By Value (über Const Schlüsselwort oder auch by default) kannst du vielleicht einen Array erstellen, der wird allerdings nie in map gesichert, und letztlich Hast du immer noch einen 0,0,0 grosen Array. Und dann versuchst du auf ein Element zuzugreifen, obwohl du keine im Array hast. Daher deine Zugriffsverletzung

heheracer
Beiträge: 54
Registriert: Mo 17. Nov 2014, 16:45

Re: Funktionen richtig verwenden?

Beitrag von heheracer »

Warf hat geschrieben:Die Auflösung ist recht simpel:

Code: Alles auswählen

procedure Cube_MapSizeInit(var Map: TCubeMap; const NumberOfMaps, LengthX, LengthY: integer);
procedure Cube_MapRanCreate(var Map: TCubeMap; const MapNumber, Percentage, Value: integer;  
statt

Code: Alles auswählen

procedure Cube_MapSizeInit(Map: TCubeMap; NumberOfMaps, LengthX, LengthY: integer);
procedure Cube_MapRanCreate(Map: TCubeMap; MapNumber, Percentage, Value: integer;  
Ich zitiere mich mal kurz selbst:
Außerdem versuchst du variablen zu verändern über Call By Value, verwende stattdessen Call by Reference mit dem Keyword Var oder Out
Wenn du eine Variable über einen Parameter übergeben willst welche bearbeitet werden soll musst du Call By Reference verwenden mit:
procedure Name(var CallByReferenceParameter: Type);
Oder du musst einen Pointer verwenden, aber Call by Reference ist einfacher

Bei Call By Value (über Const Schlüsselwort oder auch by default) kannst du vielleicht einen Array erstellen, der wird allerdings nie in map gesichert, und letztlich Hast du immer noch einen 0,0,0 grosen Array. Und dann versuchst du auf ein Element zuzugreifen, obwohl du keine im Array hast. Daher deine Zugriffsverletzung
Ah ok danke mir geht ein Licht auf :idea:

Standardmäßig wird nur der Wert geladen sozusagen "in eine neue Variable", aber nicht gespeichert.
Wenn man var eingibt dann wird die Variable geladen und Änderungen gespeichert.
Wieder was dazu gelernt.

Hab es jetzt übrigens hinbekommen

MfG

Antworten