C sprintf-Array-Zeichenzeiger

Lesezeit: 5 Minuten

Benutzer-Avatar
Benutzer2953313

Kann mir jemand sagen was ich hier falsch mache? Warum segfault mein Programm? Ich versuche, eine dritte Saite dazwischen einzufügen string1 und string2.

#include <stdio.h>

int main (void) 
{
char *string1 = "HELLO";
char *string2 = "WORLD";
char *stringX  = "++++";
char *string3;
printf ("%s,%s\n",string1,string2);
sprintf(string3,"%s%s%s",string1,stringX,string2);
printf ("NewVar: %s",string3);
}

Warum nicht sprintf speichere den resultierenden Wert an der Speicheradresse, auf die gezeigt wird string3? Es funktioniert, wenn ich deklariere string3 als gewöhnliches Array, aber nicht, wenn es ein Zeiger darauf ist char Reihe.

ich dachte string3 zeigte nicht auf einen Speicherort, aber es scheint, wenn ich es tue printf("%p",string3);

Ausgabe:

# ./concat
HELLO,WORLD,0x40042

  • nur als hinweis: wohin sollen die daten geschrieben werden? Wohin deutet Ihrer Meinung nach der Zeiger?

    – glglgl

    4. November 2013 um 16:49 Uhr

  • @glglgl – Ich dachte, string3 würde auf nichts zeigen, aber wenn ich printf (“% p”, string3) mache, scheint es auf einen Speicherort zu verweisen.

    – Benutzer2953313

    4. November 2013 um 16:59 Uhr


  • Aber zu einem unbestimmten…

    – glglgl

    4. November 2013 um 18:46 Uhr

  • @ user2953313: Von welcher Speicheradresse sprichst du? string3 zeigt nicht auf eine sinnvolle Speicheradresse. Ihr Wert ist unbestimmt und technisch überhaupt keine Speicheradresse. Es mag „scheinen“, auf „einen Ort der Erinnerung“ zu verweisen, aber in Wirklichkeit ist dies nur eine Illusion – eine Folge undefinierten Verhaltens.

    – AnT steht zu Russland

    8. März 2016 um 0:57 Uhr


Benutzer-Avatar
Bischof

Stellen Sie sich vor, Sie haben einen Haufen Bargeld, den Sie in eine Aktentasche stecken möchten. Was brauchen Sie? Sie müssen die Größe des Bargelds messen, um zu wissen, wie groß eine Aktentasche ist, und Sie benötigen einen Griff, um das Bargeld bequem herumzutragen.

Das Geld sind Ihre Fäden. Die Aktentasche ist Erinnerungsraum. Der Griff der Aktentasche ist der Zeiger.

  1. Messen Sie Ihr Bargeld: strlen(string1) + strlen(string2) + strlen(stringX). Nennen Sie dies “gesamt”.
  2. Holen Sie sich jetzt eine ausreichend große Aktentasche: malloc(total+1)
  3. Und mach einen Griff drauf: string3

Das alles zusammen basteln…

char *string3 = malloc(strlen(string1)+strlen(stringX)+strlen(string2)+1);
sprintf(string3, "%s%s%s", string1, stringX, string2);

Was war also beim ersten Versuch falsch? Sie hatten keine Aktentasche. Sie haben Bargeld und einen Griff, aber keine Aktentasche in der Mitte. Es schien auf eine zufällige Weise zu funktionieren, weil der Compiler Ihnen einen schmutzigen Müllcontainer gegeben hat, um das Geld aufzubewahren. Manchmal hat der Müllcontainer Platz, manchmal nicht. Wenn dies nicht der Fall ist, nennen wir das “Segmentierungsfehler”.

Wann immer Sie Daten haben, müssen Sie Speicherplatz für diese Daten zuweisen. Der Compiler weist Platz für Ihre konstanten Zeichenfolgen zu, wie z "HELLO". Aber Sie müssen Platz für Strings zuweisen, die zur Laufzeit erstellt werden.

  • string3 zeigt nicht auf einen beschreibbaren Speicher. Die Größe von char* ist hier nicht relevant – sprintf werde versuchen, wohin zu schreiben string3 zeigt, wird nicht versucht, in den Zeiger selbst zu schreiben.

    – Simonc

    4. November 2013 um 16:53 Uhr

  • Hallo Leute, vielen Dank für Ihre Erklärung. Wenn ich string3 mit % p drucke, warum zeigt es auf einen Speicherort? Wenn es gemäß den Kommentaren oben nicht sein sollte. Ich habe meinen Code bearbeitet, um dies hervorzuheben.

    – Benutzer2953313

    4. November 2013 um 17:08 Uhr

  • @ user2953313 C initialisiert Ihre Variablen nicht auf einen bestimmten Wert. Die Adresse, auf die gezeigt wird, ist nicht garantiert, aber es ist wahrscheinlich, was auch immer zuvor in diesen Stapelspeicherort geschrieben wurde. Der Versuch, einen nicht initialisierten Zeiger zu dereferenzieren, führt zu undefiniertem Verhalten. Manchmal stürzt es ab; In anderen Fällen scheint es zu funktionieren.

    – Simonc

    4. November 2013 um 17:19 Uhr

  • @user2953313 Um die Initialisierung zu erhalten, verwenden Sie calloc() anstelle von malloc. Wenn ich das in meine Analogie einarbeite, ist es der Unterschied zwischen einer gebrauchten und schmutzigen Aktentasche (malloc) oder einer neuen und sauberen Aktentasche (calloc). Ich beginne mit calloc, wenn Leistung ein Problem ist und Sauberkeit nicht, wechsle ich zu malloc.

    – Bischof

    4. November 2013 um 19:34 Uhr

  • Was wäre wenn string1 und string2 ist kein stringaber ein int, zum Beispiel? Sie können die Länge der Nummer nicht bestimmen.

    – Schmied

    19. Februar 2021 um 19:35 Uhr

Benutzer-Avatar
che

sprintf speichert den Wert dort. Das Problem ist, dass der Zeiger string3 einen nicht initialisierten Wert hat, Sie also nur den zufälligen Speicher überschreiben.

Eine Option, die Sie haben, ist die Verwendung eines statischen Zeichenfolgenpuffers:

char string3[20];
snprintf(string3, sizeof(string3), "Hello!");

Oder Sie können verwenden asprintf auf GNU libc-basierten Systemen, um den richtigen Speicherplatz automatisch zuzuweisen:

char * string3;
asprintf(&string3, "Hello!");
// ... after use
free(string3); // free the allocated memory

  • Ihr asprintf-Beispiel ist falsch – string3 sollte char * nicht char sein. Es könnte auch erwähnenswert sein, dass asprintf keine Standard-C-Funktion ist (oder ich denke sogar Posix).

    – Nigel Harper

    4. November 2013 um 18:25 Uhr

  • @NigelHarper: Danke, behoben. asprintf ist eine GNU-Erweiterung, das sei auch angemerkt.

    – che

    4. November 2013 um 23:23 Uhr

Benutzer-Avatar
Simonc

sprintf reserviert keinen Speicher für die Zeichenfolge, die es schreibt. Sie müssen eine gültige Zeichenfolge angeben, in die geschrieben werden kann, übergeben ihr jedoch derzeit einen nicht initialisierten Zeiger.

Die einfachste Lösung ist zu ändern

char *string3;
sprintf(string3,"%s%s%s",string1,stringX,string2);

zu

char string3[200];
sprintf(string3,"%s%s%s",string1,stringX,string2);

Möglicherweise möchten Sie sich in diesem Fall vor Pufferüberläufen schützen, indem Sie verwenden snprintf stattdessen

char string3[200];
snprintf(string3,sizeof(string3),"%s%s%s",string1,stringX,string2);

Alternativ könnten Sie auch mit größeren Längen des Quellstrings fertig werden, indem Sie die Größe von bestimmen string3 zur Laufzeit, darauf achten free diese Erinnerung, wenn Sie damit fertig sind.

char* string3 = malloc(strlen(string1) + strlen(stringX) + strlen(string2) + 1);
if (string3 == NULL) {
    // handle out of memory
}
sprintf(string3,"%s%s%s",string1,stringX,string2);
...
free(string3);

  • danke für die Antwort mit malloc.ist das +1 für das Nullzeichen?

    – Benutzer2953313

    4. November 2013 um 17:14 Uhr

  • @ user2953313 Freut mich, dass es geholfen hat. Ja, das +1 ist für das Null-Terminator

    – Simonc

    4. November 2013 um 17:15 Uhr

Sie müssen Speicherplatz zuweisen string3 entweder mit malloc wenn Sie es auf dem Heap benötigen, oder deklarieren Sie es als Zeichenarray, wenn Sie dies nicht tun.

Benutzer-Avatar
hr.mousavi

Angenommen, Sie definieren i wie int i; In diesem Level sagst du, dass ich speichern werde integer number aber da ist noch keine aussagekräftige nummer drin i Variable. so, wenn Sie definieren char *string3 das sagst du string3 speichert den Zeichenzeiger, aber es gibt immer noch keine sinnvolle Adresse. Sie müssen dieser Variablen also Speicher zuweisen

string3 =  malloc(strlen(string1)+strlen(stringX)+strlen(string2)+1);

1143720cookie-checkC sprintf-Array-Zeichenzeiger

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy