Forum: Compiler & IDEs Rückgabe von ZWEI Werten aus einer Funktion


von Balou B. (baloubaer)


Lesenswert?

Hallo alle zusammen,

ich benötige mal wieder einwenig Hilfe von euch.

Ich möchte gern zwei Werte aus einer Funktion zurück geben. Ja ich weiß, 
dass klappt so nicht. Daher hatte ich mir folgendes Überlegt. Ich nutze 
ein Array.

Die Funktion sollte z.B. wie folgt aussehen:
1
uint8_t zweiwerte (uint8_t vorher, uint8_t zaehler)
2
{
3
   uint8_t vorherzaehler[2],i;
4
   vorherzaehler[1]=vorher + 2;
5
   zaehler++;
6
   vorherzaehler[2]=zaehler;
7
   return vorherzaehler;
8
}

würde doch so gehen oder???

aber wie lese ich jetzt die zwei werte im Hauptprogramm aus?
1
#include .......
2
....
3
uint8_t zweiwerte (uint8_t,uint8_t);
4
....
5
int main (void)
6
{
7
.....
8
    jetzt = 10;
9
    zaehler_aktuell = 0;
10
....
11
    zweiwerte (jetzt,zaehler_aktuell); // übergibt den Wert 10 an vorher und den Wert 0 an zaehler
12
//   RICHTIG????
13
    
14
    jetzt = zweiwerte[1];
15
    zaehler_aktuell = zweiwerte[2];
16
.....
17
}

jetzt müste doch in jetzt der Wert 12 stehen und in zaehler_aktuell der 
Wert 1. richtig??? Oder habe ich mir das zueinfach gedacht?

Ich bedanke mich für euere Hilfe und verbleibe

mit freundlichen Grüßen

Balou Baer

von Yalu X. (yalu) (Moderator)


Lesenswert?

Hast du's ausprobiert? ;-)

: Bearbeitet durch Moderator
von Balou B. (baloubaer)


Lesenswert?

Antworten nein, weil das ein Beispiel ist und das eigentliche Programm 
noch lange nicht fertig ist, Kompilieren unmöglich.

von Daniel R. (daro6)


Lesenswert?

Du musst im Hauptprogramm ein Array anlegen und die Adresse an die 
Funktion übergeben. Dann kannst du in der Funktion auf das Array 
zugreifen.
Näheres findest du in einem C-Buch unter Pointer, Adressen einer 
Variable.... ;-).

von Yalu X. (yalu) (Moderator)


Lesenswert?

Daniel R. schrieb:
> Näheres findest du in einem C-Buch

Mist, ich wollte gerade noch schreiben:

Gleich wird jemand kommen und dir ein C-Buch vorschlagen. Recht wird er 
haben.

:)

von Balou B. (baloubaer)


Lesenswert?

Sorry,

ich glaube ich bleibe bei Globalen Variablen, ist zwar eigentlich nicht 
gut, aber das verstehe ich wenigstens ^^.

von Peter P. (Gast)


Lesenswert?

So könnte es gehen. Ist aber nur eine Variante von vielen.
Achtung: vorherzaehler in zweiwerte ist static,
d.h. es gibt nur einen Speicherbereich für die Ergebnisse,
auch wenn du es mehrmals aufrufst.
Achtung: Indizes in C beginnen mit 0, nicht mit 1.
Returnwerte einer Funktion bekommt man nur,
wenn man sie auch anfordert, sonst sind sie weg.

#define uint8_t unsigned char

uint8_t* zweiwerte (uint8_t vorher, uint8_t zaehler)
{
   static uint8_t vorherzaehler[2];
   vorherzaehler[0]=vorher + 2;
   zaehler++;
   vorherzaehler[1]=zaehler;
   return vorherzaehler;
}


int main (void)
{
    uint8_t jetzt = 10;
    uint8_t zaehler_aktuell = 0;
    uint8_t *zweireturnwerte;

    zweireturnwerte = zweiwerte (jetzt,zaehler_aktuell);

    jetzt = zweireturnwerte[0];
    zaehler_aktuell = zweireturnwerte[1];

    printf("jetzt=%d\n", jetzt);
    printf("zaehler_aktuell=%d\n", zaehler_aktuell);
}

Andere Variante von zweiwerte (nicht getestet):

void zweiwerte (uint8_t vorher, uint8_t *zaehler, uint8_t *jetzt)
{
    (*jetzt) = vorher + 2;
    (*zaehler)++;
}

Aufruf in der Art (nicht getestet):

zweiwerte(jetzt, &zaehler_aktuell, &jetzt);

von Bitflüsterer-Schulz (Gast)


Lesenswert?

Ich würde sogar vorschlagen: Lies' ein C-Buch.

von Teo D. (teoderix)


Lesenswert?

Balou Baer schrieb:
> void zweiwerte (uint8_t *vorher, uint8_t *zaehler)
> {
>
>    &vorher=&vorher + 2;
>
>    &zaehler++;
>
> }


> #include .......
> ....
> void zweiwerte (uint8_t *vorher,uint8_t *zaehler);
> ....
> int main (void)
> {
> .....
>     jetzt = 10;
>     zaehler_aktuell = 0;
> ....
>     zweiwerte (&jetzt,&zaehler_aktuell); // übergibt die ADRESSEN von beiden 
Variablen an die Funktion
>
> }

Gugst Du noch mal Funktionen ALGEMEIN und dann speziell Zeiger als 
Funktionsparameter (call–by–reference).

von Tom (Gast)


Lesenswert?

Wenn die zwei Werte irgendwie zusammengehören, darf man auch beide in 
ein ein struct stecken und dieses returnen:
1
typedef struct 
2
{
3
    float x;
4
    float y;
5
} tCoordinate;
6
7
tCoordinate whereami(void)
8
{
9
    tCoordinate position;
10
    position.x = 1.23;
11
    position.y = 3.45;
12
    return position;
13
}
14
15
int main(void)
16
{
17
    tCoordinate pos = whereami();
18
    printf("Ich bin hier: (%f, %f)\n", pos.x, pos.y);
19
}

von Joschua C. (Gast)


Lesenswert?

Geht leider nicht:

Du gibst vorherzaehler mit deinem return zurück. Dieses Array wurde 
allerdings IN der Funktion deklariert. Sie wird aufgerufen, Speicher für 
das Array reserviert, Funktion wird ausgeführt und dann wird der 
Speicher wieder freigegeben. Wenn du das Array zurückgibst, wurde das 
Ding quasi "gelöscht". Bzw sein Speicher darf wieder mit was anderem 
vollgeschrieben werden, was beim nächsten Funktionsaufruf mit großer 
Wahrscheinlichkeit passieren wird.

Daher gibst du der Funktion Speicher zum Vollschreiben mit, der auch 
nach Beenden der Funktion noch reserviert bleibt:
1
void zweiwerte (uint8_t vorher, uint8_t zaehler, vorherzaehler)
2
{
3
   uint8_t vorherzaehler[2],i;
4
   vorherzaehler[1]=vorher + 2;
5
   zaehler++;
6
   vorherzaehler[2]=zaehler;
7
}
1
#include .......
2
....
3
uint8_t zweiwerte (uint8_t,uint8_t);
4
....
5
int main (void)
6
{
7
.....
8
     int vorher[2];
9
    jetzt = 10;
10
    zaehler_aktuell = 0;
11
....
12
    zweiwerte (jetzt,zaehler_aktuell, vorher); // übergibt den Wert 10 an vorher und den Wert 0 an zaehler
13
//   RICHTIG????
14
    
15
    jetzt = vorher[1];
16
    zaehler_aktuell = vorher[2];
17
.....
18
}

jetzt = zweiwerte[1]; geht übrigens nicht. Du kannst 
Pointer=zweiwerte(...)
schreiben und dann pointer[1]

Dann greift man übrigens auf das erste Element eines Arrays mit dem 
Index null und nicht Index 1 zu. vorherzaehler[2] verreißt dir dein 
Programm zur Laufzeit, weil du versuchst auf das dritte Element 
zuzugreifen.

Die ganz feine englische Art wäre:
1
void zweiwerte (uint8_t *vorher, uint8_t *zaehler)
2
{
3
   (*vorher)+=2;
4
   (*zaehler)++;
5
}
1
#include .......
2
....
3
uint8_t zweiwerte (uint8_t,uint8_t);
4
....
5
int main (void)
6
{
7
.....
8
    jetzt = 10;
9
    zaehler_aktuell = 0;
10
....
11
    zweiwerte (&jetzt, &zaehler_aktuell); // übergibt den Wert 10 an vorher und den Wert 0 an zaehler
12
//   RICHTIG????
13
.....
14
}

Du gibst deinem Unterprogramm zwei Zahlen, lässt das UP etwas damit 
machen, holst dir die Ergebnise und kopierst sie dann im Hauptprogramm 
in die Variablen, aus denen auch die zwei Variablen kommen.
C-like wäre, wenn du dem UP nicht sagst wie die Zahlen sind, sondern wo 
sie im Speicher stehen. Dann kann dir dein UP die Arbeit mit dem Werte 
kopieren abnehmen.

Die dritte Möglichkeit wäre übrigens die Rückgabewerte in ein Struct zu 
packen. Ist aber alles Verschwendung von Zeit und Speicher.

von Joschua C. (Gast)


Lesenswert?

Heilige Mutter Gottes, als ich angefangen hab meinen Beitrag zu 
schreiben stand noch keine Antwort da :D

http://openbook.galileocomputing.de/c_von_a_bis_z/012_c_zeiger_001.htm

von Balou B. (baloubaer)


Lesenswert?

Danke euch für die Antworten.

mir raucht der Kopf ich mach jetzt schicht ;).

Ich werde mir mal ein C-Buch morgen aus der Bücherei besorgen / leihen.

Gn8 euch allen

Mit freundlichen Grüßen

Balou Baer

von Yalu X. (yalu) (Moderator)


Lesenswert?

Balou Baer schrieb:
> Ich werde mir mal ein C-Buch morgen aus der Bücherei besorgen / leihen.

Das ist eine gute Entscheidung. In deinem Code oben ist nämlich so
ziemlich alles falsch, was man falsch machen kann, wenn nicht noch mehr
;-)

Das ist aber kein Problem, denn jeder von uns hat mal bei null
angefangen. Man muss das nur einsehen und darf nicht erwarten, dass man
ohne jegliche Literatur sofort komplizierte Dinge anstellen kann. Gerade
in C führt das oft ins Chaos.

von Balou B. (baloubaer)


Lesenswert?

Joschua C. schrieb:
> C-like wäre, wenn du dem UP nicht sagst wie die Zahlen sind, sondern wo
> sie im Speicher stehen. Dann kann dir dein UP die Arbeit mit dem Werte
> kopieren abnehmen.

Wie geht das? Ok wahrscheinlich mit Pointern -> lese ich mich dann 
morgen durch, wenn ich ein C Buch habe

also das wäre die Funktion wenn es so gegangen wäre wie ich gedacht habe 
^^:
1
uint8_t y_zaehler_hoch (uint8_t zaehler, uint8_t vorher_zaehltaster)
2
{
3
  uint8_t zaehler_vorhertaster[2];  
4
    
5
    zaehltaster = ( PINC & _BV ( PC7 ) );
6
7
    if ( zaehltaster != vorher_zaehltaster )
8
    {
9
      zaehler_vorhertaster[1] = zaehltaster;
10
    
11
      if ( zaehltaster )
12
      {
13
        zaehler++;
14
      }
15
    }
16
    zaehler_vorhertaster[2] = zaehler;
17
    return zaehler_vorhertaster;
18
}

Ich benötige zur Flankenerkennung an einem PIN des ATMega32, einmal den 
ursprüngliche Zustand des PIN´s, den wollte ich mit "vorher_zaehltaster" 
übergeben ud den neuen Zustand wieder zurückgeben. Und ich wollte eine 
Zahl hoch / runterzählen. Also die Funktion oben und dann eine weitere 
Funktion die uint8_T y_zaehler_runter (uint8_t zaehler, uint8_t 
vorher_zaehltaster) heist.

von Balou B. (baloubaer)


Lesenswert?

Yalu X. schrieb:
> Man muss das nur einsehen und darf nicht erwarten, dass man
> ohne jegliche Literatur sofort komplizierte Dinge anstellen kann.

Sag das Bitte mal unseren Lehreren!
Ich bin nur ein Elektroinstallateur der sich etwas auf der Abendschule 
weiterbilden will und habe vor dieser Weiterbildung mit programmieren 
nichts zutun gehabt.

Die Lehrer meinen aber, da sitzt ein voll ausgebildeter IT´ler.

von Gaestchen (Gast)


Lesenswert?

Tom schrieb:
> Wenn die zwei Werte irgendwie zusammengehören, darf man auch beide
> in
> ein ein struct stecken und dieses returnen:typedef struct

> tCoordinate whereami(void)
> {
>     tCoordinate position;
>     position.x = 1.23;
>     position.y = 3.45;
>     return position;
> }

Leider absolut falsch, genauso wie vom TO.

>     tCoordinate position;
 position darf zwar innerhalb der Funktion benutzt werden. ist aber nach 
dem Verlassen undefiniert!


>     return position;
 Der Wert der zurückgegeben wird, zeigt auf einen ungültigen Bereich, 
der sich jederzeit ändern kann.
Typischer Anfängerfehler, der zu einem instabilen Programm führt, das 
dann irgendwann abschmiert oder Unsinn macht.

Also entweder:
     static tCoordinate position;
damit der Speicherbereich erhalten bleibt oder global anlegen.

@Balou Baer bei deinem Wissensstand, ist es besser kleinere 
Testprogramme zu schreiben, zu testen und die dann in das größere zu 
Übernehmen. Wenn du soviel Code schreibst und später erst wenn sehr viel 
da steht mit der Fehlersuche beginnst, wirst du erschlagen von den 
Fehlern.

 Ausserdem beschäftige dich mal mit der Parameterübergabe, "by 
reference" und "by value", das könnte Dein Problem eleganter Lösen.

von Sven B. (scummos)


Lesenswert?

Was ist das denn für ein Quatsch? Die struct wird by-value zurückgegeben 
und dabei kopiert. Das ist absolut okay so.

Vielleicht verwechselst du das mit dem by-reference return in C++, wo 
man eine Referenz auf eine Stack-Variable zurückgibt, was dann 
tatsächlich zu Fehlern führt. In C gibt es aber gar keine Referenzen 
(deshalb natürlich auch kein pass-by-reference!).
Mit Pointern kann man zwar den gleichen Fehler machen, dann muss man den 
aber explizit beim return machen (mit einem "&") und das habe ich 
eigentlich noch nie gesehen.

: Bearbeitet durch User
von Dennis S. (eltio)


Lesenswert?

Balou Baer schrieb:
> Antworten nein, weil das ein Beispiel ist und das eigentliche
> Programm
> noch lange nicht fertig ist, Kompilieren unmöglich.

Daran solltest du vielleicht auch arbeiten. Die einzelnen Funktionen 
soweit kapseln, dass sie möglichst einzeln getestet werden können. Das 
können ja Dummy-Werte sein, die du dir selber ausdenkst und dann im 
Hauptprogramm übergibst. Da bietet es sich dann unter Umständen auch gut 
an, vorher nachzudenken welche Ergebnisse man überhaupt erwartet.

Gruß
Dennis

von J. T. (chaoskind)


Lesenswert?

Falls du keine Lust auf Pointer hast, könntest du auch versuchen, die 
beiden Werte in einem zusammenzufassen:
1
uint32_t BeideWerte = 0;
2
uint16_t Wert1 = 10;
3
uint16_t Wert2 = 20;
4
5
BeideWerte = Wert1 | (Wert2 << 16)

Ist nicht getestet, aber so sollte dein Wert2 in den oberen 16 Bit des 
32bit Werts stehen und Wert1 sollte in den unteren 16 Bit liegen.

MfG Chaos

von Teo D. (teoderix)


Lesenswert?

Mal davon abgesehen, das man daß irgendwie hinbiegen kann, das eine 
Funktion zwei Rückgabewerte liefert.(was natürlich auch wieder falsch 
ist, da es doch nur ein wert bleibt) Führt das doch, das ganze Konzept 
einer Funktion mit Rückgabewert ad absurdum!

Wenn dann sollte der TO das richtig lernen, darum geht's doch!
Also, Globale Variablen oder call by value. Alles andere ist 
Schwachsinn!

von Peter (Gast)


Lesenswert?

Teo Derix schrieb:
> Also, Globale Variablen oder call by value. Alles andere ist
> Schwachsinn!

mit starken Ausdrücken sollte man sich zurückhalten, aber:
nicht alles andere, sonderne deine Aussage ist Schwachsinn

von Karl H. (kbuchegg)


Lesenswert?

Teo Derix schrieb:

> Wenn dann sollte der TO das richtig lernen, darum geht's doch!

Genau.
Und richtig ist in diesem Fall die Erkenntnis, dass die beiden 
Funktionalitäten, die er da in eine gemeinsame Funktion stecken will, 
nichts miteinander zu tun haben
* einen Tastendruck zu erkennen ist eine Funktionalität
* aufgrund eines Tastendrucks einen Zähler zu erhöhen oder erniedrigen, 
ist eine andere Funktinoalität

In seinem Fall stellt sich die Frage nach den beiden Rückgabewerten also 
überhaupt nicht, weil sein grundsätzliches Programmdesign in erster 
Linie schon daneben ist.
Was natürlich nicht heißt, dass man die Techniken, wie man Werte in eine 
Funktion hinein und wieder heraus kriegt, links liegen lassen darf.

von Teo D. (teoderix)


Lesenswert?

Peter schrieb:
> mit starken Ausdrücken sollte man sich zurückhalten,
Dazu sag ich nur :P

>aber:
> nicht alles andere, sonderne deine Aussage ist Schwachsinn
Hole Worte, füll sie doch mal bitte. Will ja nicht dumm sterben.

von DirkB (Gast)


Lesenswert?

@Gaestchen
Was du da beschreibst, steht in der ersten Ausgabe vom K&R und galt 
damals schon nur für einige Compiler.

Seit C89 kann man komplette structs als Rückgabewert von Funktionen 
nehmen.
Sogar mit Arrays drin.

structs sind keine Arrays.


@Balou Baer
Dein Array zaehler_vorhertaster ist eine automatische (lokale) Variable.
D.h. sie wird bei jedem Funktionsaufruf neu angelegt und beim verlassen 
zerstört.
Alte Werte bleibe da nicht erhalten.

von Daniel A. (daniel-a)


Lesenswert?

Man kann auch einen pointer auf eine bestehende variabe übergeben, um 
mehrere rückgabewerte zu simulieren.
1
void swapInt( int* a, int* b ){
2
  int t = *a;
3
  *a = *b;
4
  *b = t;
5
}
6
7
int main(){
8
  int a=1;
9
  int b=2;
10
  swapInt(&a,&b);
11
  printf("a=%d, b=%d", a,b);
12
  return 0;
13
}

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Daniel A. schrieb:
> um mehrere rückgabewerte zu simulieren

Mit "Simulieren" hat das nichts zu tun, das nennt sich "call by 
reference".

In Deinem Code sollte allerdings überprüft werden, ob die Pointer keine 
Null-Pointer sind:
1
void swapInt(int* a, int* b)
2
{
3
  int t;
4
5
  if (a && b)
6
  {
7
    t = *a;
8
    *a = *b;
9
    *b = t;
10
  }
11
}

von Sven B. (scummos)


Lesenswert?

Teo Derix schrieb:
> Mal davon abgesehen, das man daß irgendwie hinbiegen kann, das eine
> Funktion zwei Rückgabewerte liefert.(was natürlich auch wieder falsch
> ist, da es doch nur ein wert bleibt) Führt das doch, das ganze Konzept
> einer Funktion mit Rückgabewert ad absurdum!
>
> Wenn dann sollte der TO das richtig lernen, darum geht's doch!
> Also, Globale Variablen oder call by value. Alles andere ist
> Schwachsinn!

Genau das Gegenteil ist der Fall. Globale Variablen und die hässlichen 
"Output Parameter" untergraben das Konzept von Funktionen. Die 
ursprüngliche Idee ist doch, dass eine Funktion funktioniert wie in der 
Mathematik, also ohne Nebeneffekte. Es gibt auch Sprachen, die das 
konsequent so umsetzen.

Dass das nicht immer sinnvoll ist, vor allem in C, ist klar, aber zu 
behaupten es sei absurd Funktionen so zu benutzen ist ... absurd. Das 
ist die beste Art, Funktionen zu benutzen: ohne Nebeneffekte, nur n 
Inputs auf m Outputs und die Inputs sind die Parameter und die Outputs 
die Rückgabewerte.

von Teo D. (teoderix)


Lesenswert?

Teo Derix schrieb:
>> nicht alles andere, sonderne deine Aussage ist Schwachsinn
> Hole Worte, füll sie doch mal bitte. Will ja nicht dumm sterben.

OK, wenn Du das nicht kannst mach ich's halt selber :)

Die Aussage
Beitrag "Re: Rückgabe von ZWEI Werten aus einer Funktion"
ist definitiv Schwachsinn!
Natürlich gibt es genügend Gründe, warum globalen Variablen oder Call by 
Value nicht wünschenswert ist!
Da bleiben halt nur Structs, Arrays oder Zeiger, als Rückgabewert. Ob 
andere Krücken sinnvoll sind ???


PS: Wahr wohl zu sehr auf das Problem des TO fixiert :(

von Yalu X. (yalu) (Moderator)


Lesenswert?

Karl Heinz schrieb:
> Und richtig ist in diesem Fall die Erkenntnis, dass die beiden
> Funktionalitäten, die er da in eine gemeinsame Funktion stecken will,
> nichts miteinander zu tun haben
> * einen Tastendruck zu erkennen ist eine Funktionalität
> * aufgrund eines Tastendrucks einen Zähler zu erhöhen oder erniedrigen,
> ist eine andere Funktinoalität

Das ist völlig richtig, löst aber das eigentliche Problem nicht.

Die ursprüngliche, "All-in-One"-Funktion liefert zwei Ergebnisse,
nämlich den letzten Tastenstatus (gedrückt oder nicht gedrückt) und den
Zählerstand.

Teilt man die Funktion in zwei Funktionen (Flankenerkennung und Zählen)
auf, hat die Flankenerkennung ebenfalls zwei Ergebnisse, nämlich den
letzten Tastenstatus und das Flankenereignis (Flanke erkannt oder
nicht erkannt).

Wie man es auch dreht und wendet, das grundsätzliche Problem bleibt
bestehen. Natürlich gibt es viele Lösungen dafür, aber leider keine, die
man guten Gewissens einem Anfänger als die richtige empfehlen könnte.
Die letztendlich getroffene Wahl hängt meist vom jeweiligen Kontext und
vom persönlichen Geschmack ab.

Die meisten neueren Programmiersprachen übernehmen deswegen zwei
Konzepte aus der funktionalen Programmierung, nämlich Tuples und
Pattern-Matching, die das Problem auf elegante Weise lösen.

Auch in der objektorientierten Programmierung gibt es bessere Lösungen
als in C: Da würde man eine Klasse Taste mit dem letzten Tastenstatus
als Membervariable anlegen. Auf diese Membervariable haben die einzelnen
Methoden der Klasse Zugriff, wodurch man die gleichen Möglichkeiten wie
mit globalen Variablen, aber mit eingeschränktem Scope, erhält.

: Bearbeitet durch Moderator
von Schaulus Tiger (Gast)


Lesenswert?

Yalu X. schrieb:
> Auch in der objektorientierten Programmierung gibt es bessere Lösungen
> als in C: Da würde man eine Klasse Taste mit dem letzten Tastenstatus
> als Membervariable anlegen. Auf diese Membervariable haben die einzelnen
> Methoden der Klasse Zugriff, wodurch man die gleichen Möglichkeiten wie
> mit globalen Variablen, aber mit eingeschränktem Scope, erhält.

Ach, und seit wann geht das in C nicht?

von Remo F. (remo_f)


Lesenswert?

Hallo!

Na du merkst sicher, es geht hier um ein Thema in dem persönliche 
Vorlieben eine große Rolle spielen. Meine Erfahrung in der Entwicklung 
hat mir gezeigt, daß es wichtig ist Code lesbar zu halten, damit man 
auch noch nach zwei Monaten weiß was man da gemacht hat. Deshalb gefällt 
mir persönlich von den genannten Lösungen jene mit einer struct am 
besten. Außerdem hat ein struct den Vorteil, daß du sie jederzeit 
erweitern kannst und damit deinen Code modular hältst. Ob du die Instanz 
deiner Variablen dann global oder irgendwo lokal hältst, ist nicht so 
wichtig und hängt meiner Meinung stark vom Verwendungszweck ab. Hier 
mein Beispiel zur Implementation mit struct, das sich in Atmel Studio 
6.2 auch kompilieren lässt:
1
struct ZweiWerte {
2
  uint8_t Wert1;
3
  uint8_t Wert2;
4
};
5
6
void MachWas(ZweiWerte* werte)
7
{
8
  werte->Wert1++;
9
  werte->Wert2++;
10
}
11
12
int main(void)
13
{
14
  ZweiWerte werte;
15
  werte.Wert1 = 1;
16
  werte.Wert2 = 2;
17
  MachWas(&werte);
18
}

Dein Ansatz mit dem array kann natürlich auch funktionieren. Dabei musst 
du jedoch darauf achten, daß du den reservierten Speicher auch wieder 
frei gibst. Außerdem ist es wesentlich schwieriger aus dem Code die 
Bedeutung jedes einzelnen Wertes raus zu lesen und auch die Erweiterung 
wird sich in Folge schwierig und fehleranfällig gestalten. Eine mögliche 
Implementierung:
1
uint8_t* MachWasAnderes(uint8_t wert1, uint8_t wert2)
2
{
3
  uint8_t* werte = (uint8_t*)malloc(sizeof(uint8_t) * 2);
4
  werte[0] = wert1;
5
  werte[1] = wert2;
6
  return werte;
7
}

Grüße!
Remo

von Ralf G. (ralg)


Lesenswert?

Remo F. schrieb:
> Eine mögliche Implementierung:

Bitte nicht nachmachen!

(Funktion reserviert Speicher, der außerhalb der Funktion freigegeben 
werden muss...)

von Remo F. (remo_f)


Lesenswert?

Ja, hab ich auch geschrieben, danke.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Schaulus Tiger schrieb:
> Ach, und seit wann geht das in C nicht?

Ja, prinzipiell geht das auch in C. Ich vermute, du spielst darauf an,
der Funktion einen Zeiger  auf eine Struktur mit den Membervariablen zu
übergeben, so wie es weiter oben schon von Remo F. vorgeschlagen wurde.

Die C++-Variante mit einem Objekt und Private-Membervariablen ist halt
etwas gediegener, weil sie die Membervariablen vor dem Anwender der
Funktionen versteckt und so weniger Freiraum für (unabsichtliches)
Schindluder lässt.

von Schaulus Tiger (Gast)


Lesenswert?

ich meinte sowas in dieser Art, keine Ahnung, ob "man" das so macht:
1
/* zaehltaste.c */
2
3
static int zaehlerstand = 0;
4
5
void
6
zaehlpin_abfrage (int pin_zustand)
7
{
8
static int alter_zustand = 0;
9
10
  if (pin_zustand != alter_zustand) {
11
    alter_zustand = pin_zustand;
12
    if (pin_zustand != 0) {
13
      zaehlerstand += 1;
14
    }
15
  }
16
}
17
18
int
19
get_zaehlerstand (void)
20
{
21
  return zaehlerstand;
22
}

von Remo F. (remo_f)


Lesenswert?

Servus!

Meinem Verständnis nach war die ursprüngliche Frage wie man aus einer 
Funktion mehrere Werte zurück gibt. Es gibt in der Entwicklung immer 
mehr als einen Lösungsweg für eine Problemstellung. Auch einzelne 
globale Variablen sind möglich. Allerdings würde ich eher eine globale 
struct machen, damit ich durch die Eingabehilfe der IDE auch immer einen 
Überblick über diese hab.

Grüße!
Remo

von Yalu X. (yalu) (Moderator)


Lesenswert?

Schaulus Tiger schrieb:
> ich meinte sowas in dieser Art, keine Ahnung, ob "man" das so macht:

Ja, das macht man oft so, ich selber übrigens auch.

Das Programmmodul mit ein paar Funktionen und globalen Variablen hat
viele der Eigenschaften einer OOP-Klasse, von der genau ein Objekt
instanziiert wird. Durch "static" kann man Variablen oder Funktionen
sozusagen "private" machen, da sie außerhalb des Mopduls nicht sichtbar
sind.

Der Hauptnachteil dieser Methode besteht darin, dass es von der "Klasse"
nur eine einzige Instanz gibt. Wenn im konkreten Beispiel mit dem Taster
noch ein zweiter hinzukäme, würde diese Lösung nicht mehr funktionieren.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Remo F. schrieb:
> Allerdings würde ich eher eine globale struct machen

Das ist dann aber kein "Rückgabewert" einer Funktion, sondern nichts 
besseres als eine globale Variable.

Und so etwas ist in 99.95% aller Fälle Murks.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.