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).
Ka wozu du das brauchst, aber machs doch so: Definier dir die Zeilenarrays und pack Zeiger auf diese in das Spaltenarray.
1 | int zeile1[5]; |
2 | int zeile2[10]; |
3 | int* spalte[2] = {zeile1, zeile2}; |
4 | |
5 | //Zugriff:
|
6 | int blah = spalte[0][0]; |
Musst dann nur höllisch aufpassen, dasse nicht bei nem Zeilenarray daneben greifst.
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
1 | void ParsGPGGA(char *GPGGA_Ptr, struct _gpgga *GPGGA) |
2 | {
|
3 | char FeldNr = 0; |
4 | |
5 | if (*GPGGA_Ptr =='$') |
6 | {
|
7 | ExtractString( GPGGA->Name, sizeof(GPGGA->Name), &GPGGA_Ptr ); |
8 | ExtractString( GPGGA->UTC, sizeof(GPGGA->UTC), &GPGGA_Ptr ); |
9 | ExtractString( GPGGA->Latitude, sizeof(GPGGA->Latitude), &GPGGA_Ptr ); |
10 | ExtractString( GPGGA->N_S, sizeof(GPGGA->N_S), &GPGGA_Ptr ); |
11 | ExtractString( GPGGA->Longitude, sizeof(GPGGA->Longitude), &GPGGA_Ptr ); |
12 | ExtractString( GPGGA->E_W, sizeof(GPGGA->E_W), &GPGGA_Ptr ); |
13 | ExtractString( GPGGA->Quality, sizeof(GPGGA->Quality), &GPGGA_Ptr ); |
14 | ExtractString( GPGGA->NumbSat, sizeof(GPGGA->NumbSat), &GPGGA_Ptr ); |
15 | ExtractString( GPGGA->HorPrec, sizeof(GPGGA->HorPrec), &GPGGA_Ptr ); |
16 | ExtractString( GPGGA->HightNN, sizeof(GPGGA->HightNN), &GPGGA_Ptr ); |
17 | ExtractString( GPGGA->Reference1, sizeof(GPGGA->Reference1), &GPGGA_Ptr ); |
18 | ExtractString( GPGGA->HightGeo, sizeof(GPGGA->HightGeo), &GPGGA_Ptr ); |
19 | ExtractString( GPGGA->Reference2, sizeof(GPGGA->Reference2), &GPGGA_Ptr ); |
20 | ExtractString( GPGGA->Empty1, sizeof(GPGGA->Empty1), &GPGGA_Ptr ); |
21 | ExtractString( GPGGA->Empty2, sizeof(GPGGA->Empty2), &GPGGA_Ptr ); |
22 | }
|
23 | else
|
24 | {
|
25 | //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)
1 | void ExtractString( char* Ziel, int LenZiel, char** Quelle) |
2 | {
|
3 | ..... dein Code hier |
4 | }
|
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..
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.