Wie schreibt man Mit c einen Ringspeicher?

1 Antwort

Vom Fragesteller als hilfreich ausgezeichnet

Die Aufgabe ist irgendwie seltsam mit den ganzen "memcopy" und Zeichenendezeichen. Einen technischen Ringpuffer baut man recht einfach so:

Man braucht zwei pointer, für Buchstaben vom Typ char. Bei zahlen natürlich float, int oder was man da für zahlen hat. generell würde auch für Zahlen beliebiger größe ein charpointer funktionieren.

Nennen den einfach ringpoint und machen direkt ein Array draus:

char ringpoint[];

Jetzt überlegen, wie groß der Ringpuffer sein soll. Am besten ist immer "2^n", eine glatte Binärzahl. Nehmen wir einfach mal 256, eine schöne runde Zahl die 8-bit voll ausnutzt. Also

char ringpoint[0xFF];

Der Grund ist einfach. normalerweise müssten wir aufpassen, dass der Pointer nicht über das Ende des linearen Arrays hinaus läuft. Wir müssten immer mit if aufpassen ob der am Ende ist und dann den "her Hand" auf den Anfang des Arrays setzen. Bei einer schönen glatten Binärzahl können wir "maskieren". Haben wir 4 bit, also 0x0F als Maximum, dann brauchen wir wenn wir mit der Variable i die Position im pointer merken nur sagen

i = ++i & 0x0F;

Wir nehmen den aktuellen Wert der position und inkrementieren die ZUERST, daher ++i (statt i ++) und verknüpfen die dann sofort logisch und mit 0x0F. Hatte i nach dem inkrementieren 0x10, wird die direkt auf 0x00 gesetzt, da die Eins im 0x10 durch das UND abgeschnitten wird.

Da wir aber nur 8-bit haben und char 8-bit sind, geht das völlig automatisch, denn char springt von 255d auf 0 wenn man weiter inkrementiert. Also keine Hirnverrenkungen und extra code nötig, der pointer läuft ganz von alleine schön im Kreis, also im Ring obwohl man ja nur lineare Arrays haben kann. Man kann sich das Array also als Ring vorstellen.

Also denken wir uns zwei schöne Namen für die Zählpositionen der pointer aus, wie wäre es mit "INcount" und "OUTcount"? Also ich bin dafür!

char INcount = 0;
char OUTcount = 0;

Wir greifen also immer folgendermassen zu:

ringpoint[INcount] = bla;
bla = ringpoint[OUTcount];

Bei jedem Zugriff müssen wir natürlich immer eine Position weiter setzen. Also kann man gleich

ringpoint[INcount++] = bla;
bla = ringpoint[OUTcount++];

schreiben.

Falls wir keinen ganzen Datentyp als Bereich nehmen können, aber immer noch eine "glatte Binärzahl", dann kann man immer noch maskieren:

ringpoint[++INcount & 0x0F] = bla;
bla = ringpoint[++OUTcount & 0x0F];

Und wie steuert man das ganze?

Möchte man wissen ob was im Puffer drin ist, einfach INpoint und OUTpoint vergleichen. Stehen die an der gleichen Stelle, ist nichts drin! Einfaches IF! Die Ausgabe erfolgt also so lange wie die Pointer nicht auf der selben Stelle stehen.

und beim reinschreiben aufpassen, dass der INcount mindestens 1 unter dem OUTcount steht - oder einfacher ob "INcount+1!=OUTcount". Denn dann hat man ja noch mindestens eine Einheit Platz drin!

D.H. rein und raus macht man am besten selber Byteweise per Schleife.

Beim Rein also so lange wie Platz im Ringpuffer ist und das Stringende ('\0') nicht erreicht wurde, dann nach dem kopieren des Stringendes aufhören.

Beim Raus stur so lange INcount != OUTcount oder ein Stringende ('\0') wurde kopiert.

Bei diesem Puffer kann nichts schief gehen. Der kann nur Daten verstümmeln wenn kein Platz mehr drin ist.

Daher entweder das Rein blockieren wenn zu wenig Platz ist (Differenz zwischen INcount und OUTcount ausrechnen), also weniger Platz als strlen() sagt vorhanden ist oder beim Raus stur eine '\0' "hinterherpflastern" damit auch auf jeden Fall ein Stringende zwangsweise erzeugt wird auch wenn Teile eines Strings fehlen.

Was das in der Aufgabe mit den Satzzeichen soll kann ich Dir nicht sagen. Kannst Du ja zusätzlich zum Stringende (\0) prüfen.

Memcopy und strcopy sind "gefährlich" und die bedienen auch nicht Deine pointer, also wozu das nehmen wenn man eine elegante Schleife selber schreiben kann?

Woher ich das weiß:Berufserfahrung