Forum: Compiler & IDEs String terminieren wirklich notwendig?


von Frank (Gast)


Lesenswert?

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:
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <string.h>
4
5
#define MAX 3
6
7
int main()
8
{
9
    char vorname[MAX];
10
    char vorname2[] = {"ABC"};
11
12
    strncpy(vorname, vorname2, MAX-1);
13
    printf("%s", vorname);
14
15
    return 0;
16
}

von Hans (Gast)


Lesenswert?

Netter Trollversuch, aber wo siehst du da eine Endlosschleife?

von Fallobst (Gast)


Lesenswert?

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.

von Frank (Gast)


Lesenswert?

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?

von Frank (Gast)


Lesenswert?

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!

von Bernd M. (bernd_m)


Lesenswert?

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.

von DirkB (Gast)


Lesenswert?

Lass doch mal das -1 weg.

von Fallobst (Gast)


Lesenswert?

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.

von Peter II (Gast)


Lesenswert?

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.

von Klaus (Gast)


Lesenswert?

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?

von luppu (Gast)


Lesenswert?

>Meine Güte, ja du hast Recht, alle C-Bücher sind falsch, und man
>braucht eine 0-Terminierung. Bist du jetzt glücklich?
Schlechte Laune ?

von (prx) A. K. (prx)


Lesenswert?

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.

von Mr. X (Gast)


Lesenswert?

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.  ;-)

von (prx) A. K. (prx)


Lesenswert?

Ganz so mittelalterlich ist sie dann doch nicht. ;-)

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

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.

von Doris (Gast)


Lesenswert?

1
strncpy(vorname, vorname2, MAX-1)[MAX-1] = '\0';

von Klaus (Gast)


Lesenswert?

Doris schrieb:
> strncpy(vorname, vorname2, MAX-1)[MAX-1] = '\0';

Teilnehmer des obfuscated c contest? =-O

von Marwin (Gast)


Lesenswert?

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.

von Udo S. (urschmitt)


Lesenswert?

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.

von Andreas H. (ahz)


Lesenswert?

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

von Ralf G. (ralg)


Lesenswert?

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.

von Malte S. (maltest)


Lesenswert?

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?

von Andreas H. (ahz)


Lesenswert?

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

von Axel S. (a-za-z0-9)


Lesenswert?

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

von CCC (Gast)


Lesenswert?

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.

von Axel S. (a-za-z0-9)


Lesenswert?

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

von Rolf M. (rmagnus)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

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...

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
Noch kein Account? Hier anmelden.