Pages: [1] 2   Go Down
Author Topic: Funktion mit Wertrückgabe ?  (Read 1443 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
God Member
*****
Karma: 4
Posts: 583
ATmega 2560
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo,

kann eine Funktion wirklich nur ein Wert zurückgeben oder doch soviel man möchte?
Auch wenn man globale Variablen verwendet?
Logged

Tschau
Doc Arduino

Hamburg, Germany
Offline Offline
Sr. Member
****
Karma: 5
Posts: 291
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Wenn Du Pointer verwendest, kann eine Funktion auch mehrere Werte zurück"geben". Wobei das strenggenommen kein zurückgeben ist, sondern eher das Beschreiben von Speicherbereichen, die dann per Referenz wieder abgerufen werden können.
Logged


Wien
Offline Offline
Edison Member
*
Karma: 23
Posts: 1667
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

hi,

ich glaube, da hast Du was falsch verstanden.

man kann in einer funktion natürlich soviele globale variablen ändern, wie man will, und mit diesen veränderten variablen dann in anderen funktionen arbeiten.

der rückgabewert einer variablen ist etwas anderes:

byte summe(byte a, byte b) {
  return a+b;
}

der rückgabewert dieser funktion ist die summe aus a und b, man fragt also mit

c = summe(4, 7);

ab, und c ist dann 11.

auf diese art ist dann natürlich nur ein rückgabewert möglich. mit pointern sollte dann wohl mehr gehen.

gruß stefan
Logged

Offline Offline
God Member
*****
Karma: 4
Posts: 583
ATmega 2560
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo,

ich verarbeite in 2 Funktionen mehrere globale Variablen. Zwischen den Funktionsaufrufen muß ich diese ändern und dann werden diese wieder in der nächsten verarbeitet. Deshalb brauche ich die Werte der globalen Variablen aus den Funktionen immer zurück. Das geht nur mit Pointern?

Wer hat denn das verzapft das man nur eine Variable zurückbekommt.   smiley-sad

Das geht demzufolge nicht so einfach.

Code:
int Kometenschweif_Links ()
   {
     analogWrite(LEDPOS_1, LED_H1);                                 
     analogWrite(LEDPOS_2, LED_H2); 
     analogWrite(LEDPOS_3, LED_H3);               
     analogWrite(LEDPOS_4, LED_H4);     
     analogWrite(LAST_LED, LOW);                     // letzte alte LED ausschalten
             
     LAST_LED = LEDPOS_4;                              // letzte Position merken
     LEDPOS_4 = LEDPOS_3;                              // LED Position nachrücken
     LEDPOS_3 = LEDPOS_2;
     LEDPOS_2 = LEDPOS_1;
     LEDPOS_1--;
         
     delay(3000);       
                           
     if (LEDPOS_1 < 2) { LEDPOS_1 = 9; }             // wenn letzte LED erreicht, auf Anfangsposition setzen
     
     return LEDPOS_1; LEDPOS_2; LEDPOS_3; LEDPOS_4; LAST_LED;
   }
Logged

Tschau
Doc Arduino

Offline Offline
Newbie
*
Karma: 0
Posts: 31
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

verzapft ist gut smiley-wink in welcher anderen sprache geht sowas?

mit pointern kannste alles verändern und nebenbei extrem viel blödsinn anstellen.

Quote
mehrere globale Variablen

wozu musst du die zurückgeben?

 
Quote
LAST_LED = LEDPOS_4;                              // letzte Position merken
     LEDPOS_4 = LEDPOS_3;                              // LED Position nachrücken
     LEDPOS_3 = LEDPOS_2;
     LEDPOS_2 = LEDPOS_1;
     LEDPOS_1--;

das ganze ist laut deiner aussage global und somit änderst du den inhalt jeder globalen variable in jeder deiner funktionen!
da brauchst du keine rückgabe.

sobald du in deinem kometenschweif die werte für LEDPOS_3 = LEDPOS_2; etc geändert hast, kannst du nach dem aufruf für kometenschweif die neuen werte weiter benutzen.
Logged

Offline Offline
God Member
*****
Karma: 4
Posts: 583
ATmega 2560
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo,

oh Mann, ich Idiot. Jetzt wo Du das sagst, klar, wofür habe denn globale Variablen verwendet. Na dann brauche ich keine Rückgabewerte, logisch.  smiley-wink

Ich denke mal es hätte niemanden daran gehindert die Funktion so zu programmieren das man auch mehrere Rückgabewerte verwenden kann. Ich meine, übergeben kann man soviel man braucht an die Funktion. Nur beim rausrücken wird gespart. Das könnte vieles vereinfachen. Die Einschränkung verstehe ich nicht.

Logged

Tschau
Doc Arduino

Germany S-H
Offline Offline
Edison Member
*
Karma: 117
Posts: 2460
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Wer hat denn das verzapft das man nur eine Variable zurückbekommt.   smiley-sad

Als sogenannten "Rückgabewert" kannst Du nur einen einzigen Wert zurückbekommen. Das ist der Wert, der vor der Funktionsdeklaration steht, also das "int" vor dem Funktionsnamen "summe":

int summe(int a, int b)
{
  return a+b;
}

Der return-Wert. Dieser Wert ist direkt Zuweisungskompatibel. Und so wie ein Gleichheitszeichen nur eine einzige Zuweisung macht, macht eine Funktion auch nur einen einzigen zuweisungsfähigen Rückgabewert:

int i=summe(2,4);

Trotzdem kann eine Funktion auch mehrere Werte "zurückgeben", und zwar wenn Du diese Werte auch vorher auch an die Funktion "übergeben" hast, und zwar als Parameter mit spezieller Aufrufkonvention.

Bei der Parameterübergabe an Funktionen gibt es zwei Möglichkeiten:
1. Call by Value ==> Parameter als Wert an die Funktion übergeben
2. Call by Reference ==> Parameter als Referenz an die Funktion übergeben

Die "by Value" übergebenen Parameter können Konstanten sein, oder Variablen, die nach der Rückkehr aus der Funktion unverändert sind.

Die "by Reference" übergebenen Parameter werden als Adressreferenz an die Funktion übergeben, und wenn die Funktion diese Parameter in der Funktion verändert und die Funktion kehrt zurück, dann haben diese Parameter ihren veränderten Wert!

Eventuell kennst Du die Parameterübergabe "by Reference" noch nicht.

Eine Parameterübergabe "by Reference" wird so deklariert, dass bei der Funktionsdeklaration ein "&"-Zeichen (Adressoperator) vor den so zu übergebenden Parameter geschrieben wird.

Ich habe mal ein Beispielprogramm mit zwei Funktionen gemacht, bei denen ein oder mehrere Parameter "by Reference" übergeben werden.

Code:
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}


void zumQuadrat(float &x){
   x = x*x;
}


void testParamsByReference(int a, int b, int c, int &ret1, int &ret2, int &ret3)
{
  ret1=a+b+c;
  ret2=a*b*c;
  ret3=ret1+ret2;
}


void loop() {
  // put your main code here, to run repeatedly:
  float x=1.5; 
  Serial.print("x= ");
  Serial.println(x);
  zumQuadrat(x);
  Serial.println("Zum Quadrat nehmen");
  Serial.print("x= ");
  Serial.println(x);
  Serial.println();
 
  int var1, var2, var3, var4, var5, var6;
  var1=4;
  var2=5;
  var3=6;
  testParamsByReference(var1, var2, var3, var4, var5, var6);
  Serial.print("Var1= ");
  Serial.println(var1);
  Serial.print("Var2= ");
  Serial.println(var2);
  Serial.print("Var3= ");
  Serial.println(var3);
  Serial.print("Summe: ");
  Serial.println(var4);
  Serial.print("Produkt: ");
  Serial.println(var5);
  Serial.print("Summe plus Produkt: ");
  Serial.println(var6);
  while (true==true);
}

Probier's aus: Eine Parameterliste einer Funktion kann praktisch beliebig lang sein, und darunter können beliebig viele "by Reference" Parameter sein, deren "Rückgabewert" Du nach dem Aufrufen der Funktion auswerten kannst.

Du kannst einen, mehrere oder alle Parameter "by Reference" an eine Funktion übergeben.
Bei Bedarf einfach den "&"-Adressoperator mit in die Funktionsdeklaration des Parameters schreiben.

Ist es eventuell das, was Du gesucht hast?
Logged

Neuss
Offline Offline
Full Member
***
Karma: 0
Posts: 200
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo,

oh Mann, ich Idiot. Jetzt wo Du das sagst, klar, wofür habe denn globale Variablen verwendet. Na dann brauche ich keine Rückgabewerte, logisch.  smiley-wink

Ich denke mal es hätte niemanden daran gehindert die Funktion so zu programmieren das man auch mehrere Rückgabewerte verwenden kann. Ich meine, übergeben kann man soviel man braucht an die Funktion. Nur beim rausrücken wird gespart. Das könnte vieles vereinfachen. Die Einschränkung verstehe ich nicht.


Hallo,,
wenn du noch was lernen möchtest, dann schau doch mal in google oder einen C++-Lehrbuch zu dem Thema "Referenzen" nach. damit kannst du die Verwendung von Pointern bei der Rückgabe von mehreren Werten vermeiden. Z.B. hier
http://de.wikipedia.org/wiki/Referenzparameter unter dem Stichwort "Referenzparameter in Form von Referenzen".

Manche Leute sehen die Verwendung von globalen Variablen zur Parameterübergabe (oder überhaupt) als ganz schön "bah, bah" an smiley-wink
Man kann damit bei größeren Programmen nämlich ganz schnell den Überblick verlieren, wer wo etwas verändert.

Gruß
Wolfgang

[Edit]Mist,  da war jurs wohl schneller als ich und sogar noch ausführlicher
« Last Edit: March 15, 2013, 03:05:46 pm by voithian » Logged

Offline Offline
God Member
*****
Karma: 4
Posts: 583
ATmega 2560
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo,

klingt erstmal für mich sehr kompliziert.  smiley-confuse  Werde mir das in Ruhe anschauen und mehrfach lesen müssen. Danke Euch.

Hier mein Kometenschweif, der erstmal soweit funktioniert. Verwendete Pins sind 2 bis 9. Das soll ein zusätzlicher Lichteffekt werden außen herum für meinen Würfel, wenn er würfelt bei Tastendruck.

Code:
// Arduino Mega 2560

// Geschwindigkeitssteigerung des Kometenschweifs bzw. abbremsen
int PAUSE [41] = {48,52,56,60,64,68,72,77,82,86,91,96,101,107,112,118,123,129,135,141,147,154,160,167,174,180,188,195,202,209,217,225,233,240,249,257,265,274,282,291,300 };
int SPEED = 40;       

int LEDPOS_1 = 5;                      // auf sicheren Anfangswert gesetzt für ersten Durchlauf
int LEDPOS_2 = 4;                      // auf sicheren Anfangswert gesetzt für ersten Durchlauf
int LEDPOS_3 = 3;                      // auf sicheren Anfangswert gesetzt für ersten Durchlauf
int LEDPOS_4 = 2;                      // erster Pin der LED Reihe
int LAST_LED = 9;                      // letzter Pin der LED Reihe

int LED_1, LED_2, LED_3, LED_4;        // zum Zwischen speichern der LED Position zum umdrehen

int LED_H1 = 255;        // 255, Helligkeiten der LEDs     
int LED_H2 = 96;         //  96
int LED_H3 = 32;      //  32
int LED_H4 = 8;           //   8

void setup()
{     
//   Serial.begin(9600);
 
  // set pins 2 through 9 as outputs:
  for (int thisPin =2; thisPin <= 9; thisPin++)
   {
    pinMode(thisPin, OUTPUT);
   }

//  Serial.println("\n[memCheck]");
//  Serial.println(freeRAM(), DEC); 
   
}

void loop()
{

  for (int i=0; i < 60; i++)
    {
     Kometenschweif_Rechts ();
    }

  Schweif_nach_links_drehen ();
     
  for (int i=0; i < 47; i++)
    {
     Kometenschweif_Links ();
    }

  Schweif_nach_rechts_drehen ();   

}

 


/* ***  Funktionen  *** */

void Kometenschweif_Rechts ()
{
     if (LEDPOS_1 > 9) { LEDPOS_1 = 2; }             // wenn "letzte" LED erreicht, auf Anfangsposition setzen
     
     analogWrite(LEDPOS_1, LED_H1);                  // 8, Schweifspitze ganz hell                                   
     analogWrite(LEDPOS_2, LED_H2);                  // 7, LED dahinter etwas dunkler   
     analogWrite(LEDPOS_3, LED_H3);                  // 6, nächste LED noch dunkler                 
     analogWrite(LEDPOS_4, LED_H4);                  // 5, letzte LED noch dunkler       
     analogWrite(LAST_LED, LOW);                     // letzte alte LED ausschalten
             
     LAST_LED = LEDPOS_4;                            // 5

     LEDPOS_4 = LEDPOS_3;                            // 6
     LEDPOS_3 = LEDPOS_2;                            // 7
     LEDPOS_2 = LEDPOS_1;                            // 8
     LEDPOS_1++;                                     // 9
 
     delay(PAUSE[SPEED]);                            // Kometenschweif beschleunigen
     SPEED--;
     if (SPEED < 1) { SPEED = 0; }                   // schnellsten Wert beibehalten
                           
}


void Kometenschweif_Links ()
{
     if (LEDPOS_1 < 2) { LEDPOS_1 = 9; }             // wenn "letzte" LED erreicht, auf Anfangsposition setzen

     analogWrite(LEDPOS_1, LED_H1);                  // Schweifspitze ganz hell                 
     analogWrite(LEDPOS_2, LED_H2);                  // LED dahinter etwas dunkler       
     analogWrite(LEDPOS_3, LED_H3);                  // nächste LED noch dunkler                     
     analogWrite(LEDPOS_4, LED_H4);                  // letzte LED noch dunkler           
     analogWrite(LAST_LED, LOW);                     // letzte alte LED ausschalten
             
     LAST_LED = LEDPOS_4;

     LEDPOS_4 = LEDPOS_3;
     LEDPOS_3 = LEDPOS_2;
     LEDPOS_2 = LEDPOS_1;
     LEDPOS_1--;
         
     delay(PAUSE[SPEED]);                            // Kometenschweif abbremsen
     SPEED++;
     if (SPEED > 40) { SPEED = 40; }                 // langsamsten Wert beibehalten
}
 

void Schweif_nach_links_drehen ()
{
     LED_1 = LAST_LED;             //5,  LED Positionen zwischen speichern
     LED_2 = LEDPOS_4;             //6
     LED_3 = LEDPOS_3;             //7
     LED_4 = LEDPOS_2;             //8

     LEDPOS_1 = LED_1;             //5,  LED Positionen umdrehen
     LEDPOS_2 = LED_2;             //6
     LEDPOS_3 = LED_3;             //7
     LEDPOS_4 = LED_4;             //8

     if (LEDPOS_4 >= 9) { LAST_LED = 2;}
       else { LAST_LED = LEDPOS_4 + 1; }
}


void Schweif_nach_rechts_drehen ()
{
     LED_1 = LAST_LED;              //  LED Positionen zwischen speichern
     LED_2 = LEDPOS_4;             
     LED_3 = LEDPOS_3;       
     LED_4 = LEDPOS_2;         

     LEDPOS_1 = LED_1;              //  LED Positionen umdrehen
     LEDPOS_2 = LED_2;           
     LEDPOS_3 = LED_3;           
     LEDPOS_4 = LED_4;           

     if (LEDPOS_4 <= 2) { LAST_LED = 9;}
       else { LAST_LED = LEDPOS_4 - 1; }
}


int freeRAM()                                     //  Funktion im WWW gefunden, zeigt freien Speicher an
  {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
  }

Logged

Tschau
Doc Arduino

Munich/Germany
Offline Offline
God Member
*****
Karma: 9
Posts: 642
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

verzapft ist gut smiley-wink in welcher anderen sprache geht sowas?
Mehrere Rückgabewerte gehen z.B. schon immer in Python und seit einiger Zeit auch in .NET. Stichwort: Tupel
Da kann man dann z.B. solche Konstrukte machen: a,b,c = mach_irgendwas()
Ist eine nette Sache. Wenn man sich daran mal gewöhnt hat, vermisst man es bei anderen Sprachen schon etwas.
Logged

_______
Manfred

Meran/BZ/IT
Offline Offline
Full Member
***
Karma: 0
Posts: 184
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@jurs
wow, Du hast den gordischen Knoten bezüglich Pointer in meinem Hirn zerschlagen!
 smiley-grin

Wenn Du jetzt noch eine ähnlich klare Erklärung für "dereference" hättest.....
 smiley-red
Logged

Forum Moderator
BZ (I)
Online Online
Brattain Member
*****
Karma: 236
Posts: 20287
+39 349 2158303
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

verzapft ist gut smiley-wink in welcher anderen sprache geht sowas?
Mehrere Rückgabewerte gehen z.B. schon immer in Python und seit einiger Zeit auch in .NET. Stichwort: Tupel
Da kann man dann z.B. solche Konstrukte machen: a,b,c = mach_irgendwas()
Ist eine nette Sache. Wenn man sich daran mal gewöhnt hat, vermisst man es bei anderen Sprachen schon etwas.
Es ist zwar schön in Nachbars Garten zu schauen und sich zu freuen, was es da so alles gibt, aber man muß im eingenen Garten bleiben, sprich C /C++ benutzen das Arduino versteht.
Zum Rückgabewert. Viele Funktionen geben im Fehlerfall -1 zurück.

Vieel Grüße Uwe
Logged

0
Offline Offline
Faraday Member
**
Karma: 19
Posts: 3420
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

1) Wie schon erwähnt wurde kann C Referenzen in den Aufrufparametern verwenden.
2) Man kann sich ja beliebige Strukturen für die Rückgabeparameter definieren. Problem dabei ist nicht C sondern die schlecht gemachte Arduino IDE die meint Prototypen definieren zu müssen aber dabei typedefs nicht berücksichtigt. Ein Workaround ist TRICK17 http://blog.blinkenlight.net/2012/09/01/trick-17/, die andere Lösung die Verwendung von Namespaces, also so:

Code:
namespace example {
    typedef struct {
        int a;
        int b;
        int c;
    } triple;
        
    triple test(const int x, const int y, const int z) {
        triple value;
        value.a = x;
        value.b = y;
        value.c = z;
        return value;
    }
    
    triple test2(const int x, const int y, const int z) {
        return triple {x, y, z};
    }
}


void setup() {
    using namespace example;
    
    const triple result = test(1,2,3);
    
    const int x = result.a;
    const int y = result.b;
    const int z = result.c;
}

void loop() {}

test() und test2() haben das gleiche Verhalten sind aber einmal ausführlich und einmal kurz hingeschrieben.

Stattdessen globale Variablen zu verwenden ist nicht wirklich Stand der Technik.
« Last Edit: March 16, 2013, 06:26:29 am by Udo Klein » Logged

Check out my experiments http://blog.blinkenlight.net

Offline Offline
God Member
*****
Karma: 9
Posts: 721
42
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo Udo,


dankefür das kurze Tutorial. Das mit NAmespaces war mir völligeu im Arduino-Chargon, kannte ich bisher nurvon DotNet.
Verhalten sich die Namespaces genau wie in z.B. C#, dass man ohne die Using-Direktive z.B. "example.result.a" schreiben könnte? Und wie verhält es sich mit der Speichernutzung?
Logged


0
Offline Offline
Faraday Member
**
Karma: 19
Posts: 3420
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Fast jede moderne Sprache hat so ein Konzept. Manche mehr manche weniger smiley-wink Namespaces wirken sich bei kompilierten Sprachen eher wenig bis gar nicht auf den Speicherverbrauch aus. Was die Verwendung in C++ angeht guckst Du hier: http://www.cplusplus.com/doc/tutorial/namespaces/
Logged

Check out my experiments http://blog.blinkenlight.net

Pages: [1] 2   Go Up
Jump to: