Guten Abend zusammen!
Mit normalen Arrays ist das kein Problem. Leider bekomme ich es nicht
mit zweidimensionalen hin. Bitte um Hilfe.
Der einzige Code, über den ich öfter gestolpert bin, ist dieser:
Danke. Aber leider funktioniert das nicht.
Die Konsole gibt mir jetzt die Anzahl der Reihen und Spalten aus.
Möchte aber die Anzahl der Elemente jeder Reihe. Also für dieses
Beispiel: row_0 = 4, row_1 = 3.
Gute Güte, jetzt quälst Du den TO auch noch mit einem Funktionstemplate
;-)
Dann mache es wenigstens noch constexpr und gibt ihm den Namen
size(...), damit man wenigstens etwas näher an die StdLibC++ heranrückt.
Da ich stark vermute, dass er mit avr-g++ arbeitet, und der keine
StdLibC++ mitbringt, darf man das auch ruhig in den Namensraum std
packen.
Und das dieses unsäglich byte für vorzeichenlose Ganzzahlen. Nimm doch
wenigstens uint8_t.
Tim schrieb:> Danke. Aber leider funktioniert das nicht.>> Die Konsole gibt mir jetzt die Anzahl der Reihen und Spalten aus.>> Möchte aber die Anzahl der Elemente jeder Reihe. Also für dieses> Beispiel: row_0 = 4, row_1 = 3.
Jedes Zeilen Array ist gleich lang.
Das hatten wir doch schon in dem anderen Beitrag von Dir. Nichts
gelernt?
Es wird immer der maximal nötige Speicherplatz belegt, anders kann der
Compiler nicht drauf zugreifen.
Wenn Du den Zugriff auf ungültige Elemente verhindern willst, geht das
z.B. über einen reservierten Wert (0, 0xFF, NAN).
Oder Du definierst eine Struct, wo zusätzlich die Länge mit abgelegt
wird (Array of Structs).
Wenn die Länge schon zur Compilezeit feststeht, geht auch ein Array von
Pointern auf Arrays. Kostet natürlich zusätzlichen Speicher für die
Pointerliste und etwas Laufzeit zum aufdröseln der Pointer.
Peter D. schrieb:> Wenn Du den Zugriff auf ungültige Elemente verhindern willst, geht das> z.B. über einen reservierten Wert (0, 0xFF, NAN).
Warum sollen 0x00 oder 0xff reservierte Werte bei einem Byte sein, wobei
der DT byte bei Arduino ja dasselbe wie uint8_t ist. Weder für byte noch
für uint8_t gibt es "ungültige" Werte. Dein Ratschlag ist so, wie man
das Jahr-2000-Problem vielerorten gelöst hat: einfach Mist.
Und NaN hat byte schon mal gar nicht. Das gibt es bei float oder double.
Auch Pointer-Typen (T*) haben einen definitiv ungültigen Wert: nullptr.
Alle anderen primitiven DT nicht.
Will man so etwas erreich, dann braucht man einen additiven DT wie etwa
std::optional<>.
Wilhelm M. schrieb:> Jedes Zeilen Array ist gleich lang.> Das hatten wir doch schon in dem anderen Beitrag von Dir. Nichts> gelernt?
Kann mich nicht erinnern, schon mal mit 2-D-Arrays gearbeitet zu haben
:D
Peter D. schrieb:> Es wird immer der maximal nötige Speicherplatz belegt, anders kann der> Compiler nicht drauf zugreifen.> Wenn Du den Zugriff auf ungültige Elemente verhindern willst, geht das> z.B. über einen reservierten Wert (0, 0xFF, NAN).> Oder Du definierst eine Struct, wo zusätzlich die Länge mit abgelegt> wird (Array of Structs).> Wenn die Länge schon zur Compilezeit feststeht, geht auch ein Array von> Pointern auf Arrays. Kostet natürlich zusätzlichen Speicher für die> Pointerliste und etwas Laufzeit zum aufdröseln der Pointer.
Ich möchte über eine Funktion alle Arrays über eine for-Schleife
ausgeben. Mit normalen Arrays klappt das auch wunderbar. Die Größe wird
dabei bequem über ein Makro ermittelt. Die Größe wird benötigt, damit
die Zählschleife weiß, wann sie fertig ist.
Tim schrieb:> Ich möchte über eine Funktion alle Arrays über eine for-Schleife> ausgeben. Mit normalen Arrays klappt das auch wunderbar. Die Größe wird> dabei bequem über ein Makro ermittelt. Die Größe wird benötigt, damit> die Zählschleife weiß, wann sie fertig ist.>
1
>#defineSIZEOF(arr)sizeof(arr)/sizeof(*arr)
2
>
3
>{OutputArray(Array,SIZEOF(Array));}
4
>
5
>voidOutputArray(byteArr[],byteArrSize)
6
>{
7
>for(bytei=0;i<ArrSize;i++)
8
>{
9
>//do something - Arr[i]
10
>}
11
>}
12
>
Hoffentlich weißt Du auch, dass man diese üble Größenberechnung nicht
innerhalb(!) einer Funktion durchführen darf.
Zudem: werden Deine Arrays nie größer als 256 Elemente?
Tim schrieb:> Wilhelm M. schrieb:>>> Jedes Zeilen Array ist gleich lang.>> Das hatten wir doch schon in dem anderen Beitrag von Dir. Nichts>> gelernt?>> Kann mich nicht erinnern, schon mal mit 2-D-Arrays gearbeitet zu haben> :D
Für mich sieht das
Beitrag "Mehrere Arrays in einer for-Schleife"
nach demselben Problem aus. Mag mich aber auch täuschen.
Wilhelm M. schrieb:> Hoffentlich weißt Du auch, dass man diese üble Größenberechnung nicht> innerhalb(!) einer Funktion durchführen darf.
Wie meinst du das und wieso? Es funktioniert.
> Zudem: werden Deine Arrays nie größer als 256 Elemente?
Das ist mir bewusst. Ich kenne auch die gängigen anderen Datentypen und
nutze byte, da ich weiß, dass ich an dieser Stelle nicht mehr benötige.
Wilhelm M. schrieb:> nach demselben Problem aus.
Dort ging es um normale Array, was ich auch gelöst hatte. Zudem hatte
ich mir das dort noch ganz anders vorgestellt.
Nun geht es um 2D-Arrays.
Tim schrieb:> Wilhelm M. schrieb:>> Hoffentlich weißt Du auch, dass man diese üble Größenberechnung nicht>> innerhalb(!) einer Funktion durchführen darf.>> Wie meinst du das und wieso? Es funktioniert.
Ja.
Aber nicht mehr, wenn Du die Größenberechnung mittels dieses dummen
Macros innerhalb der Funktion machst, und auf den zweiter Parameter der
Funktion verzichtest.
Denn der Array-Bezeichner an der Aufrufstelle zerfällt zu einem Zeiger
in der Funktion. Ein Zeiger-Typ bei AVR hat 16 Bit. Damit ist also die
Größe um den Faktor 2 falsch.
>>> Zudem: werden Deine Arrays nie größer als 256 Elemente?>> Das ist mir bewusst. Ich kenne auch die gängigen anderen Datentypen und> nutze byte, da ich weiß, dass ich an dieser Stelle nicht mehr benötige.
Na dann ... warten wir es ab ;-)
Tim schrieb:> byte Stunden[2][4] = {> {1, 2, 3, 4},> {5, 6, 7}> };
Wenn du ein mit 4 Elementen deklariertes Array nur mit 3 Werten
initialisierst, wird das Array deswegen nicht kleiner, sondern der nicht
explizit initialisierte Teil des Arrays wird implizit mit 0
initialisiert.
Dein Code ist somit äquivalent zu diesem:
Yalu X. schrieb:> Wenn du ein mit 4 Elementen deklariertes Array nur mit 3 Werten> initialisierst
Das ist bei eindimensionalen Array übrigens nicht anders:
1
intbla[4]={1,2,3};
Dieses Array enthält vier Elemente, auch wenn nur die ersten drei davon
initialisiert werden.
Wilhelm M. schrieb:> Na dann ... warten wir es ab ;-)
Im Praxistest hats geklappt.
Einen Teil der Arrays hatte ich in einer Switch-Case-Anweisung gepackt.
Nun wollte ich den Code "optimieren"/verkürzen, indem ich diesen Block
in ein 2D-Array packe, da man auf diese Weise, die Elemente(Reihen)
nacheinander ausgeben lassen könnte. Vielleicht ein Irrglaube. Was wäre
die Alternative?
Für jedes Arrayelement(Reihe) eine Variable deklarieren? Diese dann
vielleicht auch noch in einen Block packen, zwecks Durchnummerierung?!
Bspw.:
byte Stunden[2][4] = {
{1, 2, 3, 4},
{5, 6, 7}
};
byte row_size_0 = 4;
byte row_size_1 = 3;
Vielleicht erzählst du einfach was für ein Problem du lösen willst statt
immer nur nach der Lösung für ein Scheibchen deines angedachten
Lösungswegs zu fragen.
Udo S. schrieb:> Vielleicht erzählst du einfach was für ein Problem du lösen willst statt> immer nur nach der Lösung für ein Scheibchen deiner angedachten Lösung> zu fragen.
Es geht nicht um eine explizite Anwendung, sondern darum, eine Reihe von
2D-Array nacheinander ausgeben zu können. Vielleicht verfolge ich ja
auch den falschen Ansatz...
Es geht darum, wie beim Array, eine Reihe von Werten zu deklarieren -
53, 102, 162, diese vielleicht noch thematisch zusammenzufassen und
dann, nach Bedarf, abzurufen.
Wilhelm M. schrieb:> Warum sollen 0x00 oder 0xff reservierte Werte bei einem Byte sein
Oh Gott, das war doch nur als allgemeines Beispiel genannt. Natürlich
muß der Entwickler darauf achten, daß der reservierte Code nicht regulär
enthalten sein darf.
Und falls es um float Arrays geht, kann man da z.B. NAN oder INFINITY
zuweisen und testen.
Tim schrieb:> Vielleicht sollte ich noch erwähnen, dass ich Anfänger bin und keine> Profiambitionen habe.
Dann schildere dochmal das Problem und zeige nicht, was du dir als
Lösung vorstellst.
Peter D. schrieb:> Oh Gott, das war doch nur als allgemeines Beispiel genannt.
Du hast es leider nicht verstanden: uint8_t alias byte hat in seinem
Wertebereich keine "ungültigen" Werte.
Tim schrieb:> Für jedes Arrayelement(Reihe) eine Variable deklarieren? Diese dann> vielleicht auch noch in einen Block packen, zwecks Durchnummerierung?!> Bspw.:>> byte Stunden[2][4] = {> {1, 2, 3, 4},> {5, 6, 7}> };>> byte row_size_0 = 4;> byte row_size_1 = 3;
Das ist eine von vielen Möglichkeiten. Statt dir für die Größen jeweils
einen eigenen Variablennamen auszudenken, kannst du sie auch direkt im
Array Stunden unterbringen, bspw. so:
1
structrow{
2
bytesize;
3
byteelements[4];
4
};
5
6
rowStunden[]={
7
{4,{1,2,3,4}},
8
{3,{5,6,7}}
9
};
10
11
constbyteNROWS=(sizeofStunden/sizeofStunden[0]);
Dann kannst du folgendermaßen über die gewünschten Elemente von Stunden
iterieren:
1
for(bytei=0;i<NROWS;i++){
2
for(bytej=0;j<Stunden[i].size;j++)
3
do_something_with(Stunden[i].elements[j]);
4
}
Andere Möglichkeiten wurden in diesem und dem anderen Thread bereits
genannt, bspw. die Markierung des Endes jeder Reihe durch einen
speziellen Wert, den als normales Reihenelement nicht vorkommt.
Welche der vielfältigen Möglichkeiten die geeignetste ist, hängt vom
konkreten Anwendungsfall ab.
Tim schrieb:>> Dein Code ist somit äquivalent zu diesem:
Also ist das eigentlich Platzverschwendung, wenn man kürzere Arrays
verwendet, als angegeben?! Wenn ich aber eine Liste von
Zusammengefassten Werten, die der Reihe nach abgerufen werden sollen,
möchte, ist es ein notwendiges Übel?
Oder ist das einfach nicht relevant?
Wilhelm M. schrieb:> Du hast es leider nicht verstanden: uint8_t alias byte hat in seinem> Wertebereich keine "ungültigen" Werte.
Hat ja auch niemand behauptet.
Nochmal:
"Natürlich muß der Entwickler darauf achten, daß der reservierte Code
nicht regulär enthalten sein darf."
Wenn aber der gesamte Wertebereich erlaubt sein soll, muß man es eben
als struct mit extra Längenelement definieren.
Das sieht sehr gut aus! Zumindest durch meine bescheidenen Augen
betrachtet :D Arraystructs sind mir bekannt und verstehe diese. Habe
damit aber tatsächlich noch nicht wirklich gearbeitet. Werde ich später
mal ausführlich testen. Derzeit hatten mich Arrays sehr begeistert, da
ich darin viele Möglichkeiten sehen. Was soll ich sagen, bin halt noch
ein noob.
Vielen Dank!
Peter D. schrieb:> Hat ja auch niemand behauptet.> Nochmal:> "Natürlich muß der Entwickler darauf achten, daß der reservierte Code> nicht regulär enthalten sein darf."
Nochmal: wenn ich ein Objekt vom DT byte oder uint8_t habe, wie sehe ich
ihm allgemein(!) an, dass es ungültig sein soll? Das ist nicht möglich,
weil diese DT das einfach nicht hergeben. Damit ist es dann unmöglich,
guten Code zu schreiben, der allgemeingültig ist, etwa als Rückgabewert
oder auch als Argument einer Funktion. Entweder hat der DT in seinem
Wertebereich einen ungültigen Wert, der das "Nichts" ausdrückt, wie etwa
Zeigertypen oder andere UDT, oder man verwendet dafür einen additiven
DT, wie std::optional<>.
Tim schrieb:> Wenn ich aber eine Liste von> Zusammengefassten Werten, die der Reihe nach abgerufen werden sollen,> möchte, ist es ein notwendiges Übel?
Nö. Kann man auch anders machen, aber die Längeninformation muss man
halt separat transportieren.
1
structkrempel
2
{
3
intlen;
4
int*data;
5
};
6
7
intx0[]={1,3,5,7};
8
intx1[]={1};
9
intx2[]={2,7,56,12,1,78};
10
intx3[]={2,3,4};
11
12
structkrempely[]=
13
{
14
{sizeof(x0)/sizeof(x0[0]),x0},
15
{sizeof(x1)/sizeof(x1[0]),x1},
16
{sizeof(x2)/sizeof(x2[0]),x2},
17
{sizeof(x3)/sizeof(x3[0]),x3},
18
};
Das entspricht dem Beispiel von yalu, mit dem Unterschied, daß für jedes
Teilarray wirklich nur soviel Platz verwendet wird, wie benötigt wird.
Achte bei der Definition auf die leeren eckigen Klammern! In diesem
Fall, der nur bei einer Dimension von Array angewandt werden kann,
bestimmt der Compiler die Arraygröße aus der Größe des Initialisierers.
In der Hilfsstruktur (struct krempel) ist die Anzahl der Arrayelemente
und ein Pointer auf das Array abgelegt, und das Array y besteht --wie
bei yalu-- aus mehreren dieser Hilfsstrukturen.
Bei dieser Vorgehensweise aber ist es nicht vermeidbar, die einzelnen
Arrays mit jeweils einem Variablennamen (x0 .. x3) anzulegen.
Harald K. schrieb:> In der Hilfsstruktur (struct krempel) ist die Anzahl der Arrayelemente> und ein Pointer auf das Array abgelegt, und das Array y besteht --wie> bei yalu-- aus mehreren dieser Hilfsstrukturen.
Dann wird der TO sicher noch Zeiger auf Stack-Objekte dort ablegen, und
sich wundern, warum es nicht funktioniert.
Leute, der TO verwendet C++. Ihr bringe ihm gerade C bei.
Gibt es denn in diesem tollen Arduino-Zeug nicht auch so etwas wie einen
FixedVector<>, den man ggf. aus FixedVector<byte, 10> verwenden kann.
Also ein Array mit maximal 10 Elementen.
Harald K. schrieb:> {sizeof (x0) / sizeof (x0[0]), x0}
Was spricht, in diesem Fall, gegen meine Variante?
> #define SIZEOF(arr) sizeof(arr) / sizeof(*arr)>> {OutputArray(Array, SIZEOF(Array));}
Ist das nicht sehr ähnlich?!
Wilhelm M. schrieb:> Gute Güte, jetzt quälst Du den TO auch noch mit einem Funktionstemplate> ;-)
Seit C++17 ist das auch schon in der Standardbibliothek mitgeliefert:
https://en.cppreference.com/w/cpp/iterator/size Overload 3
Man kann also einfach std::size(Stunden) schreiben. Aber das ist jetzt
hier natürlich nicht die Frage vom OP, vermeidet nur lediglich dieses
hässliche ROW_SIZE Makro. Und fehlersicherer ist es auch, denn wenn man
versehentlich nur einen Pointer übergibt, meckert der Compiler, anstatt
einfach was falsches zurückzugeben.
Wilhelm M. schrieb:> Gibt es denn in diesem tollen Arduino-Zeug nicht auch so etwas wie einen> FixedVector<>, den man ggf. aus FixedVector<byte, 10> verwenden kann.> Also ein Array mit maximal 10 Elementen.
Bitte was? :D
Tim schrieb:> Wilhelm M. schrieb:>> Gibt es denn in diesem tollen Arduino-Zeug nicht auch so etwas wie einen>> FixedVector<>, den man ggf. aus FixedVector<byte, 10> verwenden kann.>> Also ein Array mit maximal 10 Elementen.>> Bitte was? :D
Ist das AVR-Arduino? Also avr-g++? Oder etwa auf ARM (mit newlib)?
Tim schrieb:> Wilhelm M. schrieb:>> Gibt es denn in diesem tollen Arduino-Zeug nicht auch so etwas wie einen>> FixedVector<>, den man ggf. aus FixedVector<byte, 10> verwenden kann.>> Also ein Array mit maximal 10 Elementen.>> Bitte was? :D
Besorge Dir ein C++-Buch oder mach einen Online-Kurs.
Wilhelm M. schrieb:> Leute, der TO verwendet C++. Ihr bringe ihm gerade C bei.
C-Grundlagenwissen ist nicht verkehrt, um zu verstehen, was einem ein
C++-Compiler an Arbeit abnimmt (und möglicherweise an Komplexität
draufschaufelt) - wenn man im Embedded-Bereich unterwegs ist, kann es
längerfristig besser sein, zu wissen, woraus die bunten Bauklötze sind,
statt sie nur zusammendrücken zu können.
Die teilweise sehr akademischen Diskussionen, die hier in letzter Zeit
von einigen Protagonisten geführt wurden, sind jedenfalls auch nicht
hilfreich.
Wilhelm M. schrieb:> Tim schrieb:>> Wilhelm M. schrieb:>>> Gibt es denn in diesem tollen Arduino-Zeug nicht auch so etwas wie einen>>> FixedVector<>, den man ggf. aus FixedVector<byte, 10> verwenden kann.>>> Also ein Array mit maximal 10 Elementen.>>>> Bitte was? :D>> Besorge Dir ein C++-Buch oder mach einen Online-Kurs.
Der Datentyp FixedVector gibt es IMHO weder in der C++-Standard- noch in
der Arduino-Bibliothek, weswegen man ihn auch in keinem C++-Buch finden
wird.
Natürlich kann man diesen Typ selber schreiben. Er entspräche dann in
etwa diesem Typ
Yalu X. schrieb:> struct row {> byte size;> byte elements[4];> };
nur mit dem Unterschied, dass die Maximalgröße als Template-Argument
übergeben wird, der Zugriff auf die Elemente direkt mit dem []-Operator
erfolgt kann und size automatisch aus der Initialiererliste bestimmt
wird.
Um das zu tun (oder auch nur zu verstehen), sind aber Kenntnisse über
- Templates,
- Operatorüberladung und
- Initialisiererlisten
erforderlich, die der TE, der sich selbst als "Noob" bezeichnet,
definitiv (noch) nicht hat.
Deswegen sollten wir erst einmal versuchen, sein Problem mit den
Sprachelementen zu lösen, die er aus seiner Arduino-Praxis schon kennt.
Den von dir vorgeschlagenen FixedVector kann man danach Schritt für
Schritt darauf aufbauen.
Trotzdem ist es natürlich für einen Arduino-Programmierer kein Fehler,
ein C++-Buch durchzuarbeiten. Konkrete Vorschläge dafür habe ich leider
nicht, Mein letztes C++-Buch ist das von Breymann, wobei das schon ein
ziemlicher Schinken ist. Wie es sich im Vergleich zu anderen Büchern
schlägt, kann ich nicht sagen.
Tim schrieb:> Es geht nicht um eine explizite Anwendung, sondern darum, eine Reihe von> 2D-Array nacheinander ausgeben zu können.
Suchst du sowas? Wenn ja machste dir daraus eine Funktion.
Tim schrieb:> Die Konsole gibt mir jetzt die Anzahl der Reihen und Spalten aus.
So soll es auch sein!
Tim schrieb:> Möchte aber die Anzahl der Elemente jeder Reihe. Also für dieses> Beispiel: row_0 = 4, row_1 = 3.
Wie soll das möglich sein?
Solche Arrays sind "rechteckig"!
Haben keine zackeligen Ränder.
> byte Stunden[2][4]
Ein solches Array hat exakt 2*4=8 Zellen. Das ist genau die Zellenzahl
die du erzwungen hast. Völlig unabhängig davon, was du dir wünscht oder
was sich in deiner Fantasie abspielt.
Tim schrieb:>> Besorge Dir ein C++-Buch oder mach einen Online-Kurs.> Kannst du da was empfehlen?
z.B. dieses: http://www.cppbuch.de/
Veraltete Versionen gibts gerade deutlich billiger.
Warnung: Arduino wird da drin mit keinem Wort erwähnt.
Yalu X. schrieb:> Der Datentyp FixedVector gibt es IMHO weder in der C++-Standard- noch in> der Arduino-Bibliothek, weswegen man ihn auch in keinem C++-Buch finden> wird.
Deswegen habe ich auch Arduino-Zeug geschrieben und nicht StdCppLib.
Denn es gibt ja hier Leute, die sehr "stolz" auf Arduino sind, und ich
hätte es für möglich gehalten, dass es da so etwas gibt. Das macht
nämlich Sinn! So wie auch ein std::array<> (ohne std ;-).
Yalu X. schrieb:> Um das zu tun (oder auch nur zu verstehen), sind aber Kenntnisse über>> - Templates,>> - Operatorüberladung und>> - Initialisiererlisten>> erforderlich, die der TE, der sich selbst als "Noob" bezeichnet,> definitiv (noch) nicht hat.
Sinnerfassendes Lesen ist schon wichtig: er soll das nicht selbst
schreiben, sondern nur benutzen, so wie er den restlichen Arduino-Kram
auch einfach nur benutzt. Ich vermute, er wird auch Serial und String
benutzen.
Wilhelm M. schrieb:> die sehr "stolz"
Und du bist ein Nörgler, der zwar die Fähigkeit hat, die Ursache des
Nörgelns zu beseitigen, aber nicht daran interessiert ist.
Also sowas, wie ein Windbeutel, mit einer mentalen Deformation.
Oder auch: Der typische Arduino Basher.
Wilhelm M. schrieb:> Sinnerfassendes Lesen ist schon wichtig: er soll das nicht selbst> schreiben, sondern nur benutzen
Es gibt eine Sache, die noch schwieriger ist als Code zu schreiben:
Ihn zu benutzen, solange er noch gar nicht existiert ;-)
Veit D. schrieb:> Wenn ja machste dir daraus eine Funktion.
Das wäre dann ein Funktionstemplate. Und ich denke, das ist noch
außerhalb seines Horizonts;
Harald K. schrieb:> Die teilweise sehr akademischen Diskussionen, die hier in letzter Zeit> von einigen Protagonisten geführt wurden, sind jedenfalls auch nicht> hilfreich.
Damit meinst Du ja mich ;-)
Sicher: Programmieren hat etwas mit Informatik zu tun, und das wiederum
mit Mathematik, und das ist letztendlich akademisch.
Yalu X. schrieb:> Es gibt eine Sache, die noch schwieriger ist als Code zu schreiben:> Ihn zu benutzen, solange er noch gar nicht existiert ;-)
Wirklich ;-)
Nun ja, es gibt doch hunderte, wenn nicht x-tausende von Bibliotheken
für Arduino. Ist da wirklich keine darunter, die so etwas wie ein
FixedVektor<> anbietet?
Harald K. schrieb:> Veit D. schrieb:>> Suchst du sowas?>> Nee. Das genau sucht er nicht.
Dann funktioniert das was Tim eigentlich will mit Mehrdimensionalen
Arrays nicht. Das was Tim möchte funktioniert nur mit EIN-Dimensionalen
Arrays. Das ist die aktuelle Situation. Nur dann muss man sich keine
komplizierten durch die Brust ins Auge Lösungen ausdenken, denn die
Anzahl der Elemente ist zur Compiletime bekannt. Genau das deckt
Range-based for loop ab.
Wilhelm M. schrieb:> Nochmal: wenn ich ein Objekt vom DT byte oder uint8_t habe, wie sehe ich> ihm allgemein(!) an, dass es ungültig sein soll?
Man kann natürlich alles super eng sehen und alles auf die Goldwaage
legen, aber man muß nicht.
Ich nehme sehr gern einen Leerstring oder Nullpointer als
Endekennzeichen eines Arrays oder einer Liste. Rein formal sind das
natürlich gültige Einträge. Ihre Sonderbedeutung erhalten sie durch den
Kontext.
Das vermeidet Schusselfehler, wenn ich stattdessen die Länge extra mit
übergeben würde und sich nachträglich die Länge ändert. Oft fügt man
Elemente später hinzu oder löscht welche.
Auch kann man Werten außerhalb des Nutzungsbereiches eine
Sonderbedeutung geben, z.B. in meinem Scheduler:
Peter D. schrieb:> Ich nehme sehr gern einen Leerstring oder Nullpointer als> Endekennzeichen eines Arrays oder einer Liste.
Was soll das denn sein? Einen Leerstring als sentinel? Für ein
Array-of-byte? Oder noch schlimmer, einen nullptr.
Du meinst wahrscheinlich das Stringendezeichen '\0' als sentinel in
einem Array von char bzw. byte. Das ist die Konvention (!) für
C-Strings. Kannst Du aber nicht in einem Array von byte anwenden, wenn
das numerische Bedeutung (wie bei Arduino als uint8_t) hat.
nullptr oder (void*)0 (aka NULL in C) passt doch vom Dt nur in eine
Array von Pointern. Und ja, genau das habe ich doch geschrieben: Pointer
DT wie T* haben einen ungültigen Wert, hier nullptr aka NULL in C
Ich sehe schon, Du willst mich absichtlich nicht verstehen. Es waren
wieder nur praktische Beispiele, wie gültige Werte eine Sonderbedeutung
erhalten können. Diese Beispiele waren nicht konkret auf den Typ "byte"
bezogen (hab ich auch noch nie verwendet).
Wilhelm M. schrieb:> Du meinst wahrscheinlich das Stringendezeichen '\0' als sentinel in> einem Array von char bzw. byte. Das ist die Konvention (!) für> C-Strings. Kannst Du aber nicht in einem Array von byte anwenden, wenn> das numerische Bedeutung (wie bei Arduino als uint8_t) hat.
Das geht schon, wenn man man bereit ist, ein einzelnes Element des
Wertebereichs für das Vorhaben zu opfern. Ob und für welches Element
dies möglich ist, hängt von der Anwendung ab. Gerade bei der
Interpretation von byte bzw. uint8_t als Zahlenwert wird der
Wertebereich oft nicht voll ausgeschöpft, so dass entweder 255 oder 0
problemlos als Endemarkierung verwendet werden kann.
Bei den C-Strings wurde ähnlich verfahren: Eigentlich sollten darin
mindestens alle ASCII erlaubt sein. Da aber das ASCII-Zeichen NUL nur
selten verwendet wird, hat man sich dafür entschieden, dieses dem
zulässigen Wertebereich zu entnehmen und ihm stattdessen die Bedeutung
als Endezeichen zukommen zu lassen.
Entsprechendes gilt auch für den NULL-Pointer als Endemarkierung.
Veit D. schrieb:> Dann funktioniert das was Tim eigentlich will mit Mehrdimensionalen> Arrays nicht.
Funktionieren tut es schon.
Man könnte sich vorstellen:
[¢]
template<size_t... L>
struct RowLengths;
template<typename RowLengths>
struct Fluttering { ... };
[/c]
Oder wenn nur eine begrenzte Anzahl von verschiedenen Zeilenlängen
vorkommt:
Nur: der TO wird es nicht erstellen können bzw. Arduino stellt es nicht
zur Verfügung bzw. die StdLibC++ ist für avr-g++ nicht vorhanden und
std::variant<> und std::array<> wird er auch nicht schreiben können.
Gäbe es das oben vorgeschlagene FixedVector<> sähe das schon besser aus.
Wobei natürlich dabei Speicher "verschwendet" wird.
Yalu X. schrieb:> Das geht schon, wenn man man bereit ist, ein einzelnes Element des> Wertebereichs für das Vorhaben zu opfern. Ob und für welches Element> dies möglich ist, hängt von der Anwendung ab. Gerade bei der> Interpretation von byte bzw. uint8_t als Zahlenwert wird der> Wertebereich oft nicht voll ausgeschöpft, so dass entweder 255 oder 0> problemlos als Endemarkierung verwendet werden kann.
Das ist doch jetzt echt nicht Dein Ernst. Das ist wie im letzten
Jahrtausend, sorry. Und so etwas gibst Du einem Anfänger mir.
Fahrlässig.
Die durch C-Strings motivierte Ausnahme mit '\0' als Sentinel ist schon
schlimm genug. Sie wäre nur dann gerechtfertigt, wenn der DT char
definitiv nur für (ASCII)-Zeichen reserviert wäre. Aber er ist ein
normaler arithmetischer Typ. Deswegen ist auch das großer Mist.
Zeiger-Typen sind die einzigen primitiven DT, die einen ungültigen Wert
in ihrem Wertebereich haben. Und die Verwendung (Indirektion) für
definitiv zu einem Programmabbruch (eingebaute "Assertion"). Das ist gut
so.
In C++ schreibt man sich dafür einen kleinen UDT, der genau das zum
Ausdruck bringt, was man will. Von mir aus mit 255 als interne Codierung
für den ungültigen Wert. Aber dann bitte mit einer Assertion bei der
Initialisierung und einem Typumwandlungsoperator nach bool.
Wilhelm M. schrieb:> Zeiger-Typen sind die einzigen primitiven DT, die einen ungültigen Wert> in ihrem Wertebereich haben.
Ich hatte mal ein 8051 Programm, was sich merkwürdig verhielt. Beim
Debuggen bin ich dann an eine Stelle gekommen, wo ein Pointer auf 0
geprüft wurde. Nun hat der 8051 aber Harward-Architektur, d.h. die XDATA
Adresse 0x0000 ist gültiger SRAM, die dann der Linker auch brav einer
Struct zugewiesen hat.
Ich hab dann per Linkeroption den XDATA an Adresse 0x0001 definiert und
es lief einwandfrei.
Moin,
Peter D. schrieb:> Ich hab dann per Linkeroption den XDATA an Adresse 0x0001 definiert und> es lief einwandfrei.
Vor meinem inneren Auge sehe ich hier schon einige Teilnehmer sich vor
Entsetzen und Schmerz ueber diesen Frevel in ihrem eigenen Erbrochenen
waelzen ;-)
scnr,
WK
Peter D. schrieb:> Ich hatte mal ein 8051 Programm, was sich merkwürdig verhielt.
Dann hattest Du einfach einen fehlerhaften Compiler. Denn nullptr bzw.
NULL ist der definitiv ungültige Zeiger. In Deinem Fall wäre ggf.
(void*)1 richtig gewesen. Beschwere Dich beim Compiler-Hersteller /
Projekt.
Dergute W. schrieb:> Vor meinem inneren Auge sehe ich hier schon einige Teilnehmer sich vor> Entsetzen und Schmerz ueber diesen Frevel in ihrem eigenen Erbrochenen> waelzen ;-)
Wen meinst Du denn noch außer mir? Wobei ich mich nicht angesprochen
fühle. Womit Ihr auf die Schnauze fallt, ist mir egal ;-)
Wilhelm M. schrieb:> Veit D. schrieb:>> Dann funktioniert das was Tim eigentlich will mit Mehrdimensionalen>> Arrays nicht.>> Funktionieren tut es schon.
Hallo Wilhelm,
wenn sein 2D Array mit der Anzahl von 5 Elementen definiert ist je
Zeile, er aber nur 3 Werte reinschreibt zur Initialisierung, dann möchte
er auch nur diese 3 Werte auslesen und nicht 5. Das sehe ich bei dir
nicht. Und das geht auch ohne Trickserei nicht.
Veit D. schrieb:> Wilhelm M. schrieb:>> Veit D. schrieb:>>> Dann funktioniert das was Tim eigentlich will mit Mehrdimensionalen>>> Arrays nicht.>>>> Funktionieren tut es schon.>> Hallo Wilhelm,>> wenn sein 2D Array mit der Anzahl von 5 Elementen definiert ist je> Zeile, er aber nur 3 Werte reinschreibt zur Initialisierung, dann möchte> er auch nur diese 3 Werte auslesen und nicht 5. Das sehe ich bei dir> nicht. Und das geht auch ohne Trickserei nicht.
Welchen meiner Vorschläge meinst Du?
Hallo Wilhelm,
okay, wir drehen das jetzt rum. Zeige bitte dein Programm für den
Desktop PC mit Ausgabe, da haben alle die StdLibC++. Bin gespannt ob das
den Vorgaben vom TO entspricht.
Veit D. schrieb:> Hallo Wilhelm,>> okay, wir drehen das jetzt rum. Zeige bitte dein Programm für den> Desktop PC mit Ausgabe, da haben alle die StdLibC++. Bin gespannt ob das> den Vorgaben vom TO entspricht.
Für ein System mit voller Unterstützung der StdLibC++?
Auf die Schnelle würde ich das vermutlich so machen:
Wie schon vorgeschlagen, könnte man, wenn man z.B. auf Head-Allocation
verzichten möchte, sich ein Klassen-Template
1
template<typenameT,size_tSize=10>
2
structFixedVector{
3
// ...
4
};
was man statt std::vector<> einsetzen könnte:
1
FixedVector<FixedVector<int>>vv{{
2
{1},
3
{2,3},
4
{4,5,6}
5
}};
Wie oben auch schon gesagt, hat das natürlich den Nachteil der
"Speicherverschwendung".
Wenn man das auch nicht möchte und ggf. bereit ist, Speicherverbrauch
gegen Laufzeit einzutauschen, dann wäre auch das möglich (s.a. oben
Fluttering).
Bevor jetzt alle wieder aufschreien: dieser Beitrag war nicht an den TO
gerichtet! Für den TO hätte ich mir nach wie vor ein FixedVector o.ä.
aud irgendeiner Arduino-Lib gewünscht.
Hallo,
Danke für die Demo. Ich habe das natürlich ausprobiert. Eine Frage
bleibt. Woher kommt die Ausgabe der Allerersten und Allerletzten
Klammer?
Kommentiere ich
std::cout << '{';
std::cout << '}';
aus werden gar keine Klammern ausgegeben.
Wenn ich den Code lese erwarte ich eigentlich das:
{1}, {2, 3}, {4, 5, 6}
und nicht:
{{1}, {2, 3}, {4, 5, 6}}
Wo liegt der Zauber der Allerersten und Allerletzten Klammer?
Veit D. schrieb:> Hallo,>> Danke für die Demo. Ich habe das natürlich ausprobiert. Eine Frage> bleibt. Woher kommt die Ausgabe der Allerersten und Allerletzten> Klammer?>> Kommentiere ich> std::cout << '{';> std::cout << '}';> aus werden gar keine Klammern ausgegeben.
Der op<< wird ja rekursiv verwendet. Er macht immer "außen" um alle
Elemente der Containers die Klammern.
Veit D. schrieb:> Hallo Wilhelm,>> okay, wir drehen das jetzt rum. Zeige bitte dein Programm für den> Desktop PC mit Ausgabe, da haben alle die StdLibC++. Bin gespannt ob das> den Vorgaben vom TO entspricht.
Hatte es, von Yalu X., gerade ins Programm eingesetzt und werde es
später testen. Sieht aber erst einmal gut aus.
Bin gespannt :)