Hallo Gemeinde
Kann ich in C ein mehrdimensionales Feld definieren, in dem zB die
Zeilen verschiedene Längen haben ?
Beispiel
Feld(x,y)
xxxxxxxxxxxxxxxxxx
xxxxxxxxx
xxxx
xxxxxxxxxxxxxx
xxxxxx
Habe die Aufgabe im Augenblick mit einer Struktur gelöst, wo das ja kein
Problem ist.
Um den Quellcode klein zu halten, würde ich die Funktion, die die Zeilen
mit Daten füllen, aber gerne nacheinander mit einer Schleife abarbeiten.
Das geht bei einer Struktur doch nicht, oder ???
Klar könnte ich ein xy-Feld bestimmen, in dem alle Zeilen die maximal
vorkommende Länge haben, aber das finde ich stumpf.
Danke
Torsten
Torsten B. schrieb:> Klar könnte ich ein xy-Feld bestimmen, in dem alle Zeilen die maximal> vorkommende Länge haben, aber das finde ich stumpf.
Bei einem Feld geht's nicht anders.
Torsten B. schrieb:> Um den Quellcode klein zu halten, würde ich die Funktion, die die Zeilen> mit Daten füllen, aber gerne nacheinander mit einer Schleife abarbeiten.
Die Länge jedes einzelnen Teiles müsstest du ja trotzdem irgenwo
herholen.
Für kurzen Code (braucht aber mehr RAM) könnte man vielleicht sowas
machen:
Zusätzlich in deine Struktur ein Feld von Pointern auf die 'Zeilen',
evtl. kombiniert mit der Zeilenlänge. Dann kannst du das in einer
Schleife abarbeiten (entweder über Index, oder NULL-Pointer als
Endekennzeichen).
Man müsste mal mehr sehen um was es eigentlich geht. Wenn es eine
Struktur ist liegt es eigentlich nahe, daß die Daten unterschiedlicher
Art sind. Dann macht es keinen Sinn in einer Schleife
umzukopieren/befüllen.
Wenn alles Strings sind, ist es vieleicht einfacher ein Array von
Stringpointern zu benutzen und nicht zu kopieren sondern nur die Zeiger
zu setzen.
Torsten B. schrieb:> Um den Quellcode klein zu halten,
Ist nicht immer die beste Lösung. Meist geht das einher mit Tricks die
man nach einem Jahr selbst nicht mehr versteht.
Udo Schmitt schrieb:> Man müsste mal mehr sehen um was es eigentlich geht.
Das wird er sicher gleich verraten. In der vorliegenden Form sehe ich da
auch keinen Sinn. Aber vielleicht werden die Daten von irgendwoher erst
empfangen.
Udo Schmitt schrieb:> Torsten B. schrieb:>> Um den Quellcode klein zu halten,> Ist nicht immer die beste Lösung. Meist geht das einher mit Tricks die> man nach einem Jahr selbst nicht mehr versteht.
sowas dann:
Martin Wende schrieb:> Musst dann nur höllisch aufpassen, dasse nicht bei nem Zeilenarray> daneben greifst.
:-)
Ich bastel mal wieder an einem NMEA Parser, der ohne strsep & Co
auskommt, da ich damit immer Probleme hatte. Dachte ich zumindest ...
Probleme in der Hauptanwendung sind jetzt auch mit diesem nicht weg,
aber jetzt weiß ich wenigstens, dass es nicht daran gelegen hat ;-)
Die Anwendung ist:
GPS Daten vom Modul empfangen und über RF12 zu einem anderen uC senden.
Übeltäter ist aber die Empfangsfuktion.
Hab den neuen Parser mal angehängt.
Hier sieht man, dass ich sehr oft das gleiche mache. Eben bis auf die
Angabe der Strukturfelder.
Wollte eben eine Struktur verwenden, da man die sehr schön (bei einer
späteren LCD Ausgabe angeben kann.
2D char Array würde hier auch gehen.
Der Code ist zum Zerreißen freigegeben... gehts besser ?
Grüße
Torsten
Ist so doch viel besser. Überlege dir, statt Bla.Longitude hättest du
Bla[4]
Super selbsterklärend oder?
Was mir an deiner Funktion ParsGPGGA() auffällt, wenn du statt void ein
int zurückgibst könntest du damit dem Aufrufer Fehlerfreiheit oder nicht
signalisieren. Was machst du z.B. wenn ein Datensatz nicht vollständig
ist?
Hier
while (*GPGGA_Ptr != ',')
solltest du zusätzlich überall prüfen ob du nicht schon am Stringende
bist (Erkennen eines unvollständigen Datensatzes oder eines fehlerhaften
wo ein Komma fehlt) Auch in dem Fall einen Fehler returnen.
Um es noch sicherer zu machen solltest du auch alle Laufvariablen i
überprüfen dass sie (bei einem fehlenden Komma) nicht über das jeweilige
Ende des Strings in der Struktur rausschreiben.
Dein main ist etwas strange, aber ist wohl nur zum debuggen so.
Was ebenfalls funktioniert ist, du legst eine Struktur mit dem attribut
PACKED (unterschiedlich von Compiler zu Compiler) über die gesamte
Datenstruktur... Dann müsstest Du nur zwischendrin Füllbytes für die
Kommatas haben....
Also wenn Deine Daten so im Speicher stehen:
char data[12] = "AAAAA,BB,CCC"
dann
struct sData {
char A[5];
char delimiter1;
char B[2];
char delimiter2;
char C[3];
} PACKED
Später:
sData my_test;
my_test = data; entweder im gleichen Speicher auslesen oder
eben mit z.B. memcpy kopieren....
Man könnte auch beim Parsen alle Kommas einfach durch 0 Bytes ersetzen
und nur die Zeiger auf die entsprechenden Speicherstellen in das Struct
schreiben.
Aber Vorsicht, wenn man den Speicher dann mit einem neuen Datensatz
überschreibt ist das Struct vor dem erneuten parsen nicht mehr gültig.
Torsten B. schrieb:> Der Code ist zum Zerreißen freigegeben... gehts besser ?
Nehmen wir mal an, du bleibst bei dieser Umkopiererei in die Struktur,
was ja grundsätzlich nicht schlecht ist.
Natürlich gehts dann noch besser.
Anstatt im Prinzip immer gleichen Code zu duplizieren, steckt man diesen
Code in eine Funktion, wählt entsprechend nützliche Argumente und schon
.... schrumpft dein Code wieder zusammen und ist genauso kurz.
C gibt dir einen Satz Werkzeuge an die Hand. Benutzen musst du sie aber
schon selber
//wenn String nicht mit "$" beginnt, Fehlerkennung eintragen und tschüss
26
strcpy(GPGGA->Name,"?");
27
}
28
}
Jetzt schreibst du dir noch die Funktion ExtractString, die den nächsten
Teilstring extrahiert und auf das angegebene Ziel umkopiert und bist
fertig. Und das ohne das dir der Code in der Größe explodiert.
(und natürlich baust du in der Funktion dann auch die Fehlerbehandlung
und Sicherungen gegen Array-Overflows mit ein. Dazu kriegt die Funktion
ja die Arraygröße mitübergeben, damit sie das tun kann)
Anstatt deine Zeit in Code-Duplikate zu stecken und darauf zu achten,
dass du alle notwendigen Stellen auch wirklich überall korrekt ersetzt
hast, hättest du deine Zeit besser mal darin investiert, zu überlegen,
wie man diesen algorithmisch immer gleichen Teil in einer eigenen
Funktion abhandeln kann.
Und: eine Programmiersprache ist nur ein Werkzeug. Das muss man aber
kennen, um es effizient benutzen zu können!
Kauf dir ein C-Buch und arbeite es durch.
Sowas
1
(*GPGGA).Name[i]=....
ist doch schauderhaft! Es ist zwar nicht falsch, aber es ist nicht die
Schreibweise, die man in C wählt. Extra dafür wurde ein eigenes Symbol
eingeführt, damit man eben nicht diese schauderhafte und schlecht zu
tippende Notation benutzen muss
(*x).y ist identisch zu x->y
Vielen Dank für die Wertvollen Hinweise.
Ja ich habe noch viel zu lernen, aber leider nur die Zeit und die Muse
mich in solchen Hobby-Progrämmchen mit dem Erlernen der Sprache zu
beschäftigen.
Bin immer für konstruktive Kritik zu haben.
Von heute an werder ich wohl einen Kniff mehr im Petto haben und
GPGGA->Empty2 schreiben.
Danke
Torsten
Torsten B. schrieb:> Vielen Dank für die Wertvollen Hinweise.> Ja ich habe noch viel zu lernen, aber leider nur die Zeit und die Muse> mich in solchen Hobby-Progrämmchen mit dem Erlernen der Sprache zu> beschäftigen.
Du würdest dir viel Zeit sparen, wenn du nicht anlassbezogen Lernen
würdest, sondern zumindest die Grundlagenkapitel (das sind ungefähr die
ersten 30 bis 40% der Kapitel) in einer vernünftigen Literatur
durcharbeiten würdest.
Das kostte dich jetzt zwar ein paar Wochen, aber diese Zeit holst du ab
dann locker wieder rein.
Ich würde hier in diesem speziellen Fall wirklich lieber eine packed
struct drüberlegen, anstelle es in funktionen zu parsen... ist halt
einfach schneller...
Und da sich heir das Format ja niemals ändern wird ist da auch nix gegen
zu sagen..