3 Stimmen

Wie verwandle ich ein const char*, das von einer Funktion zurückgegeben wird, richtig in ein const char** in C?

Kurz gesagt, ich möchte dies tun:

const char **stringPtr = &getString();

Allerdings verstehe ich, dass Sie nicht & auf rvalues. So bin ich mit diesem stecken:

const char *string = getString();
const char **stringPtr = &string;

Ich kann mit zwei Zeilen leben. Bringe ich mit diesem Hack Probleme mit sich? Ich sollte keine Angst haben, dass ich stringPtr aus der Funktion heraus, in der sie deklariert ist, richtig?

Edit: Ich entschuldige mich dafür, dass ich ursprünglich nicht den vollständigen Kontext angegeben habe. Ich habe das Sommerprojekt übernommen, ein Videospiel von Grund auf in C unter Verwendung von OpenGL für die Grafik zu entwickeln. Ich lese Konfigurationsdaten aus einer Textdatei mit libconfig .

Eine der Komfortfunktionen zum Auffinden einer bestimmten Zeichenfolge in Ihrer Konfigurationsdatei sieht folgendermaßen aus:

int config_setting_lookup_string(const config_setting_t *setting,
                                 const char *name, const char **value)
{
  config_setting_t *member = config_setting_get_member(setting, name);
  if(! member)
    return(CONFIG_FALSE);

  if(config_setting_type(member) != CONFIG_TYPE_STRING)
    return(CONFIG_FALSE);

  *value = config_setting_get_string(member);
  return(CONFIG_TRUE);
}

Die Art und Weise, wie dieser Wert zugewiesen wird, bedeutet, dass, wenn Sie der Funktion einen nicht-initialisierten value versucht es, undefinierten Müll zu derefenzieren, was bei mir so ziemlich immer einen Segfault verursacht. Mein derzeitiger Workaround für dieses Problem ist die Initialisierung von value zuerst auf einen anderen Zeiger, etwa so:

const char *dummyPtr;
const char **fileName = &dummyPtr;
config_setting_lookup_string(foo, "bar", fileName);

Ich versuche also herauszufinden, wie ich den letzten Teil der Funktion am besten umschreiben kann, so dass ich diese zweistufige Initialisierung nicht mehr durchführen muss. Ich habe gedacht, dass die geänderte Funktion wie folgt aussehen würde:

int config_setting_lookup_string(const config_setting_t *setting,
                                 const char *name, const char **value)
{
  config_setting_t *member = config_setting_get_member(setting, name);
  if(! member)
    return(CONFIG_FALSE);

  if(config_setting_type(member) != CONFIG_TYPE_STRING)
    return(CONFIG_FALSE);

  const char *string = config_setting_get_string(member);
  value = &string;
  return(CONFIG_TRUE);
}

3voto

nornagon Punkte 14659

Wenn Sie eine Funktion aufrufen, die eine const char** könnte man es so machen:

const char *s = getString();
myFunction(&s);

Seit s im obigen Beispiel auf dem Stack zugewiesen wird, wenn Sie eine const char** aus Ihrer Funktion zu entfernen, müssen Sie sie stattdessen auf den Heap legen:

const char **sp = malloc(sizeof(const char *));
*sp = getString();
return sp;

HTH

1voto

Chris Schmich Punkte 28452

string in Ihrem Fall ist eine lokale, so dass die Adresse der es ist eine schlechte Idee, da der Speicher für die lokale kann (und wird wahrscheinlich) für andere Zwecke wiederverwendet werden, wenn Sie die Methode verlassen. Im Allgemeinen ist es keine gute Idee, die Adresse einer lokalen Variable außerhalb ihres Bereichs zu verwenden.

Was wollen Sie erreichen?

1voto

caf Punkte 224189

Nein, Sie können nicht ändern config_setting_lookup_string() auf die von Ihnen beschriebene Weise. Sie geben einen Zeiger auf den string Variable, aber sobald die Funktion endet, geht diese Variable aus dem Anwendungsbereich heraus und wird zerstört.

Sie können Ihr ursprüngliches Problem jedoch ganz einfach lösen. Lassen Sie die Definition von config_setting_lookup_string() wie es ist, und nennen Sie es so:

const char *fileName = NULL;
config_setting_lookup_string(foo, "bar", &fileName);

0voto

amrinder Punkte 208

Sie benötigen die beiden Zeilen. Allerdings ist string eine lokale Variable auf dem Stack. Sobald sie den Anwendungsbereich verlässt, haben Sie möglicherweise keinen Zeiger auf die von getString() zurückgegebenen Daten.

0voto

jamesdlin Punkte 63159

Wenn Sie zurückkehren stringPtr geben Sie einen Zeiger auf eine lokale Variable zurück ( string ). Also nein, das geht nicht.

Warum wollen Sie das tun? Dann können wir Ihnen vielleicht bessere Vorschläge machen.

Aktualisierung: Okay, jetzt verstehe ich, was du vorhast. Sie machen es falsch:

value = &string;

Si value als Ausgabeparameter gemeint ist, kann die obige Zeile nicht funktionieren, weil Sie Zuweisung an eine lokale Variable .

Lassen Sie sich durch die zusätzliche Ebene der Indirektion nicht verwirren. Wenn Sie eine Funktion schreiben würden, die einen Ausgabeparameter vom Typ T würden Sie es so schreiben:

void foo(T* value)
{
    *value = GetT();
}

Jetzt ersetzen T mit const char* :

...
*value = string;
...

Und jetzt werden keine temporären, lokalen Variablen verwendet. Natürlich war der Code ursprünglich so geschrieben (und dieser Teil davon war korrekt), also hilft Ihnen das nicht wirklich weiter. Um Ihre Absicht anzusprechen, sollten Sie:

  1. Machen Sie config_setting_lookup_string tun assert(value != NULL) .
  2. Überprüfen Sie die Aufrufer der Funktion und bringen Sie sie dazu, keinen Müll mehr zu übergeben. Das sollten sie tun:

    const char* foo; config_setting_lookup_string(..., &foo);

und NICHT:

const char** foo;
config_setting_lookup_string(..., foo);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X