Guten Morgen, ich habe einige Fragen zu C. - Wenn ich eine Größe von #define MAX 1024 zeichen definiere, sehe ich oft bei der Deklaration so etwas wie "char buffer[MAX+1]". Wozu steht die "1"? MAX übergebe ich später an eine Funktion mit der maximalen Anzahl an Strings, die erlaubt ist. Bedeutet die +1, dass das "\0" berücksichtig wird? - im weiteren Verlauf meiner Funktion lasse ich mir die Anzahl der Strings zurückgeben: bytes_read = foo(.....); Nun wird oft geschrieben: "buffer[bytes_read]='\0'". Was bedeutet das? Das nach meinem String, das ich über eine Konsole eingebe, das Terminierungszeichen drangehängt wird?
Tim schrieb: > MAX übergebe ich später an eine Funktion mit der maximalen Anzahl an > Strings, die erlaubt ist. Strings oder Zeichen? > Nun wird oft geschrieben: "buffer[bytes_read]='\0'". Was bedeutet das? > Das nach meinem String, das ich über eine Konsole eingebe, das > Terminierungszeichen drangehängt wird? Exakt. So etwas sollte natürlich nur gemacht werden, solange "bytes_read" kleiner ist als die Puffergröße.
Tim schrieb: > - Wenn ich eine Größe von #define MAX 1024 zeichen definiere, sehe ich > oft bei der Deklaration so etwas wie "char buffer[MAX+1]". Wozu steht > die "1"? MAX übergebe ich später an eine Funktion mit der maximalen > Anzahl an Strings, die erlaubt ist. Bedeutet die +1, dass das "\0" > berücksichtig wird? Ja und nein. Das bedeutet, dass die \0 berücksichtigt werden soll. Obs gemacht werden soll oder nicht hängt von dir selber ab. Tim schrieb: > - im weiteren Verlauf meiner Funktion lasse ich mir die Anzahl der > Strings zurückgeben: bytes_read = foo(.....); > Nun wird oft geschrieben: "buffer[bytes_read]='\0'". Was bedeutet das? > Das nach meinem String, das ich über eine Konsole eingebe, das > Terminierungszeichen drangehängt wird? Ja. Dabei aber wieder aufpassen das du nicht über die Grenzen hinausschreibt BTW: chars müssen nicht terminiert werden, weil es ja nur ein Zeichen ist. Die Terminierung von character arrays hingegen ist mit \o festgelegt (ob das eine Konvention oder im Standard drinsteht beantwortet dir mit Sicherheit jemand anderes hier, hab meinen Ritchi grad nicht hier)
Rufus Τ. F. schrieb: > ui schrieb: >> ist mit \o festgelegt > > Nicht \o, sondern \0. F*ck vertippt :) Warum müssen die auch s0 nahe beinander liegen?
Das ist, wie bereits gesagt ein persönliches Prinzip. Bei Zeichen (char []) ist es eigentlich egal. Aber bei Zeichenketten bzw. Strings gilt: Die sind immer ein Zeichen länger, dadurch dass "c" immer ein terminierendes '\0' hinten anhängt. Ein simples Beispiel: "Ein String mit 25 Zeichen" benötigt intern 26 Zeichen. Dadurch, dass am Ende das String-Endezeichen angehängt wird. Letzteres geschieht automatisch. Die str???-Funktionen erwarten dies alle. Üblicherweise wird das Ende-Zeichen auch nicht explizit angegeben. Also: #define STR_MAX 25 Variable char [ STR_MAX + 1 ]; In diese Variable passt also eine Zeichenkette mit maximal 25 Zeichen.
ui schrieb: >> Nicht \o, sondern \0. > > F*ck vertippt :) Warum müssen die auch s0 nahe beinander liegen? Ja, klar ... http://i.imgur.com/0DvXxkX.jpg
Sapperlot schrieb: > ui schrieb: >>> Nicht \o, sondern \0. >> >> F*ck vertippt :) Warum müssen die auch s0 nahe beinander liegen? > > Ja, klar ... > http://i.imgur.com/0DvXxkX.jpg Kännte ich mich wenigszens nicht verzzipen.
Amateur schrieb: > Das ist, wie bereits gesagt ein persönliches Prinzip. > > Bei Zeichen (char []) ist es eigentlich egal. Aber bei Zeichenketten > bzw. Strings gilt: Die sind immer ein Zeichen länger, dadurch dass "c" > immer ein terminierendes '\0' hinten anhängt. > > Ein simples Beispiel: > > "Ein String mit 25 Zeichen" > > benötigt intern 26 Zeichen. Dadurch, dass am Ende das String-Endezeichen > angehängt wird. Letzteres geschieht automatisch. Die str???-Funktionen > erwarten dies alle. Üblicherweise wird das Ende-Zeichen auch nicht > explizit angegeben. > > Also: > #define STR_MAX 25 > Variable char [ STR_MAX + 1 ]; > > In diese Variable passt also eine Zeichenkette mit maximal 25 Zeichen. Automatisch passiert gar nix. Du meinst implizit, deinen "automatismus kann man auch ganz leicht kaputt machen:
1 | char a[5] = "fooo"; |
2 | a[5] = 'f'; |
und schon ist der "automatismus" im Ar*ch. Wer in C programmiert (eigentlich bei jeder Sprache, nur in C ganz besonders) sollte insbesondere über alles mit strings dreimal nachdenken bevor er irgendwas damit macht, siehe auch https://www.golem.de/news/rust-c-ist-eine-feindselige-sprache-1707-129196.html
ui schrieb: > char a[5] = "fooo"; > a[5] = 'f'; Gleich noch beim Beispiel off-by-one... So muss natürlich richtig heißen. char a[5] = "fooo" a[4] = 'f';
@ui Mir kommt Dein Argument ein wenig wie das Zählen von Erbsen vor. Der Ausbruch aus den String-konventionen ist natürlich ganz leicht, wenn man einen fremden (hier falschen) Datentyp benutzt. Wenn mich nämlich nicht alles täuscht ist: char a[5] = "fooo" eine zulässige Anweisung im Datenformat string und a[4] = 'f'; eine zulässige Anweisung im Datenformat char Auf gleiche Weise kann man natürlich auch wunderbar Zahlen, im 32-Bit Format, durch das Speichern eines Bytes "relativieren".
Ein wesentlicher Vorteil bei +1 ist, ich kann das Define bei späteren Operationen so benutzen, wie es ist und muss nicht 1 abziehen, um Platz für das '\0' zu lassen:
1 | if (strlen(stringa) <= MAX) |
2 | {
|
3 | strcpy(stringb, stringa); |
4 | }
|
Man kann sich also zwischen +1 bei der Deklaration oder -1 bei den Stringoperationen entscheiden.
Ah ok. Und was bewirkt eigentlich "memset(buffer, 0, MAX_SIZE); ? Wenn ich anschließend mit printf irgend ein Element ausgeben möchte, erhalte ich nicht die Zahl "0", o obwohl so initialisiert. Wie überprüfe ich, dass das char* wirklich mit "0" initialisiert worden ist? "
Der Speicher sollte hoffentlich nicht mit '0' initialisiert worden sein (Ziffer 0, also Bytewert 0x30), sondern mit '\0' (0x00). Wenn das printf einfach gar nix ausgibt, hast du es evtl. richtig gemacht.
Bedeutet Initialisierung nicht, dass ich es auch mit "0" initialisiere und dann ausgeben kann?
Tim schrieb: > Bedeutet Initialisierung nicht, dass ich es auch mit "0" initialisiere > und dann ausgeben kann? Die Stringterminierung muss vorhanden sein, sonst wird Müll ausgeben. Die Ziffer 0 als darstellbares Zeichen ist keine Stringterminierung.
Sebastian S. schrieb: > @ui > Mir kommt Dein Argument ein wenig wie das Zählen von Erbsen vor. > > Der Ausbruch aus den String-konventionen ist natürlich ganz leicht, wenn > man einen fremden (hier falschen) Datentyp benutzt. > > Wenn mich nämlich nicht alles täuscht ist: > char a[5] = "fooo" eine zulässige Anweisung im Datenformat string > und > a[4] = 'f'; eine zulässige Anweisung im Datenformat char Ja das sind durchaus Kleinigkeiten. Aber um Verständnis zu schaffen und Fehler vorzubeugen finde ich diese Kleinigkeiten (oder Erbsen zählen) enorm wichtig. Übrigens: Wenn mich nicht alles täuscht (d.h. ich müsste nachschauen) kennt C keine strings (wie aus java,python,c++ etc. bekannt). C kennt nur character arrays, und damit hinkt dein Vergleich ganz gewaltig. Das gleiche für andere Datentypen ist total normal (also das man das ganze array nutzt), nur für char arrays hat man sich diesen Sonderfall ausgedacht. Und diesen zu kennen ist enorm wichtig, die meisten buffer-overflows basieren genau auf diesem Problem.
>Ah ok. Und was bewirkt eigentlich "memset(buffer, 0, MAX_SIZE); ? Niemand hindert Dich daran MAX_SIZE für inclusive das Terminierungszeichen zu definieren. Die meisten aber würden MAX_SIZE + 1 schreiben oder beten, dass die zu speichernden Strings, nie die maximale Länge erreichen. Das hat aber den Nachteil - wie bereits gesagt - dass Du z.B. in Schleifen, mit for (...;; <=MAX_SIZE - 1) Arbeiten tust. > Das ist, wie bereits gesagt ein persönliches Prinzip. Übrigens: Summarisch gesehen wird meist nur bei der Variablenkonstruktion oder der Speicherreservierung MAX_SIZE + 1 verwendet. Später fast immer MAX_SIZE ohne den Plusterm. Dem Compiler ist es egal, da es ja, auf jeden Fall, um eine Konstante geht.
Sebastian S. schrieb: > Wenn mich nämlich nicht alles täuscht ist: > char a[5] = "fooo" eine zulässige Anweisung im Datenformat string Das ist keine Anweisung, das ist eine Definition einer Variablen (vom Typ char-Array) mit einer Initialisierung mit einer Stringkonstanten. > und > a[4] = 'f'; eine zulässige Anweisung im Datenformat char Das ist eine Zuweisung an ein Element eines Arrays. Komplett andere Baustelle. Eine Zuweisung von Stringkonstanten an Arrays ist nicht möglich, die können nur zur Initialisierung verwendet werden (oder müssen mit Funktionen à la strcpy/memcpy explizit kopiert werden).
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.