Forum: Compiler & IDEs Zweidimensionales Array. Funktioniert das so zuverlaessig?


von AVR Noob (Gast)


Lesenswert?

Hallo zusammen,

Ich darf die Arbeit eines Kollegen fortsetzen.
Leider funktioniert das was er gemacht hat nicht wie gewuenscht.
Er hat Kommandos als globale Strings definiert. Dieses "verbiegt" er 
dann in ein Array von char Zeigern.

Dann ueberschreibt er Kommandos, indem er zweidimensional auf das char* 
Array zugreift.

Geht das gut? Zumal die globalen Strings unterschiedliche Groessen 
haben.

Ich freue mich ueber jeden (vernuenftigen ;) Hinweis!

Hier mal sinngemaess, was er sich ausgedacht hat. (Originale darf ich 
hier nicht posten!)
1
/* globals */
2
3
char Command_1[12]      ="Example_123";
4
char Command_2[6]      ="Examp";
5
char Command_3[8]      ="Example;";
6
char Command_4[8]      ="Example";
7
char Command_5[8]      ="Example";
8
9
char* Commands[5]
10
11
/* main */
12
int main ()
13
{
14
  char command_replacement[8] = "Replace";
15
  uint8_t index = 2;
16
  
17
  Commands[0]  = (char*) &Command_1;
18
  Commands[1]  = (char*) &Command_2;
19
  Commands[2]  = (char*) &Command_3;
20
  Commands[3]  = (char*) &Command_4;
21
  Commands[4]  = (char*) &Command_5;
22
  Commands[5]  = (char*) &Command_6;
23
....
24
  Set_Command(index, command_replacement);
25
....
26
}
27
28
/* replace function */
29
Set_Command(uint8_t index, char *replacement)
30
{
31
    uint8_t i;
32
    
33
    for (i=0; i<=strlen(replacement),i++)
34
    {
35
      Commands[index][i] = replacement[i];
36
    }
37
}

von Quack (Gast)


Lesenswert?

AVR Noob schrieb im Beitrag #3506913:
> Hier mal sinngemaess, was er sich ausgedacht hat.

Da du seinen Code nicht verstehst, kannst du ihn nicht sinngemaess 
wiedergeben. Das bringt so nichts. 2-Dimensionale Arrays kommen in 
deiner Wiedergabe auch gar nicht vor.

von AVR Noob (Gast)


Lesenswert?

Hallo Quack,

vielen Dank fuer Deinen vernuenftigen Hinweis. :(

Auch vielen Dank fuer Deien Einschaetzung, dass ich das nicht verstehe.

Ja, zweidimensionale Arrays kommen nicht vor. Wohl aber der 
zweidimensionale Zugriff:
1
    for (i=0; i<=strlen(replacement),i++)
2
    {
3
      Commands[index][i] = replacement[i];
4
    }

Wenn Du mir das erklaeren kannst wuerde ich mich freuen. Auf Hinweise 
das ich das nicht verstehe kann ich verzichten. Wenn ich genau wuesste 
was das Problem ist, braeuchte ich dieses Forum nicht.

MfG

balze aka AVR Noob

von Rolf Magnus (Gast)


Lesenswert?

AVR Noob schrieb im Beitrag #3506913:
> Leider funktioniert das was er gemacht hat nicht wie gewuenscht.

Woran hast du denn erkannt, daß es genau das ist, was nicht 
funktioniert?  Wie äußert sich das nicht-Funktionieren? Am besten gehst 
du das Problem an, indem du aus dem Code oben ein minimales, aber 
komplettes und compilierbares Programm machst, das den Fehler zeigt. Ein 
"sinngemäßes" Codefragment ist meist nicht wirklich geeignet, um es auf 
Fehler zu analysieren.

> Dann ueberschreibt er Kommandos, indem er zweidimensional auf das char*
> Array zugreift.
>
> Geht das gut?

Ich sehe da so erstmal kein Problem, mal abgesehen davon:

> Zumal die globalen Strings unterschiedliche Groessen haben.

Du mußt halt höllisch aufpassen, daß du beim "replacen" niemals etwas 
reinschreibt, für das nicht genug Platz ist. In deinem Beispiel tust du 
das aber nicht, also hätte das so funktionieren müssen.

AVR Noob schrieb im Beitrag #3506913:
>   Commands[0]  = (char*) &Command_1;

Es würde sich anbieten, den Adressoperator wegzulassen. Dann ist die 
Adresse gleich vom richtigen Typ und man braucht diesen Cast nicht.

   Commands[0]  = Command_1;
   ...

> /* replace function */
> Set_Command(uint8_t index, char *replacement)
> {
>     uint8_t i;
>
>     for (i=0; i<=strlen(replacement),i++)
>     {
>       Commands[index][i] = replacement[i];
>     }
> }

Das könnte man auch gleich durch strcpy ersetzen:
1
/* replace function */
2
void Set_Command(uint8_t index, char *replacement)
3
{
4
    strcpy(Commands[index], replacement);
5
}

AVR Noob schrieb im Beitrag #3506935:
> Auf Hinweise das ich das nicht verstehe kann ich verzichten.

Was denn nun? Kurz vorher hast du dich noch dafür bedankt.
Verzichten kann man übrigens auch auf eine Fehlerbeschreibung, die nicht 
über ein "funktioniert nicht" hinausgeht.

von Quack (Gast)


Lesenswert?

Am Besten mal ein Tool wie Purify dran lassen. Da sieht man schnell, ob 
wild im Speicher umhergemurkst wird. Was hier extrem wahrscheinlich 
ist...

von AVR Noob (Gast)


Lesenswert?

Hallo Rolf Magnus,

vielen Dank fuer Deine Antwort.

Rolf Magnus schrieb:
> AVR Noob schrieb im Beitrag #3506913:
>> Leider funktioniert das was er gemacht hat nicht wie gewuenscht.
>
> Woran hast du denn erkannt, daß es genau das ist, was nicht
> funktioniert?  Wie äußert sich das nicht-Funktionieren? Am besten gehst
> du das Problem an, indem du aus dem Code oben ein minimales, aber
> komplettes und compilierbares Programm machst, das den Fehler zeigt. Ein
> "sinngemäßes" Codefragment ist meist nicht wirklich geeignet, um es auf
> Fehler zu analysieren.

Das Program besteht zu 90% aus CAN Kommunikation.
Alle Funktionen laufen einwandfrei, bis auf das Ersetzen von Kommandos.

Das Ruecklesen der Kommandos funktioniert, das UEberschreiben nicht.
Der wesentliche Unterschied ist der schreibende Zugriff wie 
"sinngemaess" wiedergegeben.

> Du mußt halt höllisch aufpassen, daß du beim "replacen" niemals etwas
> reinschreibt, für das nicht genug Platz ist. In deinem Beispiel tust du
> das aber nicht, also hätte das so funktionieren müssen.

Dann werde ich das vor dem UEberschreiben ueberpruefen.

> Es würde sich anbieten, den Adressoperator wegzulassen. Dann ist die
> Adresse gleich vom richtigen Typ und man braucht diesen Cast nicht.

Guter Hinweis, werde ich machen.

> Das könnte man auch gleich durch strcpy ersetzen:/* replace function */
> void Set_Command(uint8_t index, char *replacement)
> {
>     strcpy(Commands[index], replacement);
> }

Stimmt, danke!

> AVR Noob schrieb im Beitrag #3506935:
>> Auf Hinweise das ich das nicht verstehe kann ich verzichten.
>
> Was denn nun? Kurz vorher hast du dich noch dafür bedankt.

Sorry, war zynisch. Ich aergere mich immer wieder ueber Antworten, die 
keinerlei Nutzen bringen, dafuer die Frage aber die erste Antwort hat.
Quacks Kommentar hilft mir nicht und wird niemandem helfen, der 
aehnliche Verstaendnisprobleme hat. Anders sieht es mit Deiner Antwort 
aus.
Deshalb Vielen Dank.

> Verzichten kann man übrigens auch auf eine Fehlerbeschreibung, die nicht
> über ein "funktioniert nicht" hinausgeht.

Ja, tut mir leid. Damit hast Du voellig Recht. Keiner von uns besitzt 
eine (funktionierende) Glaskugel. Leider kann man nicht in den 
Mikrocontroller hinein sehen, um zu erkennen, was genau zu welchem 
Zeitpunkt "in die Hose" geht. In diesem Fall habe ich den Unterschied zu 
den funktionierenden Teilen dargestellt.

MfG,

balze aka AVR Noob

von Oliver (Gast)


Lesenswert?

AVR Noob schrieb im Beitrag #3506913:
> Geht das gut? Zumal die globalen Strings unterschiedliche Groessen
> haben.

Je nun, das geht halt so lange gut, bis du was überschreibst. In deinem 
Beispiel ist das replacment-Commando genauso lang wie das ursprüngliche. 
Das passt dann, aber wenns länger gewesen wäre, wäre Command3 kaputt. 
Und wenn du über das letzte Kommando hinausschreibst, gibt es eh 
Ram-salat.

Ergo: das funktioniert, wenn man keine Fehler macht. Die Chancen, da was 
zu versemmeln, liegen aber nur wenig unter 100%.

Ach ja, da CAN Bus: Um welches Sorte Gerät geht es denn? (nur damit ich 
darum einen großen Bogen machen kann)

Wenn man schon solche Spielereien macht, sollte es da wenigstens 
Datenstrukturen geben, die die Länge des zur Verfügung stehenden Platzes 
kennen, und dann per Zugriffsfunktion und strncpy sichergestellt sein, 
daß der Platz nicht überschrieben wird. Da das ganze ja anscheinend mit 
zur Compilezeit bekannte Konstanten passiert, können ein paar ASSERTS 
dann noch zusätzlich dafür sorgen, daß da nichts schief geht.

Oliver

von Kurt H. (Firma: KHTronik) (kurtharders)


Lesenswert?

Hallo,
wenn ich den Code sehe bekomme ich Fussnagelkreuseln!

Teilweise ineffizient (Kopierschleife) und im ganzen kaum wartbar. Die 
impliziten Einschränkungen hat man blitzartig vergessen.

Wenn das replacement selten vorkommt, würde ich mit malloc arbeiten, 
wenn es häufig auftritt festen Platz reservieren. Und dann ganz 
geradeaus programmieren :-). Also strcpy/strncpy... verwenden.

Grüße, Kurt

von Karl H. (kbuchegg)


Lesenswert?

AVR Noob schrieb im Beitrag #3507022:

> eine (funktionierende) Glaskugel. Leider kann man nicht in den
> Mikrocontroller hinein sehen, um zu erkennen, was genau zu welchem
> Zeitpunkt "in die Hose" geht.

Dann muss man da eben Abhilfe schaffen!

Oder was glaubst du, wie Profis das machen?

von Yalu X. (yalu) (Moderator)


Lesenswert?

Hier sind ein paar Kommentare zu deinem Code:

1
/* globals */
2
3
char Command_1[12]      ="Example_123";        // Unschön: Wenn die Array-Größe immer der String-Länge
4
                                               // entsprechen soll, lässt man die Größenangebae weg:
5
                                               // char Command_1[] = "Example_123";
6
                                               // Dann passieren Fehler wie der in der übernächsten
7
                                               // Zeile nicht.
8
char Command_2[6]      ="Examp";
9
char Command_3[8]      ="Example;";            // Fehler: Das String-Ende-Zeichen wird nicht
10
                                               // mitgespeichert.
11
char Command_4[8]      ="Example";
12
char Command_5[8]      ="Example";
13
14
char* Commands[5]
15
16
/* main */
17
int main ()
18
{
19
  char command_replacement[8] = "Replace";
20
  uint8_t index = 2;
21
  
22
  Commands[0]  = (char*) &Command_1;           // Unschöner Cast. Besser: Commands[0]  = Command_1;
23
  Commands[1]  = (char*) &Command_2;
24
  Commands[2]  = (char*) &Command_3;
25
  Commands[3]  = (char*) &Command_4;
26
  Commands[4]  = (char*) &Command_5;
27
  Commands[5]  = (char*) &Command_6;           // Fehler: Array-Überlauf bei Commands[5].
28
                                               //         Command_6 existiert nicht.
29
....
30
  Set_Command(index, command_replacement);     // Unsauber: Prototyp zu Set_Command fehlt
31
....
32
}
33
34
/* replace function */
35
Set_Command(uint8_t index, char *replacement)
36
{
37
    uint8_t i;
38
    
39
    for (i=0; i<=strlen(replacement),i++)      // Ineffizient: Bei einem älteren C-Compiler würde
40
                                               // strlen in jedem Schleifendurchlauf aufgerufen werden.
41
                                               // Fehler: Das Komma sollte wohl ein Semikolon sein.
42
    {
43
      Commands[index][i] = replacement[i];     // Gefährlich: Was passiert, wenn replacement länger als
44
                                               // Command[index] ist?
45
    }
46
}

Da es so scheint, als wären die Command- und die Replacement-Strings
jeweils fest und zur Compile-Zeit bekannt, wäre folgendes eine
übersichtlichere, effizientere und sicherere Variante:

1
#include <stdint.h>
2
3
const char *Commands[5] =
4
{
5
  "Example_123",
6
  "Examp",
7
  "Example;",
8
  "Example",
9
  "Example"
10
};
11
12
void Set_Command(uint8_t index, char *replacement)
13
{
14
  Commands[index] = replacement;
15
}
16
17
int main ()
18
{
19
  char *command_replacement = "Replace";
20
  uint8_t index = 2;
21
22
  Set_Command(index, command_replacement);
23
  return 0;
24
}

Dabei muss aber darauf geachtet werden, dass der String, der an
Set_Command übergeben wird, dauerhaft existent ist. In diesem Beispiel
ist das der Fall.

Kann dies nicht sichergestellt werden, muss die Funktion Set_Command
dahingehend erweitert werden, dass sie eine mit malloc und strcpy
erzeugte Kopie des übergebenen Strings in Commands einträgt. Vorher muss
das bisherige char-Array mit free freigegeben werden. Da dies aber mit
den in der Initialisierung von Commands verwendeten statischen Strings
nicht möglich ist, müssen diese ebenfalls durch dynamisch erzeugte
char-Arrays ersetzt werden, was die Intialisierung etwas umständlich
macht. Zudem wird der Code durch die free- malloc- und strcpy-Aufrufe
weniger effizient, was aber nur dann eine Rolle spielt, wenn Set_Command
sehr oft aufgerufen wird.

von Oliver (Gast)


Lesenswert?

Yalu X. schrieb:
> Da es so scheint, als wären die Command- und die Replacement-Strings
> jeweils fest und zur Compile-Zeit bekannt, wäre folgendes eine
> übersichtlichere, effizientere und sicherere Variante:

Noch wesentlich sicherer wäre es, die Replacement-Kommandos auch noch 
mit in das Array zu packen, und nur noch die Pointer auf die jeweils 
benötigten Strings umzuhängen. Damit wird man das "herzerfrischend 
bescheuerte" String-Kopieren ganz los.

Aber ganz ehrlich, ich fürchte, der Rest des Programms sieht ähnlich 
aus.

Komplett in die Tonne damit, und neu schreiben.

Oliver

von Avr N. (balze)


Lesenswert?

Hallo zusammen,

vielen Dank fuer die vielen Antworten und die guten Hinweise.

Oliver schrieb:
> Ergo: das funktioniert, wenn man keine Fehler macht. Die Chancen, da was
> zu versemmeln, liegen aber nur wenig unter 100%.

Da die Replacement Commandos von Extern (ueber CAN) kommen, kann ich das 
nicht garantieren und ich muss hier besonders gruendlich sein.

> Ach ja, da CAN Bus: Um welches Sorte Gerät geht es denn? (nur damit ich
> darum einen großen Bogen machen kann)

:) Keine Sorge. Du brauchst keinen Bogen darum machen, da das Geraet die 
Abteilung nie verlassen wird. Versprochen!


> Wenn man schon solche Spielereien macht, sollte es da wenigstens
> Datenstrukturen geben, die die Länge des zur Verfügung stehenden Platzes
> kennen, und dann per Zugriffsfunktion und strncpy sichergestellt sein,
> daß der Platz nicht überschrieben wird. ...

So werde ich es machen.

Kurt Harders schrieb:
> Hallo,
> wenn ich den Code sehe bekomme ich Fussnagelkreuseln!

ging mir auch so, obwohl ich garantiert kein C Profi bin. (Ich moechte 
aber noch was lernen und besser werden!)


Karl Heinz schrieb:
> Dann muss man da eben Abhilfe schaffen!
>
> Oder was glaubst du, wie Profis das machen?

Das wuerde ich sehr gerne wissen. Damit ich es das naechste Mal besser 
machen kann.

Yalu X. schrieb:
> Hier sind ein paar Kommentare zu deinem Code:

Danke fuer die Kommentare und Fehlerberichtigungen

> Da es so scheint, als wären die Command- und die Replacement-Strings
> jeweils fest und zur Compile-Zeit bekannt, wäre folgendes eine
> übersichtlichere, effizientere und sicherere Variante:

Das ist, wie oben beschrieben, leider nicht der Fall

> weniger effizient, was aber nur dann eine Rolle spielt, wenn Set_Command
> sehr oft aufgerufen wird.

Effizienz sollte in meinem Fall kein Problem sein.

Oliver schrieb:
> Komplett in die Tonne damit, und neu schreiben.

Ja, das waere auch mein Wunsch gewesen. Der Grund warum ich es 
fortsetzen darf ist aber leider (wie sooft) fehlende Zeit. Obwohl mir 
durchaus klar ist, dass man mit dem Beseitigen von Problemen mindestens 
genauso viel Zeit "verbraten" kann.

Vielen Dank Euch allen!

MfG

balze aka AVR Noob

von Karl H. (kbuchegg)


Lesenswert?

Avr Noob schrieb:

>> Oder was glaubst du, wie Profis das machen?
>
> Das wuerde ich sehr gerne wissen.

Debug Code!
Dazu muss man sich eine Ausgabefläche schaffen, auf der man vom Programm 
aus Ausgaben machen kann. Zb eine UART, zb ein LCD. irgendwas. 
Hauptsache man kriegt Werte raus.
Und dann kommen in den Code eben Ausgabe-Anweisungen rein, mit denen man 
sich die aktuellen Werte ausgeben lässt.

D.h. Sofern man keinen Debugger hat, mit dem man dem Programm zur 
Laufzeit über die Schulter schauen kann.


> Damit ich es das naechste Mal besser
> machen kann.

Auf einem µC kann man auch so vorgehen:
Es gibt in jedem Programm Teile, die sind in keinster Weise vom µC 
selber abhängig. Eine String-Verwaltung und String Austausch in einer 
Datenstruktur ist nicht davon abhängig, wo der String herkommt.
Ergo: Das kann man sich alles auf einem PC mit seinen im Vergleich zum 
µC weit überlegenen Debug-Möglichkeiten problemlos ansehen, entwickeln 
und testen.

> Ja, das waere auch mein Wunsch gewesen. Der Grund warum ich es
> fortsetzen darf ist aber leider (wie sooft) fehlende Zeit. Obwohl mir
> durchaus klar ist, dass man mit dem Beseitigen von Problemen mindestens
> genauso viel Zeit "verbraten" kann.

Ab einem gewissen Level der verbuggt-heit, kannst du das 'kann' durch 
ein 'wird' ersetzen.

Die erste Frage, die sich stellt lautet: Warum sind die einzelnen 
char-Arrays unterschiedlich lang?
Wenn im Code darauf sowieso keine Rücksicht genommen wird UND von vorne 
herein nicht bekannt ist, welcher Command-String zugewiesen wird, dann 
kann das konzeptmässig schon mal nicht funktionieren.

Es gibt natürlich Mittel und Wege, wie man sich selbst sowas wie eine 
rudimentäre Speicherverwaltung auf einem einzigen char Array baut, 
welches man zur Laufzeit für die einzelnen Strings aufteilt. Die Frage 
ist aber: lohnt sich das?

Der Code, den du hast, wäre für mich allerdings ein Hinweis darauf, dass 
der Originalprogrammierer nicht viel von String-Verarbeitung verstanden 
hat. Er hat so ziemlich jedes C-'Fettnäpfchen' mitgenommen, das er 
finden konnte. Der ganze Code schreit förmlich "Mein Programmierer hatte 
von Stringverarbeitung nach den Regeln der Kunst keine Ahnung".

von Avr N. (balze)


Lesenswert?

Hallo Karl Heinz,

Karl Heinz schrieb:
> Avr Noob schrieb:
>
>>> Oder was glaubst du, wie Profis das machen?
>>
>> Das wuerde ich sehr gerne wissen.
>
> Debug Code!
Den gibt es bei mir schon. Allerdings geht das nur ueber CAN. (Beide 
seriellen Schnittstellen des AT90CAN128 sind belegt, ein LCD steht mir 
nicht zur Verfuegung.) Ich debugge auch schon ueber PORT Pins mit einem 
Logic Analyzer.

> D.h. Sofern man keinen Debugger hat, mit dem man dem Programm zur
> Laufzeit über die Schulter schauen kann.

Leider nicht.
> ....Das kann man sich alles auf einem PC mit seinen im Vergleich zum
> µC weit überlegenen Debug-Möglichkeiten problemlos ansehen, entwickeln
> und testen.

Das ist eine sehr gute Idee. Mit der Entwicklung fuer PC in GCC muss ich 
mich wohl naeher beschaeftigen.

> Ab einem gewissen Level der verbuggt-heit, kannst du das 'kann' durch
> ein 'wird' ersetzen.

Ja, habe ich schon selbst leidvoll erfahren. Leider sehen das die 
Vorgesetzten nicht immer ein. Hinterher beschweren Sie sich dann aber 
doch.

>
> Die erste Frage, die sich stellt lautet: Warum sind die einzelnen
> char-Arrays unterschiedlich lang?
> Wenn im Code darauf sowieso keine Rücksicht genommen wird UND von vorne
> herein nicht bekannt ist, welcher Command-String zugewiesen wird, dann
> kann das konzeptmässig schon mal nicht funktionieren.

Ich stimme Dir zu. Ich werde alle auf die maximal moegliche Laenge 
setzen und vor dem Kopieren diese maximale Laenge ueberpruefen.

> Es gibt natürlich Mittel und Wege, wie man sich selbst sowas wie eine
> rudimentäre Speicherverwaltung auf einem einzigen char Array baut,
> welches man zur Laufzeit für die einzelnen Strings aufteilt. Die Frage
> ist aber: lohnt sich das?

In meinem Fall eindeutig: NEIN!

> Der Code, den du hast, wäre für mich allerdings ein Hinweis darauf, dass
> der Originalprogrammierer nicht viel von String-Verarbeitung verstanden
> hat. Er hat so ziemlich jedes C-'Fettnäpfchen' mitgenommen, das er
> finden konnte. Der ganze Code schreit förmlich "Mein Programmierer hatte
> von Stringverarbeitung nach den Regeln der Kunst keine Ahnung".

Damit hast Du vermutlich Recht. Mein Problem ist nur, dass mein 
Verstaendnis auch nicht viel weiter reicht. :(

Aber Dank Eurer (und Deiner) Hilfe bin ich mir jetzt immerhin einigen 
Gefahren und Schwierigkeiten bewusst und bekomme es sicherlich besser 
hin.

Vielen Dank!

MfG

balze aka AVR Noob

von Karl H. (kbuchegg)


Lesenswert?

PS:

dein 2-dimensionales String Arrays ist schon mal etwas, das ich in Frage 
stelle.

Denn mit dem Kommando String alleine ist es ja nicht getan. Da hängt ja 
noch mehr drann. Wird ein eingegebenes Kommando erkannt (wo auch immer 
dann die Eingabe herkommt), muss ja eine zugehörige Aktion ausgeführt 
werden, bzw. es wird noch andere Informationen geben, die zum Kommando 
mit dazu gehören.
Da frage ich mich aber sofort: Warum reden wir die ganze Zeit von 
Kommando Strings und nicht von einem Kommando in seiner Gesamtheit? Also 
der Zusammenfassung von Kommando und zum Kommando gehörender 
Information? Also von einem struct, der ein Kommando beschreibt?
Womit sich die Frage nach einem 2-dimensionalen char-Array insofern in 
Luft auflöst, weil es das gar nicht mehr gibt. Es gibt ein Array von 
'Kommandos' und Teil eines jeden Kommandos ist ein char-Array, in dem 
der Kommando-Text steht.

: Bearbeitet durch User
von Oliver (Gast)


Lesenswert?

Nach wie vor verstehe ich den Sinn der ganzen String-Kopiererei nicht.

Selbst wenn da Kommandos als Strings über den CAN-Bus reinkommen, die 
später wieder ausgegeben werden sollen, müssen die ja zunächst mal 
irgednwie im Speicher abgelegt werden. Das geht halt über malloc() oder 
eine eigene Speicherverwaltung in einem Array.

Sobald die erst einmal im Speicher liegen, muß aber nichts mehr kopiert 
werden. Da braucht es nur eine Zeigerverwaltung, die die Zeiger auf alle 
vorhandenen Kommandos kennt, und den jeweils gewünschten liefert.

Dann noch dafür sorgen, daß ersetzte Kommandos gelöscht werden, und 
alles wird gut.

Oliver

von Avr N. (balze)


Lesenswert?

Hallo zusammen,

Karl Heinz schrieb:
> PS:
>
> dein 2-dimensionales String Arrays ist schon mal etwas, das ich in Frage
> stelle.
>
> Denn mit dem Kommando String alleine ist es ja nicht getan. Da hängt ja
> noch mehr drann. Wird ein eingegebenes Kommando erkannt (wo auch immer
> dann die Eingabe herkommt), muss ja eine zugehörige Aktion ausgeführt
> werden, bzw. es wird noch andere Informationen geben, die zum Kommando
> mit dazu gehören.
> Da frage ich mich aber sofort: Warum reden wir die ganze Zeit von
> Kommando Strings und nicht von einem Kommando in seiner Gesamtheit? Also
> der Zusammenfassung von Kommando und zum Kommando gehörender
> Information? Also von einem struct, der ein Kommando beschreibt?
> Womit sich die Frage nach einem 2-dimensionalen char-Array insofern in
> Luft auflöst, weil es das gar nicht mehr gibt. Es gibt ein Array von
> 'Kommandos' und Teil eines jeden Kommandos ist ein char-Array, in dem
> der Kommando-Text steht.

Das bringt es auf den Punkt!

Ich werde es auf ein Array von structs umstellen. Teil des structs ist 
dann der Kommandotext. Das macht es dann zukuenftig auch leicher wart- 
und erweiterbar.
Leider ist dieses 2 dimensionale char Array sehr tief in der Software 
verwurzelt. Was auf der einen Seite viel Aufwand bedeutet, diese 
AEnderung aber auf der anderen Seite unverzichtbar macht.


Oliver schrieb:
> Nach wie vor verstehe ich den Sinn der ganzen String-Kopiererei
> nicht.
>
> Selbst wenn da Kommandos als Strings über den CAN-Bus reinkommen, die
> später wieder ausgegeben werden sollen, müssen die ja zunächst mal
> irgednwie im Speicher abgelegt werden. Das geht halt über malloc() oder
> eine eigene Speicherverwaltung in einem Array.
>
> Sobald die erst einmal im Speicher liegen, muß aber nichts mehr kopiert
> werden. Da braucht es nur eine Zeigerverwaltung, die die Zeiger auf alle
> vorhandenen Kommandos kennt, und den jeweils gewünschten liefert.
>
> Dann noch dafür sorgen, daß ersetzte Kommandos gelöscht werden, und
> alles wird gut.
>
> Oliver

es gibt eine feste Anzahl von vorher definierten Kommandos. Man soll 
aber von Aussen die Moeglichkeit haben, einzelne Kommandos zu 
manipulieren. Also dieses eine Kommando zu ersetzen. Der Zugriff auf 
dieses manipulierte Kommando soll aber wie gewohnt stattfinden.

Es gibt also keine zusaetzlichen Kommandos von Aussen, sondern nur 
Ersetzungen bereits vorhandener (und unter bestimmten Voraussetzungen 
verwendeter) Kommandos.

MfG

balze aka AVR Noob

von Oliver (Gast)


Lesenswert?

Avr Noob schrieb:
> Leider ist dieses 2 dimensionale char Array sehr tief in der Software
> verwurzelt. Was auf der einen Seite viel Aufwand bedeutet, diese
> AEnderung aber auf der anderen Seite unverzichtbar macht.

Welches?
1
char* Commands[5]
 ???

Das kein zweidimensonales Array, sondern schlicht ein Array von char*. 
Die einzelnen Pointer können frei irgendwo in den Speicher zeigen, wo 
auch immer der zugehörige String gerade abgelegt ist.

Das kann ja als "Interface" (zur Not) so bleiben, auch wenn du auf 
Structs umstellst. Du musst halt in der Kommandoverwaltung die einzelnen 
Pointer in dem Array so setzen, daß die fünf gewünschten 
Kommando-Strings damit referenziert werden.

Diese Kommandoverwaltung, die die Strings ersetzt und die Pointer 
umsetzt, usw. die gehört neu geschrieben, und möglichst mit 
Zugriffsfunktionen als Modul gekapselt. Die Stellen im Restcode, die an 
den Kommandos rumfummeln, musst du halt anpassen. Mit etwas Glück sind 
das aber nicht viele.

Oliver

von Karl H. (kbuchegg)


Lesenswert?

Avr Noob schrieb:

> verwurzelt. Was auf der einen Seite viel Aufwand bedeutet,

wenn mich meine Intuition und Erfahrung nicht trügt, wirst du 
feststellen, dass mit einem sauberen Aufbau gleich mal rund 30% des 
Codes wegfallen und der übrig gebliebene Code übersichtlicher, einfacher 
und besser wartbar ist, sobald das unstrukturierte Chaos erst mal 
verschwunden ist. Das er dann auch noch besser funktioniert und 
eventuell sogar noch mehr kann, ist dann noch das Sahnehäubchen oben 
drauf :-)

von Avr N. (balze)


Lesenswert?

Ich wuenscht ich haette Eure Erfahrung. :)

Ich werde Eure Hinweise beherzigen und die Kommandos vernuenftig 
kapseln.

Das mit den Zeigern auf geaenderte Kommandos hoert sich eigentlich gut 
an. Es ist aber moeglich das die Kommandos sehr oft (nicht schnell aber 
oft) ersetzt werden. Mir fehlen hier Erfahrungen im Umgang mit malloc 
und free. Nicht das ich den speicher damit fragmentiere und es 
irgendwann nicht mehr funktioniert.
Um das kopieren komme ich sowieso nicht herum. Ich muss es ja wenigstens 
aus dem CAN-Buffe in den String kopieren. Dann kann ich auch gleich den 
Zielstring nehmen.

Danke Euch!

MfG

balze aka AVR Noob

von Karl H. (kbuchegg)


Lesenswert?

Avr Noob schrieb:

> Um das kopieren komme ich sowieso nicht herum. Ich muss es ja wenigstens
> aus dem CAN-Buffe in den String kopieren. Dann kann ich auch gleich den
> Zielstring nehmen.

Da würde ich mir jetzt erst mal keine Sorgen machen.
Wenn das vernünftig aufgebaut ist, UND sich in weiterer Folge das 
Kopieren als Problem darstellt, dann kann man das immer noch ändern. Ein 
sauberer Aufbau zeichnet sich dadurch aus, dass Änderungen leicht 
möglich sind, ohne dass gleich der komplette Code über den Haufen 
geworfen werden muss.

von Quack (Gast)


Lesenswert?

Einfach ein (diesmal wirklich) 2-dimensionales Array benutzen und 
strncpy nehmen. Neu schreiben sollte man nur, wenn man es wirklich 
besser kann. Sonst kommt nur ein anderer Murks raus.

von W.S. (Gast)


Lesenswert?

Quack schrieb:
> Einfach ein (diesmal wirklich) 2-dimensionales Array benutzen

Ah ja. Erkläre doch mal, was in C ein zweidimensionales Array wirklich 
ist.. (Tip: Array aus Pointern auf Arrays..)

Karl Heinz schrieb:
> ohne dass gleich der komplette Code über den Haufen
> geworfen werden muss.

Ach, Karlheinz, in diesem Falle wäre ich genau _dafür_: Den ganzen Code 
komplett rauszuwerfen und das Ganze grundsätzlich anders anzugehen. Ich 
sehe überhaupt keinen Sinn darin, irgendwelche eigentlich konstanten 
Zeichenketten irgendwo anders hinzukopieren. Dann schon eher mit Handles 
arbeiten, die nur bei Bedarf einen entsprechenden String liefern.

W.S.

von Karl H. (kbuchegg)


Lesenswert?

W.S. schrieb:
> Quack schrieb:
>> Einfach ein (diesmal wirklich) 2-dimensionales Array benutzen
>
> Ah ja. Erkläre doch mal, was in C ein zweidimensionales Array _wirklich_
> ist.. (Tip: Array aus Pointern auf Arrays..)

Auch in C gibt es 2-dimensionale Arrays.
Ein Array aus Pointern auf Arrays ist zwar in der verwendenden Syntax 
gleich, ist aber intern anders aufgebaut.

> Ach, Karlheinz, in diesem Falle wäre ich genau _dafür_: Den ganzen Code
> komplett rauszuwerfen und das Ganze grundsätzlich anders anzugehen. Ich
> sehe überhaupt keinen Sinn darin, irgendwelche eigentlich konstanten
> Zeichenketten irgendwo anders hinzukopieren. Dann schon eher mit Handles
> arbeiten, die nur bei Bedarf einen entsprechenden String liefern.

Wenn ich mir so ansehe, woran es beim TO hapert, dann denke ich nicht, 
dass er das hinkriegt.
So oft wird er schon kein neues Kommando definieren, dass die Kopiererei 
gross ins Gewicht fällt.
Eleganter wärs natürlich sich aus einem String-Pool bedienen zu können. 
Das kriegst du hin, das krieg ich hin, aber ob jemand den man daran 
erinnern muss, das es struct gibt und der mit Pointern auf Kriegsfuss 
steht, das hin kriegt ....

: Bearbeitet durch User
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
Noch kein Account? Hier anmelden.