String terminieren wirklich notwendig?

Gast #3147946
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
}
Gast #3147954
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.
Gast #3147955
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?
Gast #3147959
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!
Gast #3148245
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?
Persönliche Seite #3148328
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.
Gast #3148340
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.
Gast #3151229
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.
#3151254
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.
#3151282
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
#3151693
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
#3151708
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
#3151983
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.
Gast #3152051
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...

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren