it-swarm.com.de

Konstante Zeiger können nicht in C freigegeben werden

Wie kann ich einen const char* freigeben? Ich habe mit malloc neuen Speicher zugewiesen, und wenn ich versuche, ihn freizugeben, erhalte ich immer den Fehler "inkompatibler Zeigertyp".

Der Code, der dies verursacht, ist ungefähr so:

char* name="Arnold";
const char* str=(const char*)malloc(strlen(name)+1);

free(str); // error here
58
lego69

Einige Leute haben die richtige Antwort gepostet, aber sie löschen sie aus irgendeinem Grund. Sie müssen es in einen nicht konstanten Zeiger umwandeln. free nimmt einen void*, nicht einen const void*:

free((char*)str);
74
Michael Mrozek

Ihr Code ist umgekehrt.

Diese:

char* name="Arnold";
const char* str=(const char*)malloc(strlen(name)+1);

Sollte so aussehen:

const char* name="Arnold";
char* str=(char*)malloc(strlen(name)+1);

Der Speichertyp const teilt dem Compiler mit, dass Sie keinen Speicherblock ändern möchten, der einmal zugewiesen wurde (dynamisch oder statisch). Das Freigeben von Speicher ändert dies. Beachten Sie, dass Sie nicht den Rückgabewert von malloc () setzen müssen, aber das ist nur eine Seite.

Es hat wenig Sinn, Speicher dynamisch zuzuweisen (was Sie tun, basierend auf der Länge von name) und dem Compiler mitzuteilen, dass Sie nicht beabsichtigen, ihn zu verwenden. Beachten Sie, dass bedeutet, dass Sie etwas darauf schreiben und es dann (optional) später freigeben.

Das Umwandeln in einen anderen Speichertyp behebt nicht die Tatsache, dass Sie die Speichertypen von Anfang an umgekehrt haben :) Es wird nur eine Warnung angezeigt, die versucht hat, Ihnen etwas zu sagen.

Wenn der Code umgekehrt ist (wie er sein sollte), funktioniert free() wie erwartet, da Sie den von Ihnen zugewiesenen Speicher tatsächlich ändern können .

23
Tim Post

Es macht keinen Sinn, einen Zeiger auf const zu malen, da Sie dessen Inhalt nicht ändern können (ohne hässliche Hacks).

FWIW gibt gcc jedoch nur eine Warnung für Folgendes aus:

//
// const.c
//

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    const char *p = malloc(100);

    free(p);
    return 0;
}

$ gcc -Wall const.c -o const
const.c: In function ‘main’:
const.c:8: warning: passing argument 1 of ‘free’ discards qualifiers from pointer target type
$ 

Welchen Compiler verwenden Sie?

6
Paul R

Es gibt Fälle, in denen Sie einen const* freigeben möchten. Sie möchten dies jedoch nur tun, wenn Sie es in derselben Funktion zuordnen. Sonst wirst du wahrscheinlich Dinge kaputt machen. In dem folgenden Code finden Sie ein Beispiel aus der Praxis. Ich verwende const in den Funktionsdeklarationen, um zu zeigen, dass ich den Inhalt der Argumente nicht ändere. Es ist jedoch neu zugewiesen mit einem Duplikat mit niedrigerer Nummer (strdup), das freigegeben werden muss.

char* tolowerstring(const char *to_lower)
{
    char* workstring = strdup(to_lower);
    for(;workstring != '\0'; workstring++)
        *workstring = tolower(workstring);
    return workstring;
}

int extension_checker(const char* extension, const char* to_check)
{
    char* tail = tolowerstring(to_check);
    extension = tolowerstring(extension);

    while ( (tail = strstr( tail+1, extension)) ) { /* The +1 prevents infinite loop on multiple matches */
        if ( (*extension != '.' ) && ( tail[-1] != '.'))
            continue;
        if ( tail[strlen(extension)] == '\0') {
            free(tail);
            free( (char*) extension);
            return 1;
        }
    }
    free(tail);
    free( (char *) extension);
    return 0;
}
4
nlstd

Es gibt keinen Zweck, einen malloc'd-Zeiger auf const zu werfen. Jede Funktion, die einen const-Zeiger verwendet, sollte nicht für die Freigabe des an sie übergebenen Speichers verantwortlich sein.

3
Puppy

Mehrere Antworten haben vorgeschlagen, einfach zu char* zu wechseln. Aber wie el.pescado oben schrieb, 

const in Nicht-const umzuwandeln ist ein Symptom für Codegeruch.

Es gibt Compiler-Warnungen, die sich dagegen schützen, wie -Wcast-qual in gcc, was ich sehr nützlich finde. Wenn Sie wirklich einen gültigen Fall haben, um einen const-Zeiger freizugeben (im Gegensatz zu dem, was viele hier geschrieben haben sind - gültige Fälle, wie von nlstd ausgeführt), könnten Sie ein Makro für diesen Zweck definieren diese:

#define free_const(x) free((void*)(long)(x))

Dies funktioniert zumindest für gcc. Der Double Cast bewirkt, dass die Logik -Wcast-qual dies nicht als "Cast const" erkennt. Es ist unnötig zu erwähnen, dass dieses Makro mit Vorsicht verwendet werden sollte. Eigentlich sollte es nur für Zeiger verwendet werden, die der gleichen Funktion zugeordnet sind.

1
uncleremus

Ich könnte falsch sein, aber ich denke, das Problem liegt in const. Wende den Zeiger auf non-const wie folgt an:

free((char *) p);

Denn mit const sagen Sie: Ändern Sie nicht die Daten, die dieser Zeiger auf zeigt.

1
Felix Kling

Wenn Sie von reinem C sprechen und die Speicherzuordnung vollständig steuern, können Sie den folgenden Trick verwenden, um (const char *) in (char *) umzuwandeln, wodurch Sie keine Warnung im Compiler erhalten:

const char *const_str = (const char *)malloc(...);
char *str = NULL;

union {
  char *mutable_field_p;
  const char *const_field_p;
} u;

u.const_field_p = const_str;
str = u.mutable_field_p;

Jetzt können Sie free (str) verwenden. den Speicher freigeben.

BEACHTEN Sie jedoch, dass dies über die Worte hinaus böse ist und nur in streng kontrollierten Umgebungen verwendet werden sollte (z. B. Bibliothek, die Zeichenfolgen zuordnet und freigibt, die Benutzer jedoch nicht zulassen möchten, dass sie geändert werden) Kompilierzeit "STRING" zu deiner freien Funktion.

0
MMasterSK

Ich denke, die wirkliche Antwort ist, dass free ein const-Zeigerargument und NULL als const-Zeiger definieren sollte. Dies scheint ein Fehler in den Standards zu sein. Das Freigeben eines const-Zeigers sollte wie folgt implementiert werden:

free(p);
p = NULL;

Ich sehe nicht, wie ein Compiler in diesem Fall einen falschen Code generieren könnte, der const-Zeiger p ist nicht mehr zugänglich, daher ist es egal, ob das Objekt, auf das er gezeigt hat, const ist, gültig, was auch immer. Es ist const, daher dürfen keine schmutzigen Kopien in Registern oder anderswo sein. Es ist gültig, einen const-Zeiger auf einen anderen Wert zu setzen, und die Tatsache, dass dieser Wert NULL ist, spielt keine Rolle, da auf den vorherigen Wert nicht mehr zugegriffen werden kann.

0
free

Sie können const char * nicht freigeben, da es const ist. Speichern Sie Zeiger, die von malloc empfangen wurden, in nicht-konstanten Zeigervariablen, damit Sie sie an free übergeben können. Sie können char *-Argumente an Funktionen übergeben, die const char *-Argumente verwenden. Das Gegenteil ist jedoch nicht immer wahr.

void foo (const char *x);
char *ptr = malloc (...);
foo (ptr);
free (ptr);
0
el.pescado