PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C++: Zeiger Programmierung und Strukturen



Staind
28.01.2018, 20:04
Hallo,

bei meinem Projekt (https://www.roboternetz.de/community/threads/69561-Mein-neues-Projekt-Die-kleine-Mischerei) geht es langsam aber sicher in die Programmierphase...
Beruflich programmiere ich viel in der SPS Welt hauptsächlich in AWL. In der Techniker Schule habe ich C# kennengelernt und dort bin ich auch relativ fit drin.
Naja C++ ist zwar sehr ähnlich aber das sind die Programmiersprachen ja alle irgendwie. Nun geht es um die Zeigerprogrammierung. Dort hoffe ich das ganze verstanden zu haben, sicher bin ich aber nicht.
Daher wollte ich mal fragen ob ich das ganze so programmieren kann. Das Programm wird nachher auf ein Arduino laufen.
Ich habe auch schon viel im Internet gelesen, aber spezielle Fragen habe ich immer noch. Das Programm lässt sich auf jeden fall so kompilieren wie ich das jetzt hier im ersten Beispiel vorstelle.
Mir geht es darum ob ich das ganze so realisieren kann, oder ob es da zu Datenverlust kommen kann.

Fall 1:
Klasse.h


class Sortierer
{

////////////////////////////////////////
// Strukturen
public:
struct strKoordinate
{
byte x;
byte y;
};


struct strGrenzen
{
byte minimum;
byte maximum;
};


struct strFarbGrenzen
{
strGrenzen rot;
strGrenzen gruen;
strGrenzen blau;
};

struct strStellung
{
strKoordinate koordinate;
strFarbGrenzen farbe;
};

////////////////////////////////////////
// Variablen
private:
strStellung adressenStellung[SO_STELLUNGEN];
strStellung stellung[SO_STELLUNGEN];

////////////////////////////////////////
// Konstruktoren
public:
Sortierer(struct strStellung padressenStellung[SO_STELLUNGEN]);


////////////////////////////////////////
// Methoden
void setFarbGrenzen(byte pStellung, struct strFarbGrenzen *pFarbe);
struct strFarbGrenzen getFarbGrenzen(byte pStellung);

};
#endif // SORTIERER_H



Meine Frage zu diesem Teil. Kann ich die Strukturen so realisieren, also eine Struktur in eine Struktur und noch tiefer schachteln?

Klasse.cpp


#include "Sortierer.h"
#include <EEPROM.h>


////////////////////////////////////////
// Konstruktoren
Sortierer::Sortierer(struct Sortierer::strStellung padressenStellung[SO_STELLUNGEN])
{
for(int i = 0; i < SO_STELLUNGEN; ++i)
{
adressenStellung[i].koordinate = padressenStellung[i].koordinate;
adressenStellung[i].farbe = padressenStellung[i].farbe;
}
}


////////////////////////////////////////
// Methoden
void Sortierer::setFarbGrenzen(byte pStellung, struct Sortierer::strFarbGrenzen *pFarbe)
{
EEPROM.update(adressenStellung[pStellung].farbe.rot.minimum, pFarbe -> rot.minimum);
EEPROM.update(adressenStellung[pStellung].farbe.rot.maximum, pFarbe -> rot.maximum);
EEPROM.update(adressenStellung[pStellung].farbe.gruen.minimum, pFarbe -> gruen.minimum);
EEPROM.update(adressenStellung[pStellung].farbe.gruen.maximum, pFarbe -> gruen.maximum);
EEPROM.update(adressenStellung[pStellung].farbe.blau.minimum, pFarbe -> blau.minimum);
EEPROM.update(adressenStellung[pStellung].farbe.blau.maximum, pFarbe -> blau.maximum);
stellung[pStellung].farbe.rot = pFarbe -> rot;
stellung[pStellung].farbe.gruen = pFarbe -> gruen;
stellung[pStellung].farbe.blau = pFarbe -> blau;
}

struct Sortierer::strFarbGrenzen Sortierer::getFarbGrenzen(byte pStellung)
{
struct Sortierer::strFarbGrenzen pFarbe;
pFarbe = stellung[pStellung].farbe;
return pFarbe;
}



Hier die frage zum Zeiger. Der Übergabewert der Methode setFarbGrenzen ist ja ein Byte, und ein Zeiger der Struktur strFarbGrenzen.
In der Methode will ich ja die Werte von dem Zeiger abgreifen was ich ja mit pFarbe -> rot mache. Momentan kann ich so aber nur die Elemente der Struktur übergeben aber nicht die ganze Struktur.
Ist es möglich die ganze struktur zu übergeben. Also quasi:

stellung[pStellung].farbe = pFarbe;

pFarbe ist ja im diesen Fall die Zeigeradresse weswegen das so ja nicht geht. Gibt es irgendein Befehl um von der Zeigeradresse die ganze Struktur zu übergeben?

also so in der Art:

stellung[pStellung].farbe = pFarbe -> pFarbe;

oder kann ich nur die Strukturelemente einzeln übergeben wie in der Methode geschrieben:

stellung[pStellung].farbe.rot = pFarbe -> rot;
stellung[pStellung].farbe.gruen = pFarbe -> gruen;
stellung[pStellung].farbe.blau = pFarbe -> blau;

Dann noch eine Frage zu den Methoden einer Klasse:

Ist so etwas möglich?

struct Sortierer::strFarbGrenzen *Sortierer::getFarbGrenzen(byte pStellung)
{
struct Sortierer::strFarbGrenzen pFarbe;
pFarbe = stellung[pStellung].farbe;
return &pFarbe;
}

Also ich gebe ein Zeiger zurück von einer Variable / Struktur die in einer Methode erzeugt wird.
Wahrscheinlich nicht da die Variable nach dem Return nicht mehr existiert und der Zeiger somit ins leere zeigt.

Ich müsste wahrscheinlich die Variable in der Klasse.h erzeugen damit dieses funktioniert also quasi so:

struct Sortierer::strFarbGrenzen *Sortierer::getFarbGrenzen(byte pStellung)
{
farbe = stellung[pStellung].farbe; // farbe wird als private Variable in der Klasse erzeugt
return &farbe;
}

Hauptprogramm



...
Sortierer::strStellung fs_adressen[7] = {{1,2,3,4,5,6,7,8}, // EEPROM Adressen
{9,10,11,12,13,14,15,16},
{17,18,19,20,21,22,23,24},
{25,26,27,28,29,30,31,32},
{33,34,35,36,37,38,39,40},
{41,42,43,44,45,46,47,48},
{49,50,51,52,53,54,55,56}};


Sortierer fs_sortierer(fs_adressen); //Objekt erstellen
...
void loop() {
...
Sortierer::strFarbGrenzen fs_Grenzen = fs_sortierer.getFarbGrenzen(0); //Grenzen von Stellung 0
...
}



So und jetzt die Fragen was ist möglich in der Loopschleife.

Ich denke dieses hier sollte kein Problem sein:

Sortierer::strFarbGrenzen fs_Grenzen = fs_sortierer.getFarbGrenzen(0);

also der Rückgabewert (Struktur) der Methode wird nicht als Zeiger sondern als Struktur zurückgegeben.

Ich denke so etwas geht nicht oder:

Funktion(&fs_sortierer.getFarbGrenzen(0));

Also der Übergabewert der Funktion ist ein Zeiger auf den Rückgabewert der Methode.
Dies wird wahrscheinlich nicht Funktionieren, weil der Rückgabewert (die Struktur) nicht mehr bei dem Funktionsaufruf existiert und der Zeiger somit ins leere zeigt.
Ist dieses richtig?

Das Ganze müsste ich dann wahrscheinlich so lösen oder?

Sortierer::strFarbGrenzen fs_Grenzen = fs_sortierer.getFarbGrenzen(0);

Funktion(&fs_Grenzen);

Ich hoffe der Code ist nicht zu schwer zu lesen und ich weiß auch das es schwierig ist / Zeit braucht fremden Code zu verstehen.
Ich hoffe trotzdem das der ein oder andere sich Zeit nimmt und sich ein wenig rein denkt.
Schon einmal vielen Dank für die Antworten.

Gruß André

Mxt
29.01.2018, 08:53
Hallo,

ich beantworte mal einen Teil, im Moment habe ich wenig Zeit



Meine Frage zu diesem Teil. Kann ich die Strukturen so realisieren, also eine Struktur in eine Struktur und noch tiefer schachteln?

Kann man. Ist eigentlich nur eine Stilfrage. In C# wären verschachtelte Klassen schlechter Stil, in C++ ist Verschachteln etwas üblicher.



Ist es möglich die ganze struktur zu übergeben. Also quasi:

stellung[pStellung].farbe = pFarbe;

du meinst sicher

stellung[pStellung].farbe = *pFarbe;

Aber eigentlich ist die Verwendung von Zeigern dort falsch. Da würde man eher eine Referenz nehmen, das entspräche in etwa dem "ref" in C# bei Werttypen.

void Sortierer::setFarbGrenzen(byte stellung, strFarbGrenzen &farbe)
oder, wenn man das übergebene gar nicht verändern will, als konstante Referenz

void Sortierer::setFarbGrenzen(byte stellung, const strFarbGrenzen &farbe)
mit

stellung[pStellung].farbe = farbe;

Die Benennung deiner Parameter finde ich ziemlich fragwürdig

getFarbGrenzen(byte pStellung)
Mit p beginnende Parameternamen benutzt man sehr häufig um zu kennzeichnen, dass es sich um Zeigervariablen handelt (p wie Pointer), dass das jetzt hier anscheinend im Sinne von Parameter gebraucht wird, ist ziemlich verwirrend.

Außerdem sind die ganzen "struct" in den Funktionsparameterlisten absolut überflüssig.

Mxt
29.01.2018, 14:14
Ok, nächstes Stück



Ist so etwas möglich?

struct Sortierer::strFarbGrenzen *Sortierer::getFarbGrenzen(byte pStellung)
{
struct Sortierer::strFarbGrenzen pFarbe;
pFarbe = stellung[pStellung].farbe;
return &pFarbe;
}


Abgesehen von den vielen falschen struct, kommt es darauf an, was du haben willst.

Eine Kopie von stellung[pStellung].farbe wäre


Sortierer::strFarbGrenzen Sortierer::getFarbGrenzen(byte pStellung)
{
return stellung[pStellung].farbe;
}


Aber wahrscheinlich meinst du auch hier eher eine Referenz, über die du den Wert ändern willst


Sortierer::strFarbGrenzen& Sortierer::getFarbGrenzen(byte pStellung)
{
return stellung[pStellung].farbe;
}


Und wenn es wirklich ein Zeiger sein muss, wäre es



Sortierer::strFarbGrenzen* Sortierer::getFarbGrenzen(byte pStellung)
{
return &(stellung[pStellung].farbe);
}


Alle Beispiele haben das Problem, dass sie nicht prüfen ob pStellung einen gültigen Wert hat.