Das Programmverhalten ist undefiniert. Es kann funktionieren, wenn im
Speicher zufällig eine hinter deinem Array ist. Oder es kann ein paar
tausend weitere Zeichen ausgeben, bis eine 0 im Speicher steht.
Hans schrieb:> Netter Trollversuch, aber wo siehst du da eine Endlosschleife?
Im printf. Bei %s versucht doch printf solange auszugeben bis \0 kommt,
und das kommt ja nicht vor, also irgendwie sollte es doch die restlichen
Speicherzellen (array) durchsuchen, bis es das Betriebssystem
abschießt... oder liege ich da falsch?
Fallobst schrieb:> bis eine 0 im Speicher steht.
zufällig funktionierts aber immer ohne dass irgendetwas hinterher kommt.
Vielleicht braucht das printf ja gar nicht, aber es muss es doch
brauchen, denn ein Leerzeichen gehört dann auch zum String, und ich kann
mir aber beim besten Willen nicht vorstellen, dass bei 15 mal von 15
Versuchen immer Leerzeichen und \0 im Speicher steht!
vorname ist drei zeichen lang, es werden drei minus eins gleich zwei
zeichen kopiert. vorname ist mit drei mal null ix null null
initialisert.
edit:
zorry, korrigiere mich: vorname ist eine stackvariable d.h. inhalt
unbekannt, evtl. zufällig null.
Frank schrieb:> mir aber beim besten Willen nicht vorstellen, dass bei 15 mal von 15
Doch, weil Windows dir den dem Programm zugewiesenen Speicher mit Nullen
füllt. Ein anderes Betriebssystem könnte den Speicher auch m mit 0x12
füllen.
Fallobst schrieb:> Doch, weil Windows dir den dem Programm zugewiesenen Speicher mit Nullen> füllt
maximal bei ersten Speicher anfordern, Speicher den man selber
freigegeben hat bekommt man auch gefüllt wieder.
Frank schrieb:> zufällig funktionierts aber immer ohne dass irgendetwas hinterher kommt.> Vielleicht braucht das printf ja gar nicht, aber es muss es doch> brauchen, denn ein Leerzeichen gehört dann auch zum String, und ich kann> mir aber beim besten Willen nicht vorstellen, dass bei 15 mal von 15> Versuchen immer Leerzeichen und \0 im Speicher steht!
Meine Güte, ja du hast Recht, alle C-Bücher sind falsch, und man
braucht eine 0-Terminierung. Bist du jetzt glücklich?
Man könnte es auch anders formulieren: Nicht die Notwendigkeit der
Terminierung ist falsch, sondern das ganze Konzept dieser Terminierung,
also der Darstellung von Strings, ist grottenfalsch und eine stete
Quelle von Exploits in Programmen aller Art.
A. K. schrieb:> Man könnte es auch anders formulieren: Nicht die Notwendigkeit der> Terminierung ist falsch, sondern das ganze Konzept dieser Terminierung ...
Was erwartest du von einer Programmiersprache aus den 70er Jahren des
vorigen Jahrtausends. ;-)
A. K. schrieb:> sondern das ganze Konzept dieser Terminierung,> also der Darstellung von Strings, ist grottenfalsch
Also bräuchtest Du Strings, die ihre Länge mit sich transportieren, was
die Verarbeitung, wie z.B. das Anhängen verkomplizieren.
Ein strcat wird ohne Umkopieren des Zielstrings nur schwer
implementierbar sein.
Das Problem ist nicht die Stringrepräsentation, das Problem sind die
nach wie vor vorhandenen Stringverarbeitungsfunktionen, die ohne
Längenangabe arbeiten, also strcpy, strcat, sprintf etc.
Diese Funktionen sollten "verboten" werden und durch ihre Komplemente
mit Längenangabe ersetzt werden, also strncpy, strncat, snprintf etc.
Mit Disziplin kann man das in den Griff bekommen, nur steht so etwas in
all den tollen "Tutorials" nicht drin, die von Anfängern gerne anstelle
von ernstgemeinten Büchern zu Hilfe gezogen werden.
C ist keine Anfängerprogrammiersprache. Den Anspruch hatte es auch nie.
Rufus Τ. Firefly schrieb:> Also bräuchtest Du Strings, die ihre Länge mit sich transportieren, was> die Verarbeitung, wie z.B. das Anhängen verkomplizieren.
Und die hardwarenahe Programmierung wie auf Mikrocontrollern oder in
Kerneln schwierig machen.
Wenn man "einfache" Strings will, nimmt man C++ oder Java oder...
Frank schrieb:> ich kann> mir aber beim besten Willen nicht vorstellen, dass bei 15 mal von 15> Versuchen immer Leerzeichen und \0 im Speicher steht!
Nun, vielleicht ist es in deinem Setup mit diesem Programm, diesem
Compiler und diesem Betriebssystem eben so dass tatsächlich immer 0 da
steht. Wenn du also niemals irgendetwas (wie zB dein Programm) änderst,
könntest du die Terminierung weglassen. Aber dann musst du jedes Mal,
wenn du irgend etwas mit Strings programmierst, den Compiler updatest
oder gar das Programm auf einen anderen Computer kopierst, genau
überprüfen, ob das da immer noch zufällig genau so hinkommt. Einige
Programmierer tun das nicht, verlassen sich darauf dass es zufällig
immer passt, und das Resultat sind dann Dinge wie die Sicherheitslücken
im Adobe PDF-Reader und 900000 anderen Programmen.
Rufus Τ. Firefly schrieb:> Ein strcat wird ohne Umkopieren des Zielstrings nur schwer> implementierbar sein.
Na sicher geht das, es ist ja nicht so, dass es nicht schon Sprachen mit
Strings mit Laengenangabe gegeben haette. Die Frage ist eigentlich nur,
wie viele Bytes man fuer die Laengenangabe reservieren moechte. Da hat
es C eben einfacher.
Marwin schrieb:> Die Frage ist eigentlich nur,> wie viele Bytes man fuer die Laengenangabe reservieren moechte. Da hat> es C eben einfacher.
Dafür ist ein strlen() in C deutlich teurer was die Ausführzeit betrifft
als in anderen Sprachen.
In Pascal wiederum hatte man damals ein maximum von 255 Bytes für einen
String.
man könnte auch variabel lange ints nehmen (Ähnlich wie UTF-8 codierte
Zeichen.
In C ist halt dieses Konzept gewählt worden, mit allen seinen Vor und
Nachteilen. Es gibt keinen Königsweg.
Frank schrieb:> Wenn es wirkich notwendig wäre den String zu terminieren, dann würde> doch das hier nicht funktioniere und in eine endlosschleife enden> müssen:
Prima, damit hast du gezeigt daß du noch nicht viel verstanden hast und
besser ein C Buch lesen würdest.
Frank schrieb:> Wenn es wirkich notwendig wäre den String zu terminieren, dann würde> doch das hier nicht funktioniere und in eine endlosschleife enden> müssen:Dr. Sommer schrieb:> Frank schrieb:>> ich kann>> mir aber beim besten Willen nicht vorstellen, dass bei 15 mal von 15>> Versuchen immer Leerzeichen und \0 im Speicher steht!> Nun, vielleicht ist es in deinem Setup mit diesem Programm, diesem> Compiler und diesem Betriebssystem eben so dass tatsächlich immer 0 da> steht.
Ich will Euch ja nicht mit Realitäten langweilen, aber der ANSI-Standard
für C ist da eindeutig zum Thema strncpy (hab leider nur den Draft hier
rumliegen, sry):
"7.21.2.4 The strncpy function
Synopsis
#include <string.h>
char *strncpy(char * restrict s1,
const char * restrict s2,
size_t n);
Description
The strncpy function copies not more than n characters (characters that
follow a null character are not copied) from the array pointed to by s2
to the array pointed to by
If copying takes place between objects that overlap, the behavior is
undefined.
If the array pointed to by s2 is a string that is shorter than n
characters, null characters are appended to the copy in the array
pointed to by s1, until n characters in all have been written."
Quelle: "WG14/N1336 Committee Draft — August 11, 2008 ISO/IEC
9899:201x", Pg 326-327
Beachtet den letzten Absatz.
Mit anderen Worten, im Beispiel des TE (zwei Zeichen werden in einen
drei Zeichen langen String kopiert) padded strncpy mit '\0'.
Schönes Wochenende
Grüße
Andreas
Andreas H. schrieb:> Mit anderen Worten, im Beispiel des TE (zwei Zeichen werden in einen> drei Zeichen langen String kopiert) padded strncpy mit '\0'.
Ich würde mal sagen: umgekehrt. Wenn ich mehr Zeichen kopieren will, als
der Ausgangsstring hergibt, dann wird der Rest mit Nullen aufgefüllt.
Andreas H. schrieb:> Beachtet den letzten Absatz.>> Mit anderen Worten, im Beispiel des TE (zwei Zeichen werden in einen> drei Zeichen langen String kopiert) padded strncpy mit '\0'.
Quatsch. MAX-1 erlaubt strncpy() explizit nur das Schreiben von zwei
Zeichen (für MAX = 3). Woher soll strncpy() denn auch sonst die
Information nehmen, bis wo es padden soll?
Ralf G. schrieb:> Ich würde mal sagen: umgekehrt. Wenn ich mehr Zeichen kopieren will, als> der Ausgangsstring hergibt, dann wird der Rest mit Nullen aufgefüllt.
Ups, hast recht.
Sry 4 te noise ;-)
Grüße
Andreas
Frank schrieb:> Hans schrieb:>> Netter Trollversuch, aber wo siehst du da eine Endlosschleife?>> Im printf. Bei %s versucht doch printf solange auszugeben bis \0 kommt,
Ja.
> und das kommt ja nicht vor
Das weißt du nicht, das vermutest du nur.
Ich tippe mal darauf, daß deine Laufzeitumgebung das char Array
vorname mit \0 initialisiert, was es zwar darf aber nicht zwingend
muß. Und weil du mit strncpy() nur die ersten beiden Zeichen
überschreibst, hast du am Ende dann doch wieder einen 0-terminierten
String. Und deswegen läuft printf() dann auch nicht Amok.
Das blöde ist, daß dir der C-Standard dieses Verhalten nicht
garantiert. Das kann also mit einem anderen Compiler oder auf einer
anderen Plattform in die Hose gehen. Dein Code ist also auf die bösest
mögliche Art fehlerhaft und ich hoffe ernsthaft, daß du niemals
solchen Code absichtlich (v)erbrichst.
XL
Andreas H. schrieb:> Ich will Euch ja nicht mit Realitäten langweilen, aber der ANSI-Standard> für C ist da eindeutig zum Thema strncpy> The strncpy function copies not more than n characters
Tolle Diskussion, aber eigentlich gibt es nur eine Antwort - Andreas H.
hat Recht.
A. K. schrieb:> Man könnte es auch anders formulieren: Nicht die Notwendigkeit der> Terminierung ist falsch, sondern das ganze Konzept dieser Terminierung,> also der Darstellung von Strings, ist grottenfalsch
Das ist zunächst mal Ansichtssache. Von den beiden offensichtlichen
Arten, Strings im Speicher zu repräsentieren, hat C sich für eine
Ende-Markierung entschieden (und Pascal für ein Längenbyte). Jede der
beiden Varianten hat Vor- und Nachteile. Ach ja, Pascal ist tot.
C nicht so.
> und eine stete Quelle von Exploits in Programmen aller Art.
Die sind aber weniger der Programmiersprache anzulasten als dem
Programmierer^H^Hlegastheniker. Wenn der Handwerker mit einem Werkzeug
schlechte Resultate erzielt, ist nicht automatisch das Werkzeug Schuld.
Und falls ein Programmierer zu faul sein sollte, sich immer um die
Terminierung zu kümmern, dann hindert ihn ja keiner daran, seine eigene,
bequemere String-Repräsentation zu verwenden und nur dort wo es nötig
ist (im wesentlichen für calls in die stdlib) auf C-Strings zu wechseln.
Huch, ist ja schon passiert. C++ und std::string anyone?
XL
Axel Schwenke schrieb:> A. K. schrieb:>> Man könnte es auch anders formulieren: Nicht die Notwendigkeit der>> Terminierung ist falsch, sondern das ganze Konzept dieser Terminierung,>> also der Darstellung von Strings, ist grottenfalsch>> Das ist zunächst mal Ansichtssache. Von den beiden offensichtlichen> Arten, Strings im Speicher zu repräsentieren, hat C sich für eine> Ende-Markierung entschieden (und Pascal für ein Längenbyte). Jede der> beiden Varianten hat Vor- und Nachteile. Ach ja, Pascal ist tot.> C nicht so.
Auf der anderen Seite scheint es mir aber, als ob die Pascal-Variante in
anderen Sprachen deutlich häufiger zu finden ist - allerdings meist
hinter einen Interface versteckt, so daß man es als Programmierer gar
nicht sieht.
>> und eine stete Quelle von Exploits in Programmen aller Art.>> Die sind aber weniger der Programmiersprache anzulasten als dem> Programmierer^H^Hlegastheniker. Wenn der Handwerker mit einem Werkzeug> schlechte Resultate erzielt, ist nicht automatisch das Werkzeug Schuld.
So sehen es aber die meisten heutzutage. Deshalb ist ja auch der
Mikrowellen-Hersteller schuld am Ableben des Schoßhündchens, wenn der
Benutzer so dämlich ist, es darin trocknen zu wollen. Und McDonad's ist
schuld, wenn sich jemand verbrüht, da er ja nicht ahnen kann, daß sein
gerade bestellter Kaffee heiß ist.
Und wenn jemand sich nicht um Array-Längen und korrekt terminierte
Strings kümmert, ist die Programmiersprache schuld.
Fakt ist: Wenn man ein technisches Produkt auf den Markt bringt und
nicht schuld am Zusammenbrechen der Welt wie wir sich kennenen sein
will, muß man alles unter der Annahme entwickeln, daß der Benutzer zu
blöd zum Sch* ist.
Fakt ist, man braucht eine Sprache, die keine versteckten Längenbytes
bei Strings&Arrays hat, sondern nur ganz dumm genau das tut was man
schreibt; gerade im Embedded-Bereich ist das sehr wichtig. Diese Sprache
heißt eben C. Das wird in C auch niemals geändert, denn dann wäre C
nicht mehr für so etwas geeignet, und man bräuchte eine neue Sprache...
Wenn man automatische Längenverwaltung in Strings haben möchte, sollte
man eine andere Sprache verwenden.
Werkzeug-Analogie: Wenn man die Kraft beim Schrauben nicht von Hand
aufbringen will, bastelt man keinen Motor an den Handbohrer, sondern
kauft sich eine richtige Bohrmaschine mit Motor...