Hllo,
ich habe ein Problem und hoffe hier auf einen hilfenden rat.
Ich muss einer Funktion eine Struktur übergeben. Allerdings habe habe
ich nur einen Pointer davon und muss die Struktur immer erweitern (also
neue Daten hinten drann hängen)
1
typedefstruct
2
{
3
uint8_tid;
4
uint8_tflags;
5
uint8_tframeLength;
6
}frameCfg_ts;
7
8
typedefstruct
9
{
10
frameCfg_ts*frameTable_ps;
11
uint8_tnofFrames;
12
}Schedule_ts;
Lokal habe ich mir eine Variable erstellt
1
Schedule_tsscheduleCfg_s;
Jetzt benötige ich eine Funktion, wo ich daten an frameTable_ps
dranhängen kann.
Beim ersten aufruf funktioniert es ja noch. aber wenn die Funktion ein
weiteres mal aufgerufen wird, steht an der stelle wo der Pointer drauf
zeigt ja schon was drinn.
Wie kann ich hinten etwas dranhängen?
Wo kann man sich ja mit scheduleCfg_s.nofFrames ausrechnen. Ich weiß
halt nur nicht wie ich es hinschreiben muss.
Mit realloc hat das nichts zu tun, und auch nichts mit "struct
erweitern".
Das Stichwort "linked list" fiel ja schon. Dazu gibt's ausreichend viele
Infos im Netz.
Chandler B. schrieb:> Ich muss
Manchmal stellt sich dann die Frage: Warum?
Hausaufgaben? RTFM
Nutzung vorhandener Bibliotheken? RTFM
Oliver
Oliver S. schrieb:> Chandler B. schrieb:>> Ich muss
Ich muss, da die Bibliothek die ich verwende eine fertige konfiguration
benötigt. Da es bei uns variable sein kann haben wir bisher
vorgefertigte Listen genommen. Hier wurde für jede Kombination eine
liste erstellt und beim Aufstart abgeprüft welche genommen werden muss.
Da jetzt aber mehrere module kommen, die alle ihr eigenen FrameTable
haben, wird das mit den vorgefertigeten Tables zu umständlich
Chandler B. schrieb:> Wie kann ich hinten etwas dranhängen?
Allein aus der Deklaration von `Schedule_ts` ergibt sich, dass es sich
wohl eher um ein dynamisches array handelt. Mit `nofFrames` hast Du die
derzeitige Anzahl der Elemente im array. Du brauchst Speicher für
nofFrames zusätzliche Elemente.
In C macht man das wohl mit `realloc`:
https://en.cppreference.com/w/c/memory/realloc
P.S.: Eine verkettete Liste kann es nicht sein.
Edit: Typos
Klaus W. schrieb:> Chandler B. schrieb:>> frameTable_ps* frameTable_ps>> Chandler B. schrieb:>> frameTable_ps = frameTable_ps;
die Funktion sollte so aussehen
>> oder die anzahl der Frames mit in der Struktur>
1
...
2
>
Bevor Du Dich total verzettelst, hilft es ggf. einmal die Dokumentation
der Funktion zu schreiben. Dann ist Dir vielleicht viel besser klar, was
die Funktionen machen sollen. Danach kann man dann auch überlegen, ob
die Namen für die Funktionen gut gewählt sind.
Königsdisziplin: Du überlegst Dir auch, wie Du die Funktionen testen
möchtest und schreibst die Tests ggf. sogar bevor Du die Funktionen
selbst implementierst (wie sieht so eine Datenstruktur initial aus?
Welche Operationen habe ich auf der Datenstruktur? Welche Sonderfälle
gibt es dabei etc.).
Um Funktionen gut testen zu können, ist es vorteilhaft, keine
Seiteneffekte zu haben. In Deinem Fall würde das bedeuten, dass Du auf
scheduleCfg_s nicht direkt in der Funktion zugreifst, sondern auch diese
Struktur als Parameter übergibst.
Man kann das alles händisch über realloc(), eventuelll umkopieren etc,
machen.
Man kann auch eine verkette Liste anlegen, Beispiele dafür gibt es genug
in diversen C Büchern.
Da muss man aber immer mit den Pointern klar kommen, und genau wissen,
was man tut.
Ich hatte darauf irgendwann keine Lust mehr, und benutze nur noch C++
std::vector.
Damit kann man wunderbar was dranhängen, oder löschen. Kann die
Strukturen selber in den Vector eintragen, oder da nur die Pointer
nehmen.
Ich bin damit schneller, und habe auch wesentlich weniger Fehler, weil
kein Pointer mal ins Nirwana zeigt.
https://en.cppreference.com/w/cpp/container/vector
Und beim Kompilieren statt gcc kann man einfach g++ aufrufen.
Oliver S. schrieb:> Mit realloc hat das nichts zu tun
Doch, natürlich kann man das auch damit machen. Hat halt neben dem
Nachteil, dass ReAllocs Zeit kosten und den Speicher in großen Blöcken
fragmentieren, den Vorteil, dass alle Operationen, die keine Erweiterung
des Arrays erfordern, eben auf ein Array angewendet werden können, was
fast immer viel effizienter ist als dieselben Operationen auf eine
(auch: Double-)LinkedList anzuwenden.
Der Overhead sowohl beim Speicherbedarf (zusätzlich: die Node) als auch
beim Rechenzeitaufwand für's Iterieren mit einem Haufen Indirektionen
fällt einfach weg.
Und das Problem bei der Erweiterung kann man mit "Exp2-Erweiterung" und
vernünftigen Startwerten bezüglich der erforderlichen Kapazität recht
gut in den Griff bekommen. Die Libs aller höheren Programmiersprachen
machen das genau so.
Oder, je nach konkreter Ausprägung, auch mal als "Chimäre". Das hängt
dann primär davon ab, wie groß der Payload ist, aber auch von den
anzuwendenden Operationen. Dann gibt es u.U. einen Speicherbereich, der
als Array nach den o.g. Prinzipien verwaltet wird und die eigentlichen
Nutzdaten beinhaltet, und einen zusätzlichen Speicherbereich, der die
Nodes einer LL aufnimmt, aber auch nach den o.g. Prinzipien verwaltet
wird. Sowas trifft man vor allem bei Sachen, die einerseits viel Payload
haben, abdererseits aber auch schnell nach vielen verschiedenen
Kriterien sortiert werden sollen. Sprich: z.B. bei Datenbanken.
Letzlich kochen halt alle mit Wasser. Unbegrenzte Resourcen gibt es
nicht. Und deswegen auch keine für alle Anwendungsfälle optimale Lösung.
Chandler B. schrieb:> Wie kann ich hinten etwas dranhängen?
Gar nicht.
Du legst ein Array der Struct an, z.B. für 10 Einträge und füllst dieses
nacheinander.
Sind alle Einträge belegt, erweiterst Du mit realloc das Array.
Zur Verwaltung des Arrays hast Du noch 2 Variablen für die reservierte
und die belegte Anzahl.
Die belegte Anzahl kann man auch mit einem ungültigen Element
kennzeichnen (Leerstring, Nullpointer, NAN).
Ist zur Compilezeit die maximale Anzahl bekannt, kann man die natürlich
fest reservieren.
Eine Linked List benutzt man nur, wenn die Elemente sortiert werden
müssen, z.B. bei einem Scheduler nach der Ablaufzeit.