moin,
irgendwie bin ich immer und immerwieder vor dem Problem, dass ich gerne
eine Funktion in C hätte, mit der ich mehrere Rückgabeparameter auf
einmal zurückgeben kann.
Beispiel:
Ein Array nach dem kleinsten Wert durchsuchen und dessen Position im
Array ebenfalls mit rausgeben.
Eine Bastellösung wäre, die beiden Werte jeweils als ein High- und
Low-Byte zu betrachten und das zusammengesetzte Wort zu returnen...
Aber wie gesagt, dass wäre eine Bastellösung, die mir gerade so in den
Sinn kommt und die irgendwie suboptimal ist, weil man immer noch eine
zusätzliche Funktion brauch, um das wieder auseinander zu frickeln...
Wie löst ihr am elegantesten eine solche Aufgabenstellung?
mfg
Wie von den Vorpostern schon extrem kurz umschrieben:
Das Stichwort heißt "call by reference".
Mehrere Parameter lassen sich nicht über den eigentlichen Rückgabewert
der Funktion zurückgeben.
Stattdessen übergibst Du der Funktion beim Aufruf für die
Rückgabeparameter einen oder mehrere Pointer auf beschreibbare
Variablen, in denen die eigentliche Werte-Rückgabe erfolgt.
Du übergibst also im Funktionsaufruf für die Rückgabeparameter der
Funktion einen Pointer auf die zu beschreibende Variable.
Diese kann z.B. auch ein Array oder Struct sein, womit man mit nur einem
Pointer mehrere Parameter zurückgeben kann.
Innerhalb der Funktion dereferenzierst Du den übergebenen Pointer, um
die verschiedenen Rückgabewerte zu speichern. Die Funktion schreibt also
ihre Rückgabewerte direkt in das durch den Pointer adressierte Array
oder Struct.
Über dieselbe Struktur kann man der Funktion natürlich auch Parameter
übergeben, Array oder Struct müssen beim Funktionsaufruf ja nicht
undefiniert sein. ;-)
So ist z.B. eine Funktion machbar, die eine 3 x 3 Matrix als Array (per
Pointer darauf!) übergeben bekommt und diese Matrix, falls möglich,
invertiert. Die Inverse Matrix wird dann wieder in dem Übergabe-Array
abgelegt und der normale Rückgabewert der Funktion wird als Fehlercode
genutzt, um zu signalisieren, daß die Matrix nicht invertierbar ist.
Gruß,
Thorsten
Da merkt man, dass die Jungs die C erfunden haben, eher einen
mathematischen Hintergrund hatten als dass sie Assembler-Hacker waren.
Letztere haetten ganz selbstverstaendlich Funktionen mit mehreren
Resultaten vorgesehen.
Marwin schrieb:> Da merkt man, dass die Jungs die C erfunden haben, eher einen> mathematischen Hintergrund hatten als dass sie Assembler-Hacker waren.> Letztere haetten ganz selbstverstaendlich Funktionen mit mehreren> Resultaten vorgesehen.
Merkwürdig nur dass praktisch in allen Programmiersprachen Funktionen
nur einen Rückgabewert haben.
Das hat doch mit den "Jungs" von C nichts zu tun. Die Anlehnung an die
mathematische Funktion ist durchaus sinnvoll.
gruß cyblord
Marwin schrieb:> Da merkt man, dass die Jungs die C erfunden haben, eher einen> mathematischen Hintergrund hatten als dass sie Assembler-Hacker waren.> Letztere haetten ganz selbstverstaendlich Funktionen mit mehreren> Resultaten vorgesehen.
In Assembler kann ich nicht mal 1 Wert zurückgeben, sondern muss von
vorn herein sagen: ich erwarte den Wert an dieser Adresse (und sei es
auch der Stack).
Alternativ kann man die Funktion einen Pointer auf ein Array zurückgeben
lassen das 2 Einträge hat die dann Minimum und Position ausgeben.
Was die anderen nicht "beachtet" haben ist, dass deine Funktion noch
irgendwoher wissen muss wie lang dein Array ist, brauchst also einen
Zusätzlichen eingabeparameter.
Florian
Marwin schrieb:> Da merkt man, dass die Jungs die C erfunden haben, eher einen> mathematischen Hintergrund hatten als dass sie Assembler-Hacker waren.
Andersherum wird ein Schuh daraus:
Gerade diejenigen Sprachen, die etwas mathematisch angehaucht sind
(prominentestes Beispiel: Haskell), erlauben die Rückgabe von Tupeln.
Die Zerlegung des Tupels in einzelne Komponenten kann dank Pattern-
Matching im gleichen Aufwasch erfolgen. Beispiel:
1
sumprod x y = (x+y, x*y) -- Funktion mit zwei Ergebnissen
In vielen anderen Sprachen (Python, Ruby, Lua, Groovy ...) geht das ganz
ähnlich.
Bei den C-Entwicklern hingegen stand nicht die reine Mathematik sondern
der reale Prozessor im Vordergrund. Eines der ursprünglichen Konzepte
bestand darin, Funktionswerte in einem (immer gleichen) Prozessorregis-
ter oder allenfalls einem Registerpaar (bei double) zurückzugeben. Die
Rückgabe mehrerer Werte (sei es als getrennte Werte oder zusammengefasst
in eine Struktur oder ein Array) war deswegen nicht vorgesehen. Struktu-
ren als Funktionswerte kamen erst später (mit ANSI-C), Arrays sind immer
noch nicht möglich.
Das Beispiel von oben ist in heutigem C zwar in ähnlicher Form möglich,
sieht aber recht holprig aus:
1
// Hilfsstruktur
2
3
structSumProd{
4
intsum,prd;
5
};
6
7
// Funktion mit zwei Ergebnissen
8
9
structSumProdsumprod(intx,inty){
10
structSumProdsp;
11
sp.sum=x+y;
12
sp.prd=x*y;
13
returnsp;
14
}
15
16
// Anwendung ergibt s=7 und p=12
17
18
structSumProdsp;
19
ints,p;
20
21
sp=sumprod(3,4);
22
s=sp.sum;
23
p=sp.prd;
Deswegen bedient man sich auch heute noch meist der klassischen Methode
mit den Zeigerargumenten:
>Ein Array nach dem kleinsten Wert durchsuchen und dessen Position im>Array ebenfalls mit rausgeben.
Der "richtige" Returnwert ist dann die Position und sonst nix. Auf die
Rückgabe des Wertes kann man verzichten, denn um den zu wissen muss man
ja nur "a[i]" schreiben (wenn i die Position ist und a das Array).
Vuvuzelatus schrieb:>>Ein Array nach dem kleinsten Wert durchsuchen und dessen Position im>>Array ebenfalls mit rausgeben.>> Der "richtige" Returnwert ist dann die Position und sonst nix. Auf die> Rückgabe des Wertes kann man verzichten, denn um den zu wissen muss man> ja nur "a[i]" schreiben (wenn i die Position ist und a das Array).
Das war auch mein erster Gedanke...
Lothar Miller schrieb:> In Assembler kann ich nicht mal 1 Wert zurückgeben, sondern muss...
Das ist Quatsch.
Man kann in Assembler so ziemlich alles zurückgeben. Das Ganze ist
lediglich eine Frage der vereinbarten Implementierung.
So kann man bei Arm nachlesen, daß Funktionen dort im Prinzip sehr wohl
mehrere Variablen zurückgeben können, weil es bei den dafür vorgesehenen
Registern möglich ist. In Assembler wäre das nutzbar.
ABER: Es macht niemand davon Gebrauch, weil sowas in den einschlägigen
Programmiersprachen nicht vorgesehen ist.
nochwas:
Gert schrieb:> Ja, Pointer ist die Lösung.
Jaja, eine zwar benutzbare, aber schlechte Lösung. Anstatt mit Pointern
um sich zu werfen, sollte man lieber über seine Lösungswege nachdenken
und sich einen besseren Code ausdenken, der weitgehend ohne sowas
auskommt. Pointer als Resultate sind grottenschlecht, denn worauf sollen
sie zeigen? Auf Variablen auf dem Stack etwa?
W.S.
Naja Pointer zurückgeben meinte er wohl nicht, sondern vielmehr einen
Pointer auf ein Array oder Struct übergeben und dort direkt
reinschreiben. Also call by reference.
Das ist natürlich performanter als ein Struct zurückzugeben, da man sich
so die ganze Rumkopiererei spart.
Hängt halt immer davon ab wie knapp die Ressourcen sind wie man das
implementiert. Ich verwende beides, aber wenn ich mehrere Werte
zurückgeben will, arbeite ich meist mit Pointer auf struct und schreibe
direkt rein, anstatt ein Struct zurückzugeben.
Wenn ich z.B. überlege wenn ich meine "Einstellungen" die im EEPROM
liegen auslese und vielleicht 30 Werte umfassen, dann würde ich nicht im
Traum darauf kommen das ganze per return by value zu realisieren,
zumindest nicht auf einem µC
W.S. schrieb:> Gert schrieb:>> Ja, Pointer ist die Lösung.>> Jaja, eine zwar benutzbare, aber schlechte Lösung. Anstatt mit Pointern> um sich zu werfen, sollte man lieber über seine Lösungswege nachdenken> und sich einen besseren Code ausdenken, der weitgehend ohne sowas> auskommt.
Schwachsinn.
> Pointer als Resultate sind grottenschlecht, denn worauf sollen> sie zeigen? Auf Variablen auf dem Stack etwa?
Warum denn nicht?
Schau mal als Beispiel in die Windows API, die ist voll mit sowas.
Mal zufallsmäßig was rausgepickt:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363260(v=vs.85).aspx