[erledigt] Referenz mehrfach verwenden

Meine gedankliche Analogie:

byte a = 5;
...
a = 7;

Das funktioniert:

Setlist &s = liste[zeile];
...
Setlist &t = liste[z];

Das funktioniert nicht: error: lvalue required as left operand of assignment

Setlist &s = liste[zeile];
...
Setlist &t = liste[z];

Das funktioniert auch nicht: error: redeclaration of 'Setlist& s'

Setlist &s = liste[zeile];
...
Setlist &t = liste[z];

Wo liegt mein Denkfehler, wie mache ich es richtig?

Meine Baustelle im Zusammenhang, siehe Zeile 300 (ich teste auf Teensy 3.2, mit ROW_DIM 50 compiliert es für einen Mega2560, sollte aber egal sein):

// Strukturierte Textdatei von SD lesen und anzeigen
// Beispiel aus SdFat: ReadCsvArray.ino
// getestet mit Teensy 3.2 und OLED SSD1306
#include <Arduino.h>
#include "U8g2lib.h"
#include <SPI.h>
#include <Wire.h>

U8G2_SSD1306_128X64_NONAME_F_HW_I2C oled(U8G2_R0);

#include <SdFat.h>
#define CS_PIN SS

#define ROW_DIM 300
#define COL_DIM 4
#define MAXCOL 21

#include <Bounce2.h>
Bounce debSongVor = Bounce();
Bounce debSongZur = Bounce();
Bounce debVor = Bounce();
Bounce debZur = Bounce();
const byte pinSongVor = 0;  // Taster Song vorwärts Blättern
const byte pinSongZur = 1;  // Taster Song zurück Blättern
const byte pinVor = 2;  // Taster vorwärts Blättern
const byte pinZur = 3;  // Taster zurück Blättern

SdFat SD;
File file;

class Setlist {
    char song[MAXCOL];
    char part[MAXCOL];
    char sound[MAXCOL];
    char midi[MAXCOL];
  public:
    Setlist() {}

    void init() {
      for (byte j = 0; j < MAXCOL; j++) {
        song[j] = '\0';
        part[j] = '\0';
        sound[j] = '\0';
        midi[j] = '\0';
      }
    }

    void anzeige() {
      oled.clearBuffer();          // clear the internal memory
      oled.setCursor(0, 10);
      oled.print(song);
      oled.setCursor(0, 20);
      oled.print(part);
      oled.setCursor(0, 30);
      oled.print(sound);
      oled.setCursor(0, 40);
      oled.print(midi);
      oled.sendBuffer();          // transfer internal memory to the display
    }

    void ausgabe(uint16_t j) {
      if (song[0] != '\0') {
        Serial.print(j); Serial.print(F(" \t"));
        Serial.print(song); Serial.print(F(" \t"));
        Serial.print(part); Serial.print(F(" \t"));
        Serial.print(sound); Serial.print(F(" \t"));
        Serial.println(midi);
      }
    }

    size_t suche(char *ziel, const char *quelle, const char *textA, const char *textE) {
      char *ptr = strstr(quelle, textA) + strlen(textA);
      size_t laenge = strcspn(ptr, textE);
      strncpy(ziel, ptr, laenge);
      return laenge;
    }
    size_t suche_song(const char *quelle, const char *textA, const char *textE) {
      return suche(song, quelle, textA, textE);
    }
    size_t suche_part(const char *quelle, const char *textA, const char *textE) {
      return suche(part, quelle, textA, textE);
    }
    size_t suche_sound(const char *quelle, const char *textA, const char *textE) {
      return suche(sound, quelle, textA, textE);
    }
    size_t suche_midi(const char *quelle, const char *textA, const char *textE) {
      return suche(midi, quelle, textA, textE);
    }
    size_t strlen_song() {
      return strlen(song);
    }
    char *zeiger_song() {
      return song;
    }
};
Setlist liste[ROW_DIM];

/*
   Read a file one field at a time.
   file - File to read.
   str - Character array for the field.
   size - Size of str array.
   return - length of field including terminating delimiter.
*/
size_t readLine(File* file, char* str, size_t size) {
  char ch;
  size_t n = 0;
  while ((n + 1) < size && file->read(&ch, 1) == 1) {
    if (ch == '\r') {    // lösche Zeichen
      continue;
    }
    if (ch == '\n') {
      break;
    }
    str[n++] = ch;
  }
  str[n] = '\0';
  return n;
}

//------------------------------------------------------------------------------
#define errorHalt(msg) {Serial.println(F(msg)); SysCall::halt();}

void setup() {
  Serial.begin(9600);
  pinMode(pinSongVor, INPUT_PULLUP);
  debSongVor.attach(pinSongVor);
  debSongVor.interval(50);
  pinMode(pinSongZur, INPUT_PULLUP);
  debSongZur.attach(pinSongZur);
  debSongZur.interval(50);
  pinMode(pinVor, INPUT_PULLUP);
  debVor.attach(pinVor);
  debVor.interval(50);
  pinMode(pinZur, INPUT_PULLUP);
  debZur.attach(pinZur);
  debZur.interval(50);

  oled.begin();
  oled.clearBuffer();          // clear the internal memory
  oled.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
  oled.setCursor(0, 10); oled.print(F("Song"));
  oled.setCursor(0, 20); oled.print(F("Part"));
  oled.setCursor(0, 30); oled.print(F("Sounddescription"));
  oled.setCursor(0, 40); oled.print(F("Midicommand"));
  oled.sendBuffer();          // transfer internal memory to the display

  // Wait for USB Serial
  while (!Serial) {
    if (millis() > 3000) break;
  }
  Serial.println(F("Los geht's"));
  /*
    Serial.println(F("Type any character to start"));
    while (!Serial.available()) {
    SysCall::yield();
    }
  */
  // Initialize the SD.
  if (!SD.begin(CS_PIN)) {
    errorHalt("SD begin failed");
  }
  // Create or open the file.
  file = SD.open("setlist.xml", FILE_READ);
  if (!file) {
    errorHalt("SD open failed");
  }
  // Rewind the file for read.
  file.rewind();
  for (Setlist &s : liste) s.init();
  uint16_t zeile = 0;     // Strukturindex.
  char str[200];          // Längste Zeile

  // Read the file and store the data.
  while (zeile < ROW_DIM - 1) {
    if (!readLine(&file, str, sizeof(str))) break;
    if (strstr(str, "<setlist>") != NULL) {
      while (1) {
        if (!readLine(&file, str, sizeof(str))) break;
        if (strstr(str, "<song ") != NULL) {
          Setlist &s = liste[zeile];
          if (s.suche_song(str, "name=\"", "\"") > 1) {
            while (1) {
              if (!readLine(&file, str, sizeof(str))) break;
              if (strstr(str, "<part ") != NULL) {
                Setlist &s = liste[zeile];
                s.suche_part(str, "name=\"", "\"");
                s.suche_sound(str, "sounddescription=\"", "\"");
                if (s.suche_midi(str, "midicommand=\"", "\"") > 1) {
                  Setlist &q = liste[zeile - 1];
                  if (s.strlen_song() < 1) strncpy(s.zeiger_song(), q.zeiger_song(), MAXCOL);
                }
              }
              if (strstr(str, "</part>") != NULL) zeile++;
              if (strstr(str, "</song>") != NULL) break;
            }
          }
        }
        if (strstr(str, "</setlist>") != NULL)break;
      }
    }
  }

  Serial.println(F("\nFeld:"));
  for (uint16_t j = 0; j < ROW_DIM; j++) {
    Setlist &s = liste[j]; s.ausgabe(j);
  }
  Serial.println(F("Done"));
  file.close();
  delay(1000);
  Setlist &s = liste[0]; s.anzeige();
}
//------------------------------------------------------------------------------
void loop() {
  debSongVor.update();
  debSongZur.update();
  debVor.update();
  debZur.update();
  static uint16_t zeile = 0;
  if ( debVor.fell() ) {
    if (zeile < ROW_DIM) {
      Setlist &s = liste[zeile + 1];
      if (s.strlen_song() > 1) zeile++;
    }
    Setlist &a = liste[zeile];
    a.anzeige();
  }
  if ( debZur.fell() ) {
    if (zeile > 0) {
      Setlist &s = liste[zeile - 1];
      if (s.strlen_song() > 1) zeile--;
    }
    Setlist &a = liste[zeile];
    a.anzeige();
  }
  if ( debSongVor.fell() ) {
    uint16_t z = zeile;
    Setlist &s = liste[zeile];
    do {
      z++;
      Setlist &q = liste[z];
      if (q.strlen_song() > 1) {
        if (strncmp(s.zeiger_song(), q.zeiger_song(), MAXCOL) != 0) {
          zeile = z;
          break;
        }
      } else break;
    } while (z < ROW_DIM);
    Setlist &a = liste[zeile];
    a.anzeige();
  }
  if ( debSongZur.fell() ) {
    uint16_t z = zeile;
    Setlist &s = liste[zeile];
    while (z > 0) {
      z--;
      if (z == 0) {
        zeile = z;
        break;
      }
      Setlist &q = liste[z];
      if (strncmp(s.zeiger_song(), q.zeiger_song(), MAXCOL) != 0) {
        break;
      }
    }
    Setlist &t = liste[z];   // hier!
    while (z > 0) {
      z--;
      if (z == 0) {
        zeile = z;
        break;
      }
      Setlist &q = liste[z];
      if (strncmp(t.zeiger_song(), q.zeiger_song(), MAXCOL) != 0) {
        zeile = z + 1;
        break;
      }
    }
    Setlist &a = liste[zeile];
    a.anzeige();
  }
}
/* Daten in setlist.xml
  <setlist>
  <song name="The Lovesong">
    <part name="Intro" sounddescription="Clean/Delay" midicommand="xxx"></part>
    <part name="Strophe I" sounddescription="Clean/Chorus" midicommand="xxx"></part>
    <part name="Bridge" sounddescription="Light Crunch" midicommand="xxx"></part>
    <part name="Refrain I" sounddescription="Distortion" midicommand="xxx"></part>
    <part name="Strophe II" sounddescription="Clean/Chorus" midicommand="xxx"></part>
    <part name="Bridge" sounddescription="Light Crunch" midicommand="xxx"></part>
    <part name="Refrain II" sounddescription="Distortion" midicommand="xxx"></part>
    <part name="Solo" sounddescription="Lead Echo" midicommand="xxx"></part>
    <part name="Refrain III" sounddescription="Distortion" midicommand="xxx"></part>
    <part name="Outro" sounddescription="Clean/Delay" midicommand="xxx"></part>
  </song>
  <song name="The Rocksong">
    <part name="Intro" sounddescription="Distortion/Wah" midicommand="xxx"></part>
    <part name="Strophe I" sounddescription="Crunch" midicommand="xxx"></part>
    <part name="Refrain I" sounddescription="Distortion" midicommand="xxx"></part>
    <part name="Strophe II" sounddescription="Crunch" midicommand="xxx"></part>
    <part name="Refrain II" sounddescription="Distortion" midicommand="xxx"></part>
    <part name="Solo" sounddescription="Lead Echo" midicommand="xxx"></part>
    <part name="Refrain III" sounddescription="Distortion" midicommand="xxx"></part>
  </song>
  <song name="A Progsong">
    <part name="Strophe I" sounddescription="Clean/Chorus" midicommand="xxx"></part>
    <part name="Refrain I" sounddescription="Distortion" midicommand="xxx"></part>
    <part name="Strophe II" sounddescription="Clean/Chorus" midicommand="xxx"></part>
    <part name="Refrain II" sounddescription="Distortion" midicommand="xxx"></part>
    <part name="Mittelpart" sounddescription="Lead Echo" midicommand="xxx"></part>
    <part name="Refrain III" sounddescription="Distortion" midicommand="xxx"></part>
    <part name="Outro" sounddescription="Clean/Delay" midicommand="xxx"></part>
  </song>
  </setlist>
*/

Die Referenz ist ein Alias für etwas bestehendes.

Der kann man nichts zuweisen, die kann man nur benutzen, um etwas zu übergeben.
Meist in Hinblick auf die Übergabe einer Struktur/Klasse/Variable, um sie zu verändern.
Z.B. da, wo man früher (TM) Zeiger übergeben hat.

Gruß Tommy

Wo liegt mein Denkfehler,

Sagt die Meldung schon!

error: redeclaration of 'Setlist& s'
s ist schon vergeben.
Ein zweites s darfst/kannst du nicht im selben Geltungsbereich erzeugen.

error: lvalue required as left operand of assignment

Eine Referenz kann nicht neu zugewiesen werden sie, ist und bleibt ein Alias des Ursprünglichen.

Für solche Tricks, wie du sie offensichtlich planst, wären evtl. Zeiger das richtige.

Merke:

Setlist &s = liste[zeile];
Das ist keine Zuweisung, sondern eine Initialisierung

Beweis:

Setlist &s {liste[zeile]};

combie:
Für solche Tricks, ...

Den Typen, der mich zu

for (Setlist &s : liste) s.init(); verleitet hat, siehst Du morgens im Spiegel :slight_smile:

Ich habe das nur aufgedröselt. Und an anderer Stelle wurde mir nahegelegt, Referenzen anstelle von Zeigern zu nutzen. Wo ich gerade anfing, mich mit Referenzen anzufreunden, nun doch wieder Zeiger?

Das kommt immer darauf an, was Du machen willst.
Leider zeigt das Forum keine Zeilennummern an.
Da wäre ein genauerer Hinweis auf den Code sinnvoll.

Bei der For-Schleife wird immer ein neuer Alias angelegt. Du kannst ihn halt nicht umbiegen, wie einen Zeiger.

Gruß Tommy

Den Typen, der mich zu

Code: [Select]
for (Setlist &s : liste) s.init();
verleitet hat, siehst Du morgens im Spiegel :slight_smile:

Da wird bei jedem Durchlauf eine neue Referenz im neuen Geltungsbereich erzeugt.
Wie schon gesagt, das ist keine Zuweisung.
Und "erzeugt" ist auch nicht ganz das richtige Wort. denn eine solle Referenz benötigt keinen Speicher, im Gegensatz zu einem Pointer.

Ansonsten, würde ich den Typen erschlagen, der dir so einen Mist verkaufen will...

Ich habe das nur aufgedröselt.

Nein.
Du versuchst was zu machen, was nicht geht.

Wo ich gerade anfing, mich mit Referenzen anzufreunden, nun doch wieder Zeiger?

Naja, gut angewendete Zeiger sind seit Jahrzehnten gängige Praxis.
Ist doch besser, als wenn einen der Compiler anschreit, weil ...

Bisher habe ich den Zweck noch nicht kapiert.
Was willst du erreichen?
Irgenwo bist du scheinbar falsch abgebogen.
Habe leider bisher KA wo.

Tommy56:
Da wäre ein genauerer Hinweis auf den Code sinnvoll.

Klar doch, 17. Zeile von hinten, jetzt mit "hier" ergänzt.

Ich frage jetzt mal den Sandmann um Rat, danke schon mal für die Hinweise :slight_smile:

Stelle wurde mir nahegelegt, Referenzen anstelle von Zeigern zu nutzen.

Ich rate dir:
Wenn du die Wahl zwischen Zeiger und Referenz hast, dann nutze die Referenz.

Im Moment versuchst du die Vorteile der Referenzen mit den Nachteilen der Zeiger auszuhebeln/auszustatten
Das wird nicht gelingen.

Wenn du der C++ Sprachdefinition nicht glaubst, dann verwende eine Sprache, deren Definition du mehr Vertrauen entgegen bringst.

Tipp:
Weder die Referenz, noch der Bote der schlechten Nachricht ist böse, nur weil du die Doku nicht gelesen hast.

In #2 steht schon die Antwort und der Compiler hat mich mit den zitierten Meldungen zu einem funktionierenden Programm geführt.

Wenn es so ist, wie es ist, dann ist es halt so.

agmue:
der Compiler hat mich mit den zitierten Meldungen zu einem funktionierenden Programm geführt.

Hat er nicht.

Beides sind Errors.
Dort endet es abrupt.
Nix lauffähig.
Nada.
Nijet.

combie:
Hat er nicht.

Da hast Du nicht genau genug geschaut: Ich konnte alle Fehler und Warnungen beseitigen und das Programm in #0 tut, was es soll.

Meine Frage sollte lediglich der Verbesserung und dem damit einhergehenden Verständnis dienen.