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)
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.
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:
@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.
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).