Entwickler-Ecke

Sonstiges (Delphi) - Rekursive Funktion möglich?


anubis2k5 - Mo 25.08.14 18:12
Titel: Rekursive Funktion möglich?
Hallo Leute,

ich arbeite gerade an einem kleinen Programm, welches mir u.a. die Anzahl der Unterverzeichnisse eines bestimmten Verzeichnis zählen soll. So weit, so gut. Die Procedure funktioniert auch, nur möchte ich diese gerne als Funktion nutzen, sprich einmal aufrufen und dann einen Wert zurück bekommen. Momentan löse ich das ganze mit einer globalen Variable, welcher vorher genullt und Procedure-Intern inkrementiert wird. Das ganze versuche ich als Funktion zu verpacken, jedoch fehlt mir da noch eine Idee bzw. die Bestätigung, dass sowas überhaupt geht.

Hier die simple Procedure:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
procedure RecursiveFolderScan(Path: String);
var
  sr: TSearchRec;
  FileAttrs: Integer;

begin
  FileAttrs := faDirectory + faHidden;

  if FindFirst(Path + '\*.*', FileAttrs, sr) = 0 then
    repeat
      if ((sr.Attr AND FileAttrs) = sr.Attr) AND (sr.Name <> '.'AND (sr.Name <> '..'then
      begin
        inc(FolderCounter);
        RecursiveFolderScan(Path + '\' + sr.Name);
      end;
    until FindNext(sr) <> 0;
  FindClose(sr);
end;


Nur mal kurz zur Logik - eine Funktion würde sich - je nach Verzeichnistiefe - immer wieder selbst aufrufen, daher bringt es nichts dort eine "Result-Variable" zu definieren. Wäre es mit einer "Funktion in einer Funktion" zu realisieren? Dabei müsste ja eine Variable innerhalb der Funktion existieren und erhalten bleiben... :? Ich komm nich drauf...


jfheins - Mo 25.08.14 18:33

Wiese sollte ein Result nichts bringen?

Prinzipiell wird es auf folgende Struktur hinauslaufen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
function RecursiveFolderScan(Path: String): Integer;
begin
Result = 0;
//...
      if ((sr.Attr AND FileAttrs) = sr.Attr) AND (sr.Name <> '.'AND (sr.Name <> '..'then
      begin
        inc(Result);
        Result = Result + RecursiveFolderScan(Path + '\' + sr.Name);
      end;
//...
end

Die Result-Variable existiert natürlich für jeden einzelnen Unteraufruf der Funktion, somit muss das Ergebnis dann auch immer fleißig addiert werden.


bole - Mo 25.08.14 21:48

Ich würde in diesem Fall die Procedure als Teil der Funktion machen. Aufgerufen wird die function mit dem Rückgabewert der Anzahl Folders. Die einzige Aufgabe dieser Funktion ist die Procedure aufzurufen und den Wert zurück zu geben. So ist auch keine globale Variable mehr notwendig


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
function TForm1.FRecursiveFolderScan(Path: String): Integer;
var
   folderCounter  :integer;

  procedure RecursiveFolderScan(Path: String);
  var
    sr: TSearchRec;
    FileAttrs: Integer;

  begin
    FileAttrs := faDirectory + faHidden;

    if FindFirst(Path + '\*.*', FileAttrs, sr) = 0 then
      repeat
        if ((sr.Attr AND FileAttrs) = sr.Attr) AND (sr.Name <> '.'AND (sr.Name <> '..'then
        begin
          inc(FolderCounter);
          RecursiveFolderScan(Path + '\' + sr.Name);
        end;
      until FindNext(sr) <> 0;
    FindClose(sr);
  end;

begin
  foldercounter:=0;
  RecursiveFolderScan(Path);
  result:=folderCounter
end;


Gruss

Bole


Blup - Mi 27.08.14 09:39

FindClose sollte man nur aufrufen, wenn FindFirst erfolgreich war.
Der SearchRec ist sonst unter Umständen nicht initialisiert.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
  if FindFirst({..}then
  begin
    try
      {...}
    finally
      FindClose({...});
    end;
  end;


anubis2k5 - Mi 27.08.14 11:37

Ich danke euch für die Denkanstöße. Einmal drüber nachgedacht macht das auch alles Sinn - das bleibt haften :)


Delphi-Laie - Mi 27.08.14 18:48

user profile iconanubis2k5 hat folgendes geschrieben Zum zitierten Posting springen:
ich arbeite gerade an einem kleinen Programm, welches mir u.a. die Anzahl der Unterverzeichnisse eines bestimmten Verzeichnis zählen soll. So weit, so gut. Die Procedure funktioniert auch, nur möchte ich diese gerne als Funktion nutzen, sprich einmal aufrufen und dann einen Wert zurück bekommen. Momentan löse ich das ganze mit einer globalen Variable, welcher vorher genullt und Procedure-Intern inkrementiert wird.


Wenn Du die Anzahl der Unterverzeichnisse aller (untergeordneter) Hierarchieebenen ermitteln möchtest, so sehe auch ich das nur mit einer globalen Variable lösbar, zumal ich auch nur die rekursive Lösungsmethode für diese Problemstellung kenne. Gut, es gibt theoretische Informatiker, die bewiesen haben, daß sich alles über Funktionen und mithin wohl auch nur lokale, funktionsinterne Variablen lösen läßt. Wüßte ich gern, ob das auch in einem solchen Falle zutrifft bzw. wie es sich hier umsetzen läßt.

user profile iconanubis2k5 hat folgendes geschrieben Zum zitierten Posting springen:
Wäre es mit einer "Funktion in einer Funktion" zu realisieren?


Das bedeutet, den Teufel mit dem Beelzebub auszutreiben. Rekursion besteht doch schon darin und ist so realisierbar, daß eine Funktion sich selbst aufruft. Funktionen mit ähnlichem bzw. gleichen Quellcode (mit Ausnahme der eingebetteten Funktion) im Quelltext hierarchisch zu verknüpfen bedeutet, die Rekursion in den Quellcode zu verpacken, das ist ja schon "Metarekursion". Das mag funktionieren, ist m.E. aber zuviel des Guten bzw. Nötigen, es ist schlichtweg redundant.