• Das kreative Thema des Monats Oktober wird vor allem diejenigen unter Euch besonders ansprechen, denen Do-it-yourself quasi im Blut liegt. Zeigt uns Eure Improvisationskünste oder fotografiert, was andere Leute sich so im Alltag zusammengestrickt haben. --> Zum Mitmachen bitte hier klicken

[C Programmierung] Frage zu Stringlängen

Hammurapi

Macoun
Registriert
17.07.09
Beiträge
123
Hallo,

in meinem struct definiere ich:

Code:
	struct {						 
		char stringA[3]; 
		char stringB[3]; 
	} structA ;
	strcpy(structA.stringA, "abc");
	strcpy(structA.stringB, "def");

Wenn ich den struct per printf() darstellen will:

Code:
printf("%s%s", structA.stringA, structA.stringB);

Erscheint im promt:
$ abcdef

Soweit, so gut.

Rufe ich aber

Code:
printf("%s", structA.stringA);

auf erscheint die gleiche Ausgabe im promt. Was mache ich falsch???

Danke und Grüße!
 
Du berücksichtigst nicht, das C-Strings mit einem Null-Byte abgeschlossen werden. Für "abc" benötigst Du also vier Bytes Speicherplatz. Beim Kopieren von "def" in 'structA.stringB' überschreibst Du das abschließende Null-Byte von 'structA.stringA', weil das schon im ersten Byte von 'structA.stringB' steht. Erschwerend kommt hinzu, dass Du dabei auch über den Speicherplatz Deiner Struktur hinaus schreibst. Im günstigsten Fall veränderst du damit nur andere Daten Deines Programms, es kann dadurch aber auch zum Absturz des Programms kommen.

MacApple
 
  • Like
Reaktionen: weasel77
Code:
struct {						 
		char stringA[4]; 
		char stringB[4]; 
	} structA ;
	strcpy(structA.stringA, "abc\0");
	strcpy(structA.stringB, "def\0");

wäre also die Ideallösung. Ich weiß, dass unter Mac OS X das Setzen des Null-Bytes nicht nötig ist, jedoch ist das Verhalten hier unter Windows und Linux anders, so dass auch beim letzten Funktionsaufruf etwas wie:
abc$def?mdA;_DSF
rauskommen könnte. Was hier aber nicht passieren würde, da du dich nicht im Heap befindest.
 
Ja richtig! Danke, das hat mir gut geholfen. Da muss ich jetzt einiges an Code ändern ;)

Ach ja, noch was:

wenn ich sage

char char1 = 'K';

brauche ich den Null-Byte nicht, oder?
 
genau, weil du nur einen Buchstaben speicherst.

aber bedenke:

char test[1] = "K"; // compiler fehler
char test[2] = "K"; //geht

hier wird das NULL-Byte automatisch hinzugefügt, also braucht man auch ein array der Länge: Stringlänge + 1
 
ähh.. muss ich den normalen char auch mit der eckigen Klammer deklarieren? Ich dachte

char test = 'k';

reicht aus.

Oder müsste ich demnach

char test[2] = 'k';

deklarieren?
 
ähh.. muss ich den normalen char auch mit der eckigen Klammer deklarieren? Ich dachte

char test = 'k';

reicht aus.
Das reicht auch vollkommen aus, denn ein Zeichen in Hochkomma ist für den Compiler nur ein Byte. Ein Zeichen in Anführungszeichen ist für den Compiler ein C-String, also ein Array von Bytes mit abschließendem Null-Byte.

MacApple
 
Ich weiß, dass unter Mac OS X das Setzen des Null-Bytes nicht nötig ist, jedoch ist das Verhalten hier unter Windows und Linux anders
Ein anderes Verhalten unter Linux wäre ja echt 'n Ding. Findet man doch unter Linux üblicherweise auch den gcc Compiler vor.

MacApple
 
nicht unbedingt. Ich hatte Probleme mit Code wie folgenden:

Code:
char* test = new char[255];
char test2[5] = "test";
memcpy(test, test2, 4); // 5 wäre zwar richtiger, aber ich möchte ja das ungleiche Verhalten zeigen.

printf(test);
// output mac: "test"
// output linux: "testºø¡€“..." undefiniertes Verhalten

unter windows hatte ich noch ganz andere Probleme, was das anging. Mac OS X hat die Angewohnheit beim alloziieren von Speicher, alls mit NULL-Bytes zu überschreiben. Unter windows und Linux geschieht das meines Wissen nicht. Ich kann mich aber auch gerade irren.

Da dies nicht auf C-Strings zurückzuführen ist, sondern auf malloc, können hier wohl unterschiede zwischen Linux und mac os x auftauchen.
 
unter windows hatte ich noch ganz andere Probleme, was das anging. Mac OS X hat die Angewohnheit beim alloziieren von Speicher, alls mit NULL-Bytes zu überschreiben. Unter windows und Linux geschieht das meines Wissen nicht. Ich kann mich aber auch gerade irren.

Da dies nicht auf C-Strings zurückzuführen ist, sondern auf malloc, können hier wohl unterschiede zwischen Linux und mac os x auftauchen.

Das was Du oben schreibst ist eher C++ (new). Weder in C++ noch C ist definiert, dass ein via new/malloc angelegter Speicherbereich mit \0 aufgefüllt wird. In C wäre dann calloc die Funktion der Wahl, z.B.
Code:
char *s= calloc(255, sizeof(char))
.

Da das Verhalten eben nicht definiert ist, muss es nicht nur Unterschiede zwischen OS/X und Linux/Win geben, sondern es kann sogar welche zwischen Aufruf morgens und abends geben ;-) - eben einfach undefinert. Ein via " deklarierte String wird vom Compiler immer implizit mit \0 terminiert und der entsprechende Speicherbereich mit strlen(STRING) + 1 allokiert (egal ob C/C++).
 
ja okay, ich habe bisher nie reines C programmiert, sondern immer in Verbindung mit ObjC oder C++. Aber ich frage mich dann, warum ich unter Mac OS X auf dieses Problem nie gestoßen bin. Wahrscheinlich war es auch nur riesiges Glück.
 
nicht unbedingt. Ich hatte Probleme mit Code wie folgenden:

Code:
char* test = new char[255];
char test2[5] = "test";
memcpy(test, test2, 4); // 5 wäre zwar richtiger, aber ich möchte ja das ungleiche Verhalten zeigen.

printf(test);
// output mac: "test"
// output linux: "testºø¡€“..." undefiniertes Verhalten
Mit dem Code zeigst Du keineswegs ein ungleiches Verhalten des Compilers bei Stringliteralen. Du hattest behauptet, dass der Compiler für die zweite Zeile, je nach System, mal ein abschließendes Null-Byte erzeugt und mal nicht. Wenn du nun das fünfte Byte aber gar nicht mit kopierst, steht dann im Zielstring natürlich auch nicht das vom Compiler erzeugte Null-Byte. Die Beweiskraft ist also gleich null. Damit der Code Beweiskraft hat, musst Du schon das fünfte Byte mit kopieren und dann wirst Du unter Mac OS X, Windows und Linux das gleiche Ergebnis bekommen.

Da dies nicht auf C-Strings zurückzuführen ist, sondern auf malloc, können hier wohl unterschiede zwischen Linux und mac os x auftauchen.
malloc() hat mit Stringliteralen aber nichts zu tun. Stringliterale werden vom Compiler bereits beim Compilieren in Bytefolgen umgesetzt. malloc() allociert Speicher zur Laufzeit des Programms.

MacApple
 
Mit dem Code zeigst Du keineswegs ein ungleiches Verhalten des Compilers bei Stringliteralen. Du hattest behauptet, dass der Compiler für die zweite Zeile, je nach System, mal ein abschließendes Null-Byte erzeugt und mal nicht. Wenn du nun das fünfte Byte aber gar nicht mit kopierst, steht dann im Zielstring natürlich auch nicht das vom Compiler erzeugte Null-Byte. ...

Ich glaube es ging ihm auch eher darum, dass der String test unter OS X evtl. durch das new() bereits mit \0 initialisiert wäre - zufällig scheint das bei Ihm wohl so gewesen zu sein, aber wie schon oben gesagt, das ist eben undefiniert ...
 
naja, es geht halt eher darum, wie man den Speicher von OS bekommt. Wenn sich an bestimmte Gegebenheiten gewöhnt und man dann komisches Verhalten auf anderen Plattformen entdeckt, dann kann man gut wochenlang nach Fehlern suchen ;) Ich kenne da ganz gute Beispiele von undefiniertem Verhalten und die meisten sind überhaupt nicht trivial.
 
Ich glaube es ging ihm auch eher darum, dass der String test unter OS X evtl. durch das new() bereits mit \0 initialisiert wäre - zufällig scheint das bei Ihm wohl so gewesen zu sein, aber wie schon oben gesagt, das ist eben undefiniert ...
Ich weiß schon, worum es ihm mit seinem Codebeispiel ging. Das hatte aber nur nichts mit dem Verhalten von Compilern bei Stringliteralen zu tun, was der Ausgangspunkt der Diskussion war. Das sind einfach zwei verschiedene Themen.

MacApple