Prüfen auf Gleichheit

06/30/2016 16:01 NRj™#1
Kann mir jemand erklären warum zwei int's mit gleichem Wert als gleich angesehen werden aber zwei Zeichenketten mit gleichem Inhalt nicht?

Code:
int i1 = 1;
int i2 = 1;

char z1[] = "Hallo";
char z2[] = "Hallo";

if(i1 == i2) {
printf("i1 und i2 sind gleich\n"); }

if(z1 == z2) {
printf("z1 und z2 sind gleich\n"); }

else {
printf("z1 und z2 sind nicht gleich\n"); }
Ausgabe:
i1 und i2 sind gleich
z1 und z2 sind nicht gleich
06/30/2016 16:08 algernong#2
Zeichenketten sind Arrays, also Zeiger. Du vergleichst, ob z1 und z2 auf die selbe Speicherstelle zeigen.
Mich wundert es aber, dass die Speicherstellen in deinem Beispiel tatsächlich verschieden ist; eigentlich sollte der Compiler den selben statischen Text nur einmal im Speicher ablegen. Vermutlich ist das aber jedem Compiler frei überlassen?
Wenn der String aber nicht statisch ist, klappt das auf keinen Fall, da dann eben der selbe Text zweimal an verschiedenen Stellen im Speicher liegt. Mit strcmp() kannst du dann den Inhalt der beiden verschiedenen (und den nachfolgenden) Speicherstellen vergleichen.

Also als Beispiel, vielleicht sieht dein Speicher so aus:
Code:
z1                       z2
 V                        V 
|H|a|l|l|o|\0| | |b|a|0|1|H|a|l||l|o|\0
z1 und z2 zeigen auf verschiedene Stellen (--> z1 != z2), an beiden liegt aber der selbe String.

Deine int Variablen sind hingegen keine Zeiger, also wird hier nicht die Speicherstelle sondern direkt der Inhalt verglichen. Die Variante von den Strings würde also dem entsprechen:
Code:
int a1 = 1;
int a2 = 1;
int *p1 = &a1;
int *p2 = &a2;
if (p1 == p2) { ... } else { ... }
Dann vergleichst du wieder die Speicherstellen der Zahlen.
06/30/2016 16:23 NRj™#3
Danke für die super Erklärung! :)
Ich hätte noch eine Frage:
Angenommen man erstellt ein Array mit der Größe 5: char hallo[5] = "Hallo";
Hier finden alle Zeichen gerade so Platz. Doch wo findet das '\0' Platz, wenn das Array doch mit 5 Bytes eigentlich voll ist?
06/30/2016 16:43 algernong#4
Das '\0' wird in dem Fall dann einfach abgeschnitten. Wenn du das Array noch kleiner machst, wird der zu große Teil auch abgeschnitten (und der Compiler gibt eine Warnung aus).
Sowas kann dann natürlich zu ungewolltem Verhalten oder Speicherzugriffsfehler führen, wenn später ein '\0' am Ende erwartet wird (fast alle str* Funktionen erwarten das). Die Funktionen würden den String dann solange weiter ablaufen, bis irgendwann zufällig ein '\0' kommt; und wenn auf Speicher dazwischen aus irgendeinem Grund nicht zugegriffen werden darf, gibt es den Speicherzugriffsfehler.
06/30/2016 22:02 .Scy#5
grundsätzlich solltest du bei deinem Beispiel keine größe angeben, sprich 'char *hallo = "hallo";', da es sich um statischen text handelt kümmert der compiler sich um den Speicher. falls du aber variable größen hast, also z.b. irgend einen text einliest, so kannst und solltest du einfach einen pointer erstellen, sprich char *tmp; dort reinschreiben was du brauchst und nur wenn du das auch außerhalb der Funktion brauchst malloc aufrufen mit der passenden Größe. ein Beispiel:

Code:
void irgendwas(char *etwas){
char *buffer;
char *test = "test";
strcpy(buffer, etwas);
strcmp(buffer, test); //falls die Größe bekannt ist, strncmp nutzen
}
Code:
char *irgendwas(char *etwas){
char *buffer;
//vorausgesetzt, dass etwas ein String ist, also mit '\0' abgeschlossen
int length = strlen(etwas);
buffer = malloc(length*sizeof(char));
strcpy(buffer, etwas);

return buffer;
}
das Beispiel ist eher sinnlos, aber so siehst du mal ungefähr wie man in c mit so etwas umgehen kann. alle str Funktionen die String.h liefert fordern einen gültigen String, wenn du in strlen z.b. einfach ein char array rein gibst ohne '\0' oder mit mehreren '\0', dann stürzt entweder dein Programm ab oder du hast nicht den ganzen teil den du haben wolltest.

für allgemeines byte-kopieren o.ä. gibt es Funktionen wie memcmp, memncmp, memcpy, memncpy,... welche byteweise arbeiten und ignorieren was der Inhalt ist.
06/30/2016 23:15 algernong#6
Code:
buffer = malloc(length*sizeof(char));
Du hast das +1 für die \0 vergessen :P

Code:
char *test = "test";
Das ist dann aber etwas anderes. Hier zeigt test ins .rodata, bei einem
Code:
char test[5] = "test";
wird "test\0" auf dem Stack abgelegt und test zeigt entsprechend dort hin.

Folglich führt
Code:
test[0] = 'T';
bei deiner Variante zur Segfault, während das bei der zweiten Variante funktioniert.

"Grundstätzlich" würde ich also nicht sagen, das kommt eher darauf an, was er denn dann mit dem String machen möchte.