Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - mindestgröße eines Integer-Parameters


IhopeonlyReader - Sa 23.02.13 22:06
Titel: mindestgröße eines Integer-Parameters
Guten Tag,
ich denke die Frage ist für erfahrene Programmierer schnell zu beantworten...

folgendes Beipsiel

Delphi-Quelltext
1:
2:
3:
4:
Procedure Beispielfunktion(Liste: Array of TBeispiel; EineVariable: Integer);
begin
//...
end;

Die eigentliche Frage ist: wie kann ich die Procedure so "vorbereiten", dass "EineVariable" > 0 sein muss ?...
sodass, wenn ich

Delphi-Quelltext
1:
Beispielfunktion(EineListehalt, -5);                    

eingebe, eine Fehlermeldung kommt (nicht zur Laufzeit, sondern beim compilierversuch)

2te Frage: Wie kann ich ein beliebig großes Array von einem vorbestimmten Typ als parameter verlangen? (siehe "Liste")
Also, wenn TBeispiel = Integer wäre, dass ich dann die procedure sowohl mit

Delphi-Quelltext
1:
2:
3:
4:
var EineListehalt: Array[1..100of Integer; 
begin
Beispielfunktion(EineListehalt, 10);
end;

als auch mit

Delphi-Quelltext
1:
2:
3:
4:
var EineListehalt: Array[1..15of Integer; 
begin
Beispielfunktion(EineListehalt, 10);
end;

aufrufen kann/könnte..

bei

Delphi-Quelltext
1:
2:
3:
4:
var EineListehalt: Array[1..100of String
begin
Beispielfunktion(EineListehalt, 10);
end;

natürlich ein Felher (beim compilieren) kommt...

Ich hoffe es ist verständlich, was ich frage :D


WasWeißDennIch - Sa 23.02.13 22:12

Zu 1: ganz so geht es leider nicht, aber nimm doch statt Integer Cardinal, dann kann man zumindest keine Zahlen < 0 übergeben.
Zu 2: das nennt sich Open Array (sofern ich die Frage richtig verstanden habe).

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
procedure SomeProc(IntArr: array of integer);

...
(* Möglicher Aufruf: *)
SomeProc([1234]);

(* Oder auch *)
var
  Dings: array[1..10of integer;
begin
  SomeProc(Dings);


IhopeonlyReader - Sa 23.02.13 22:19

ich kenn das als "dynamisches Array".. oder bring ich da was durcheinander?
könnte ich also die "maxanzahl" des arrays mit length bestimmen etc?


WasWeißDennIch - Sa 23.02.13 22:32

Ein dynamisches Array ist etwas anderes als ein Open Array. Lesestoff dazu [http://delphibasics.co.uk/Article.asp?Name=Arrays] (Englisch).

[edit] Nachtrag/Korrektur: Du kannst Dir einen eigenen Zahlentyp definieren, dann kommst Du Deinem Ziel aus Frage 1 zumindest nahe:

Delphi-Quelltext
1:
2:
type
  TMyZahl = 1..MAXINT;

Allerdings bekommt der Compiler falsche Werte nur dann mit, wenn Du Konstanten übergibst wie in Deinem Beispiel.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
procedure Bla(Zahl: TMyZahl);

Bla(0); //Compilerfehler

Blubb := 0;
Bla(Blubb); //kein Compilerfehler
[/edit]


IhopeonlyReader - Sa 23.02.13 22:41

user profile iconWasWeißDennIch hat folgendes geschrieben Zum zitierten Posting springen:

type
TMyZahl = 1..MAXINT;


genau das ist mir auch eingefallen :D

und ja ich verwende dazu immer konstanten, oder die variable ist vom Typ TMyZahl^^

Und:
könntest du mir die "grundlagen" zu dem openarray liefern?

z.B.
Maximale Größe / Range ( bei var Str: Array[3..16] of integer; wäre die maximale größe 16, die range 13


Tranx - Sa 23.02.13 22:55

das mit den Offenen Arrays ist ganz einfach:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
  procedure Tuewas(a : Array of double);
  var
    Summe : double; 
    i : integer;
  begin
    Summe := 0.0;
    for i := 0 to High(a) do
    begin
      Summe := Summe + a[i];
    end;
  end;


Das mit der EinenVariablen ist - wie schon erwähnt - vom Compiler nur dann zu erkennen, wenn der übergebene Wert eine Konstante ist. Allerdings funktioniert es auch, wenn Du die Variable als var-Paramter übergibst. Denn dann muss der Typ übereinstimmen.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
procedure Tuewas(var w : Word);
begin
  w := w + 123;
end;

procedure TForm1.btn1Click(Sender: TObject);
var
  i : Integer;
  j : Word;
begin
  i := 15;
  Tuewas(i);  // hier Compilerfehler!!
  j := 15;
  Tuewas(j);
end;


Allerdings wird dann die Variable EineVariable, die Du übergibst, auch geändert. Das heißt, die übergebene Variable hat dann nach Verlassen der Prozedur u.U. einen anderen Wert. Und um die Eingrenzung auf Werte>0 zu gewährleisten musst Du mindestens Word oder andere Vorzeichenlose Integer-Typen nehmen. Sonst funktioniert das nicht. Und dann darf der Typ der übergebenden Variablen kein anderer sein.

Vielleicht solltest Du besser eine Fehlerbehandlungsroutine in der Prozedur einbinden.


WasWeißDennIch - Sa 23.02.13 23:12

Etwas ausführlicher: bei einem Open Array kann man den zu übergebenden Parameter "On the fly" schreiben, bei einem dynamischen nicht.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
type
  TIntArr = array of integer; //dynamischer Arraytyp

function SumInt(Arr: TIntArr): integer;
var
  i: integer;
begin
  Result := 0;
  for i := Low(Arr) to High(Arr) do
    inc(Result, Arr[i]);
end;

procedure TForm1.btnBlubb(Sender: TObject);
begin
  ShowMessage(IntToStr(SumInt([1234]))); //Compilerfehler
end;

Definiert man den Parameter aber als offenes Array, dann klappt das auch.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
function SumInt(Arr: array of integer): integer;
var
  i: integer;
begin
  Result := 0;
  for i := Low(Arr) to High(Arr) do
    inc(Result, Arr[i]);
end;

procedure TForm1.btnBlubb(Sender: TObject);
begin
  ShowMessage(IntToStr(SumInt([1234]))); //kein Compilerfehler
end;


Weitere Beispiele finden sich auch auf der oben verlinkten Seite, wenn man dem dort enthaltenen Link auf "Array" folgt: http://delphibasics.co.uk/RTL.asp?Name=Array [http://delphibasics.co.uk/RTL.asp?Name=Array]


IhopeonlyReader - Sa 23.02.13 23:48

vielen Dank :)
also bei

Delphi-Quelltext
1:
2:
3:
4:
5:
var
Testvariable: Array[11..111of Integer;
begin
SumInt(Testvariable);
end;



Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
function SumInt(Arr: array of integer): integer;
var
DynArr: Array of Integer;
C: Integer;
begin
//Maximale Größe des Arrays = High(Arr); (111)
//Startwert des Arrays = Low(Arr); (11)
//Range des Arrays = High(Arr)-Low(Arr); (100)
SetLength(DynArr, High(Arr)-Low(Arr));

Result := 0;
For C:=0 to High(DynArr) do
Result := Result + DynArr[C];  //= inc(Result, DynArr[C]);
end;



richtig? und sind High und low auch verwendbar, wenn man in einer procedure die eigentliche Variable (statisches Array) hat?
also

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
var
Testvariable: Array[11..111of Integer;
begin
// High = High(Testvariable) ...
oder muss man das ganze abstrakt sehen?
// High= High(^Testvariable) ... ?
end;


WasWeißDennIch - So 24.02.13 00:02

Ich verstehe nicht ganz, worauf Du hinauswillst. Low(Array) gibt Dir den Index des ersten Array-Elements zurück, High(Array) den des letzten, Length(Array) die Länge, unabhängig von Low() und High().

Delphi-Quelltext
1:
2:
3:
var
  Testvariable: Array[11..111of Integer;
(* Low = 11, High = 111, Length = 101 *)


IhopeonlyReader - So 24.02.13 00:17

Length(Array) = High(Array) - Low(Array) +1; !
ich frage mich wozu es length(array) gibt, wenn es immer konstant im bezug auf high und low ist.

Worauf ich auf folgendes hinaus:
Dyn Array = OpenArray + SetLength-Function;
also kann ich mehere verschiedenlage arrays zu einem langen hinzufügen


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
type
TGesamtArray = Array of Integer;

Procedure MoreToOne(EinArray: Array of Integer, GesamtArray: TGesamtArray);
var C: Integer;
begin
setlength(GesamtArray, length(GesamtArray) + length(EinArray));
For C := 1 to length(EinArray) do
 GesamtArray[C + length(GesamtArray) - length(EinArray)] := EinArray[Low(EinArray)+C];
end;


WasWeißDennIch - So 24.02.13 00:25

Prinzipiell sollte das möglich sein, ich persönlich würde es nur etwas anders schreiben:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure AddToArray(Source: array of integer; var Dest: TGesamtArray);
var
  i, OldHigh: integer;
begin
  OldHigh := High(Dest);
  SetLength(Dest, Length(Dest) + Length(Source));
  for i := Low(Source) to High(Source) do
    Dest[i + Succ(OldHigh)] := Source[i];
end;

Ungetestet.


IhopeonlyReader - So 24.02.13 00:38

user profile iconWasWeißDennIch hat folgendes geschrieben Zum zitierten Posting springen:


Delphi-Quelltext
1:
Dest[i + Succ(OldHigh)] := Source[i];                    


mhh..
1. kenn ich succ nicht :D aber so wie http://www.delphibasics.co.uk/RTL.asp?Name=Succ das erklärt, macht succ nichts anders als den wert um 1 zu erhöhen
(wie OldHigh := OldHigh +1)
2. falls dein Array nicht bei 1 beginnt, klappt das mit Dest[i + Succ(OldHigh)] nicht !
Denn dann wäre der Index über dem Max.

logischer wäre:
Dest[i - low(Source) + 1 + OldHigh)];
oder wie du das machen würdest;
Dest[i - low(Source) + Succ(OldHigh)];

Wobei ich bei der 2 Vairante unsicher bin, ob oldhigh PRO durchführung um 1 größer wird oder nur für die prozedure...

Wenn es pro durchführung ist, also

Delphi-Quelltext
1:
2:
3:
4:
Procedure Succ(Wert: Integer);
begin
Wert := Wert +1;
end;

dann funktioniert die 2 variante nicht... ist es jedoch nur für den zweck um 1 vergrößert, also

Delphi-Quelltext
1:
2:
3:
4:
Function Succ(Wert: Integer): Integer;
begin
Result := Wert +1;
end;

würde es funktionieren.. aber ich glaube es ist so wie die prozedure aufgebaut


WasWeißDennIch - So 24.02.13 00:44

Open Arrays und dynamische Arrays beginnen immer mit Index 0, das passt schon. Und Succ() ist eine Funktion, die den übergebenen Wert nicht verändert (sonst könnte man ja auch keine Konstanten übergeben), im Gegensatz zu z.B. Inc().


IhopeonlyReader - So 24.02.13 00:51

also ist

Zitat:


Delphi-Quelltext
1:
for i := Low(Source) to High(Source) do                    


ist also nichts anders als

Delphi-Quelltext
1:
for i := 0 to length(Source) do                    

richtig?

P.S: vielen Dank für deine Mühe mir alles genau zu erklären :)


IhopeonlyReader - So 24.02.13 00:59

user profile iconWasWeißDennIch hat folgendes geschrieben Zum zitierten Posting springen:

Bla(0); //Compilerfehler

Blubb := 0;
Bla(Blubb); //kein Compilerfehler[/delphi][/edit]


fast :D
das untere ergibt auch ein CompilerFehler, denn Blubb muss ja integer, extended oder so sein und das ist ungleich mit TMyZahl...
also müsste Blubb vom Typ TMyZahl sein und der Fehler läg dann schon bei
Blubb := 0;

nur so ^^


WasWeißDennIch - So 24.02.13 01:08

user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
also ist

Zitat:


Delphi-Quelltext
1:
for i := Low(Source) to High(Source) do                    


ist also nichts anders als

Delphi-Quelltext
1:
for i := 0 to length(Source) do                    

richtig?

Nicht ganz. Von 0 bis Length(Source) - 1 ;) Dass ich grundsätzlich von Low() bis High() über Arrays iteriere hat einen ganz einfachen Grund: es passt immer! Ich weiß zwar, dass dynamische Arrays immer mit Index 0 beginnen und mit Index Length - 1 enden, aber daran muss ich bei dieser Vorgehensweise keinen Gedanken verschwenden. Zum eigenen Datentyp: versuch doch mal das hier

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
type
  TZahl = 1..MAXINT;

procedure DoWork(Zahl: TZahl);
begin
  ShowMessage(IntToStr(Zahl));
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Blubb: integer;
begin
  Blubb := -42;
  DoWork(Blubb);
end;

Ergibt zumindest in Delphi 7 weder zur Entwurfs- noch zur Laufzeit einen Fehler.


IhopeonlyReader - So 24.02.13 01:15

user profile iconWasWeißDennIch hat folgendes geschrieben Zum zitierten Posting springen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
type
  TZahl = 1..MAXINT;

procedure DoWork(Zahl: TZahl);
begin
  ShowMessage(IntToStr(Zahl));
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Blubb: integer;
begin
  Blubb := -42;
  DoWork(Blubb);
end;

Ergibt zumindest in Delphi 7 weder zur Entwurfs- noch zur Laufzeit einen Fehler.


stimmt.. um solche "Fehler" zu beheben schreiben wird die procedure ein ganz klein wenig anders :D

Delphi-Quelltext
1:
procedure DoWork(var Zahl: TZahl);                    


WasWeißDennIch - So 24.02.13 01:27


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
procedure DoWork(var Zahl: TZahl);
begin
  ShowMessage(IntToStr(Zahl));
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Blubb: integer;
begin
  Blubb := -42;
  DoWork(TZahl(Blubb));
end;

Ällabätsch :P . Wie man so etwas allerdings verhindern soll, weiß ich selbst nicht. Mit dem harten Typecast sagt man ja dem Compiler so "Sledge Hammer"-mäßig
Zitat:
Vertrauen Sie mir, ich weiß, was ich tue.

Knallt es dann, kann man nur sagen: selber Schuld! Aber dieses Problem lässt sich auf jeden beliebigen Datentyp übertragen.


Tranx - Do 28.02.13 05:53

user profile iconWasWeißDennIch hat folgendes geschrieben Zum zitierten Posting springen:
Prinzipiell sollte das möglich sein, ich persönlich würde es nur etwas anders schreiben:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure AddToArray(Source: array of integer; var Dest: TGesamtArray);
var
  i, OldHigh: integer;
begin
  OldHigh := High(Dest);
  SetLength(Dest, Length(Dest) + Length(Source));
  for i := Low(Source) to High(Source) do
    Dest[i + Succ(OldHigh)] := Source[i];
end;

Ungetestet.



Da ja Source = Array of integer für Low(Source) immer 0 ausgibt, sollte es funktionieren, aber warum nicht folgende Variante:
(*1)

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
var
  i, AktPos, OldHigh: integer;
begin
  OldHigh := High(Dest);
  SetLength(Dest, Length(Dest) + Length(Source));
  AktPos:= OldHigh+1;
  for i := Low(Source) to High(Source) do
  begin
    Dest[AktPos] := Source[i];
    Inc(AktPos);
  end;
end;

(*2)

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
var
  i, AktPos: integer;
begin
  AktPos := High(Dest)+1;
  SetLength(Dest, Length(Dest) + Length(Source));
  for i := Low(Source) to High(Source) do
  begin
    Dest[AktPos] := Source[i];
    Inc(AktPos);
  end;
end;



Bemerkung zur Editierung: Variablen im Namen geändert!!!


WasWeißDennIch - Do 28.02.13 09:28

Einverstanden, aber dann sollte man vielleicht noch etwas sprechendere Bezeichner wählen.


Tranx - Do 28.02.13 12:05

Kein Thema, s. Änderung