Unterprogramm-Aufruf mit InOut Variable

Hi,

bei solchen Sachen bin ich mir immer ziemlich unsicher:

Aufgabenstellung: An ein Unterprogramm soll eine Zahl übergeben werden. Diese wird darin kausal bearbeitet, und wieder zurückgegeben.

Ich habe das momentan so gelöst:

int Zahl;
// Aufruf:
Zahl = sub (Zahl);

int sub(int sub_zahl) {
   if (irgendwas) {
   sub_zahl++;
   }
   if (irgendwasanderes) {
   sub_zahl--;
   }
   return sub_zahl
}

Funktionieren tut es. Aber ist das so OK, oder gehts einfacher?

In C/C++ heißen Unterprogramme Funktionen. Oder Methoden wenn sie Teil von Klassen sind.

Das geht. Du kannst auch eine Referenz übergeben:

void func(int& zahl)
{
}

Dann wird die Adresse der Variable statt der Wert übergeben und Änderungen sind nach außen sichtbar. Siehe "call by reference"

void func(int& zahl)

oder

void func(int& Zahl)

?

Hi Serenifly,
oh du mein C-Gott und Lehrmeister :slight_smile:

danke für die Erklärung.
Also dann so (mein Prog abgewandelt):

int Zahl;
// Aufruf:
sub (Zahl);

void sub(int& sub_zahl) {
   if (irgendwas) {
   sub_zahl++;
   }
   if (irgendwasanderes) {
   sub_zahl--;
   }
}

Serenifly, stell das mal richtig

Was? Das wegen der Groß-/Kleinschreibung? Spielt doch keine Rolle. Die Variable ist bei ihm "Zahl". Der Parameter kann ruhig anders heißen. Ist bei ihm ja auch "sub_zahl"

Serenifly:
Die Variable ist bei ihm "Zahl". Der Parameter kann ruhig anders heißen.

Kann oder muss?
Dachte ich muss innerhalb der Funktion eine andere Bezeichnung nehmen.

Nein, ich meinte den neuen Code in Post 3. Oder ist das etwa richtig? :confused:

ElEspanol:
Nein, ich meinte den neuen Code in Post 3. Oder ist das etwa richtig? :confused:

Dann sag halt was falsch ist....

Ich hätte eher so gedacht

int Zahl;
// Aufruf:
sub (Zahl);

void sub(int& Zahl) {
if (irgendwas) {
Zahl++;
}
if (irgendwasanderes) {
Zahl--;
}
}

Da sind wir jetzt aber wieder bei meiner Frage aus Post#6

hk007:
Dachte ich muss innerhalb der Funktion eine andere Bezeichnung nehmen.

Nein. Ist vielleicht etwas verwirrend, aber die lokale Variable überdeckt die globale wenn der Name gleich ist.

#3 passt. Es ist natürlich Pseudo-Code, aber korrekt. Wie kommt ihr jetzt darauf dass der Parameter-Name eine Rolle spielt? Der ist vollkommen egal. Nur weil das eine Referenz ist, verhält sich das nicht anders als jede andere Funktion.

Ich war immer der Meinung, dass die Variable in der Funktion nicht genauso heissen darf, wie die globale.
Habe sie daher immer etwas anders genannt.
Auch aus Gründen des besseren Verständniss, wenn ich meine Programmkonstrukte nach längere Zeit wieder angeschaut habe.

Aber habe es gerade probiert. Software läuft in beiden Varianten.

Wäre auch Irrsinn wenn das nicht möglich wäre. Ob es klug ist, ist eine andere Frage. Wenn dich das verwirrt dann lass es sein.

Wird dann durch das int& bestimmt, das der beim Aufruf übergebene Parameter (Zahl) mit dem "überschrieben" wird, was in der Funktion nach dem int& steht ?

Ja. & ist in diesem Kontext der "adress of" Operator. Das heißt es wird statt dem Wert eine Referenz (d.h. die Adresse der Variable) übergeben

Du kannst auch (int &zahl) schreiben. Geschmackssache

Serenifly:
Ob es klug ist, ist eine andere Frage. Wenn dich das verwirrt dann lass es sein.

Ich seh das auch noch aus einem anderen Gesichtspunkt. Eine Funktion kann ich ja öfters aufrufen. Da habe ich beim Aufruf verschiedene Übergabeparameter. Also macht es imho Sinn, die lokale Variable funktionsbezogen zu benennen.

Referenzen und Zeiger sind ein Unterschied, wenn ich mal ein wenig verwirren darf:

In C gibt es nur Zeiger:

int zahl;

void foo ( int * px ) { (*px)++; }

void loop() {
   foo (&zahl); // erhöht zahl bei jedem Aufruf
}

foo erwartet als Parameter den Zeiger auf ein int ( also ein int* ), der Wert auf den der Zeiger zeigt ( *px ) wird dann verändert.
Der Funktion wird explizit die Adresse der Variablen ( &zahl ) übergeben.

in C++ gibt es auch Referenzen. Da sieht das so aus:

int zahl;
void foo (int& rx) { rx++; }  // rx ist eine Referenz auf ein int, kein Zeiger.

void loop() {
  foo (zahl); 
}

Das sieht einfacher aus, macht effektiv dasselbe. Man kann dem Funktionsaufruf foo (zahl); halt nicht direkt ansehen, dass da nicht der Wert der Variablen übergeben wird. Aber eigentlich muss man sowieso die Funktions-Signatur kennen ( welche Parameter mit welchen Datentypen ) um sie verwenden zu können.

Zeiger habe ich mal absichtlich hier nicht erwähnt :slight_smile:

Also das macht ales das gleiche, wieder was dazugelernt:

#include <Streaming.h>
void sub1(int &Zahl) {
  Zahl++;
  return;
}
void sub2(int& Zahl) {
  Zahl++;
  return;
}
void sub3(int &zahl) {
  zahl++;
  return;
}
void sub4(int &subZahl) {
  subZahl++;
  return;
}
void setup() {
  Serial.begin(115200);
  // put your setup code here, to run once:
  int Zahl = 5;
  // Aufruf:
  Serial << Zahl  << endl;
  sub1(Zahl);
  Serial << Zahl  << endl;
  sub2(Zahl);
  Serial << Zahl  << endl;
  sub3(Zahl);
  Serial << Zahl  << endl;
  sub4(Zahl);
  Serial << Zahl  << endl;
}
void loop() {}

Dazulernen ist bei meinem Kenntnisstand auch nichts aussergewöhnliches ;D ;D ;D