Konstante Zeiger in C können nicht freigegeben werden

Lesezeit: 11 Minuten

Benutzeravatar von lego69
lego69

Wie kann ich a const char*? Ich habe neuen Speicher mit zugewiesen mallocund wenn ich versuche, es zu befreien, erhalte ich immer den Fehler “Inkompatibler Zeigertyp”.

Der Code, der dies verursacht, ist etwa so:

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

free(str); // error here

  • Gibt es einen bestimmten Grund, warum Sie es so machen müssen? Normalerweise kennen Sie String-Konstanten im Voraus, daher erscheint es seltsam, Speicherplatz für eine String-Konstante dynamisch zuzuweisen.

    – James Kingsbery

    12. Mai 2010 um 14:20 Uhr

  • Im Grunde ein C-Sprachproblem. Die Signatur von free() hätte lauten sollen void free(const void* p);. Behoben in C++ (mit delete)

    – MSalter

    12. Mai 2010 um 14:26 Uhr

  • @James Kingsbery: Internierte Zeichenfolgen, vielleicht: Sobald Sie Ihren Zeichenpuffer anfänglich gefüllt haben, ist es sinnvoll, ihn danach als zu behandeln const char*. Brauchen Fragesteller wirklich unsere Erlaubnis, um Probleme zu haben? 😉

    – Steve Jessop

    12. Mai 2010 um 15:16 Uhr


  • Es macht jedoch überhaupt keinen Sinn. Sobald der Speicher zugewiesen ist stres ist unmöglich, es durch zu ändern strwas bedeutet, dass es dauerhaft ist, was wann im Speicher war malloc() packte es. Es ist nicht möglich, den Namen ohne Casting zu kopieren str. (Auch das Zuweisen eines Zeichenfolgenliterals zu a char * ist nicht gut, da der Versuch, ein Zeichenfolgenliteral zu ändern, ein undefiniertes Verhalten ist. Ich glaube, du hast gerade deine bekommen constist verwechselt.)

    – David Thornley

    12. Mai 2010 um 15:32 Uhr

  • @DavidThornley: Die const char * Sie erhalten möglicherweise eine Konvertierung von char * nachdem der Inhalt gefüllt ist; zB von const char* foo() { char* s = malloc(...); strcpy(s, ...); return s; }.

    – musiphil

    7. März 2014 um 1:06 Uhr

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

free((char*)str);

  • Es wird funktionieren, aber Gießen const to non-const ist ein Symptom für Code Smell.

    – el.pescado – нет войне

    12. Mai 2010 um 14:17 Uhr

  • @el. free() ist so etwas wie eine Ausnahme, da Sie vielleicht nicht möchten, dass der Zeiger während seiner Lebensdauer geändert wird, Sie ihn aber am Ende trotzdem freigeben möchten

    – Michael Mrozek

    12. Mai 2010 um 14:20 Uhr

  • Warum die Umwandlung in char * ? warum nicht direkt free((void *) str) ?

    – Philant

    12. Mai 2010 um 14:30 Uhr

  • Ich erinnere mich, dass ich im Linux-Kernel über eine Speicherfreigabefunktion gelesen habe, die einen const-Zeiger verwendet hat, und jemand hat Linus gefragt, warum, und er hat es verteidigt, indem es gesagt hat, dass es den Wert, auf den gezeigt wird, weder konzeptionell noch in der Praxis tatsächlich ändert, es sieht nur so aus den Speicherblock mit dem Zeiger nach oben und hebt die Zuordnung auf. Ich schließe mich seiner Einschätzung an und sehe daher die Spezifikation der Funktion free() als falsch an. Aber leider ist es der Standard.

    – rméador

    12. Mai 2010 um 15:48 Uhr

  • Wenn „Befreien“ sich konzeptionell geändert hat, ist es in Ordnung, a zu deklarieren const int und dann den Geltungsbereich verlassen, in dem es deklariert wurde? Das “befreit” die automatische Variable in dem Sinne, dass die Ressource freigegeben wird und Zeiger darauf ungültig werden. Das ist nur eine Macke free nimmt non-const, es ist kein Gebot von oben. In dem seltenen Fall, dass Sie mit Ihrem Zeiger nur eine Sache machen, die nicht konstant ist, und das ist kostenlos, dann ziehen Sie pragmatisch wahrscheinlich mehr Nutzen aus einem konstanten Zeiger (den Sie in frei umwandeln) als aus einem nicht konstanten Zeiger (der Sie könnten versehentlich etwas ändern).

    – Steve Jessop

    12. Mai 2010 um 19:31 Uhr

Benutzeravatar von Tim Post
Tim Post

Ihr Code ist umgekehrt.

Dies:

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);

Das const Der Speichertyp teilt dem Compiler mit, dass Sie nicht beabsichtigen, einen einmal zugewiesenen Speicherblock (dynamisch oder statisch) zu ändern. Das Freigeben des Speichers verändert ihn. Beachten Sie, dass Sie den Rückgabewert von malloc() nicht umwandeln müssen, aber das ist nur eine Randbemerkung.

Es hat wenig Sinn, Speicher dynamisch zuzuweisen (was Sie tun, basierend auf der Länge von name) und dem Compiler mitteilen, dass Sie nicht die Absicht haben, es zu verwenden. Notiz, verwenden was bedeutet, etwas darauf zu schreiben und es dann (optional) später freizugeben.

Das Umwandeln in einen anderen Speichertyp behebt nicht die Tatsache, dass Sie die Speichertypen von Anfang an umgekehrt haben 🙂 Es lässt nur eine Warnung verschwinden, die Ihnen etwas sagen wollte.

Wenn der Code umgekehrt ist (wie es sein sollte), free() wird wie erwartet funktionieren, da Sie es tatsächlich können ändern der Speicher, den Sie zugewiesen haben.

  • Das OP hat gefragt, wie ein Zeiger auf einen konstant qualifizierten Typ freigegeben werden kann. Das angehängte Codebeispiel spiegelt seine Frage wider, bei der Ihre Interpretation dem widerspricht. Nebenbei bemerkt, der const-Qualifizierer für den Typ, auf den gezeigt wird, beeinflusst oder drückt keine Absicht aus, was mit einem zugewiesenen Objekt selbst getan wird, es beeinflusst nur, was über diesen Zeiger getan wird. Sobald/wenn Sie den Konstanten-Qualifizierer, auf den gezeigt wird, verwerfen, können Sie das zugewiesene Objekt ändern.

    – Dror K.

    3. März 2017 um 22:38 Uhr

  • @DrorK. Trotzdem ist dies zumindest für mich die nützlichste Antwort, da ich den gleichen Fehler wie das OP gemacht habe. Die meisten Menschen, die auf dieses Problem stoßen, sind wahrscheinlich ähnlich verwirrt, daher gehe ich davon aus, dass dies tatsächlich die beste Antwort ist.

    – Michael Dorst

    12. April 2020 um 21:04 Uhr

Benutzeravatar von Paul R
Paul R

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

FWIW, gcc gibt 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 verwendest du?

  • Hier ist ein Fall, in dem Sie vielleicht einen Zeiger auf const freigeben möchten: char const* s = strdup("hello"); free(s);.

    – Bobbogo

    19. Juli 2012 um 9:44 Uhr


  • @bobbogo: ja, obwohl es schwer vorstellbar ist, warum Sie überhaupt eine konstante Kopie eines Zeichenfolgenliterals erstellen möchten.

    – PaulR

    19. Juli 2012 um 10:46 Uhr


  • Vielleicht möchten Sie eine Kopie eines Strings nehmen, der gerade freigegeben () oder anderweitig durch Bibliothekscode geändert wird. Sie werden Ihre Kopie nicht ändern, also markieren Sie sie als const.

    – Bobbogo

    27. August 2012 um 11:44 Uhr

Benutzeravatar von nlstd
nlstd

Es gibt Fälle, die Sie befreien möchten const*. Sie möchten dies jedoch nicht tun, es sei denn, Sie weisen es in derselben Funktion zu. Sonst machst du wahrscheinlich Sachen kaputt. Sehen Sie sich den folgenden Code für ein reales Beispiel an. ich benutze const in den Funktionsdeklarationen, um zu zeigen, dass ich den Inhalt der Argumente nicht ändere. Wie auch immer es ist neu zugewiesen mit einem kleingeschriebenen Duplikat (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;
}

Es hat keinen Zweck, einen Malloc-Zeiger auf const zu werfen. Eine Funktion, die einen konstanten Zeiger verwendet, sollte nicht dafür verantwortlich sein, den an sie übergebenen Speicher freizugeben.

  • Was ist mit Code wie struct foo { const char *bar; ... }? Dies drückt die Tatsache aus, dass die Erinnerung auf by zeigt foo->bar sollte als unveränderlich behandelt werden (während andere Mitglieder von struct foo kann variabel sein). Dies ist nützlich, um die Korrektheit eines Programms sicherzustellen. Still bar muss möglicherweise malloc’d werden, wenn das Objekt zum ersten Mal initialisiert wird. Wenn Sie ein solches Objekt befreien möchten, brauchen Sie eine Möglichkeit, es zu befreien barzu.

    – Uncleremus

    27. Oktober 2020 um 9:12 Uhr

  • @uncleremus Hier geht es darum, aus wessen Perspektive Sie operieren. Der Speicher, auf den foo->bar zeigt, sollte vom Empfänger als unveränderlich behandelt werden. Der Speicher, auf den foo->bar zeigt, sollte von seinem Besitzer nicht als unveränderlich behandelt werden, da er diesen Speicher freigeben muss, was definitiv eine Mutation darstellt. Sie müssen also anderen Menschen eine unveränderliche Schnittstelle zeigen, während Sie für sich selbst eine veränderbare Version behalten.

    – Welpe

    28. Oktober 2020 um 10:27 Uhr

  • Schlagen Sie vor, eine Gewerkschaft zu verwenden? struct foo { union { const char *bar; char *__bar; }; } würde funktionieren, denke ich.

    – Uncleremus

    29. Oktober 2020 um 13:19 Uhr

  • @uncleremus Ich schlage vor, dass Sie zwei völlig unterschiedliche Strukturen haben sollten, eine für den internen Gebrauch und eine für den externen Gebrauch.

    – Welpe

    30. Oktober 2020 um 14:33 Uhr

  • Sogar der “Besitzer”-Code muss möglicherweise geändert werden bar -Element nur an einer einzigen Stelle (dem Destruktor), während es herumgereicht werden kann foo Objekte viel und möglicherweise andere Mitglieder modifizieren. Sogar im Code, der die Struktur besitzt, schützt bar gegen irrtümliche Änderung mit const ist wünschenswert. Das const muss nur im Destruktor verworfen werden.

    – Uncleremus

    15. Januar 2021 um 13:34 Uhr

Benutzeravatar von uncleremus
Onkelemus

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

Gießen const zu nicht-const ist ein Symptom für Code Smell.

Es gibt Compiler-Warnungen, die davor schützen, wie z -Wcast-qual in gcc, was ich sehr nützlich finde. Wenn du Ja wirklich einen triftigen Grund für die Befreiung von a const Zeiger (im Gegensatz zu dem, was viele hier geschrieben haben, dort sind gültige Fälle, wie von nlstd aufgezeigt), könnten Sie für diesen Zweck ein Makro wie folgt definieren:

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

Dies funktioniert zumindest für gcc. Die Doppelbesetzung ergibt die Logik -Wcast-qual erkennt dies nicht als “casting const away”. Natürlich sollte dieses Makro mit Vorsicht verwendet werden. Eigentlich sollte es nur für Zeiger verwendet werden, die in derselben Funktion zugewiesen sind.

  • Was ist mit Code wie struct foo { const char *bar; ... }? Dies drückt die Tatsache aus, dass die Erinnerung auf by zeigt foo->bar sollte als unveränderlich behandelt werden (während andere Mitglieder von struct foo kann variabel sein). Dies ist nützlich, um die Korrektheit eines Programms sicherzustellen. Still bar muss möglicherweise malloc’d werden, wenn das Objekt zum ersten Mal initialisiert wird. Wenn Sie ein solches Objekt befreien möchten, brauchen Sie eine Möglichkeit, es zu befreien barzu.

    – Uncleremus

    27. Oktober 2020 um 9:12 Uhr

  • @uncleremus Hier geht es darum, aus wessen Perspektive Sie operieren. Der Speicher, auf den foo->bar zeigt, sollte vom Empfänger als unveränderlich behandelt werden. Der Speicher, auf den foo->bar zeigt, sollte von seinem Besitzer nicht als unveränderlich behandelt werden, da er diesen Speicher freigeben muss, was definitiv eine Mutation darstellt. Sie müssen also anderen Menschen eine unveränderliche Schnittstelle zeigen, während Sie für sich selbst eine veränderbare Version behalten.

    – Welpe

    28. Oktober 2020 um 10:27 Uhr

  • Schlagen Sie vor, eine Gewerkschaft zu verwenden? struct foo { union { const char *bar; char *__bar; }; } würde funktionieren, denke ich.

    – Uncleremus

    29. Oktober 2020 um 13:19 Uhr

  • @uncleremus Ich schlage vor, dass Sie zwei völlig unterschiedliche Strukturen haben sollten, eine für den internen Gebrauch und eine für den externen Gebrauch.

    – Welpe

    30. Oktober 2020 um 14:33 Uhr

  • Sogar der “Besitzer”-Code muss möglicherweise geändert werden bar -Element nur an einer einzigen Stelle (dem Destruktor), während es herumgereicht werden kann foo Objekte viel und möglicherweise andere Mitglieder modifizieren. Sogar im Code, der die Struktur besitzt, schützt bar gegen irrtümliche Änderung mit const ist wünschenswert. Das const muss nur im Destruktor verworfen werden.

    – Uncleremus

    15. Januar 2021 um 13:34 Uhr

Benutzeravatar von Felix Kling
Felix Klinge

Ich könnte mich irren, aber ich denke, das Problem liegt darin const. Setzen Sie den Zeiger auf Nicht-Konstante wie:

free((char *) p);

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

  • free ändert den Zeiger nicht. Es gibt den Speicherblock frei, auf den der Zeiger zeigt. Dies ist ein Fehler in der Sprachspezifikation. free sollte eindeutig einen const-Zeiger nehmen.

    – Axel Gneiting

    12. Mai 2010 um 14:45 Uhr


  • @ Axel const bedeutet, dass Sie den Inhalt des Speicherobjekts nicht ändern können, nicht den tatsächlichen Wert des Zeigers … und das Freigeben des angezeigten Speichers ist eine ziemlich dramatische Änderung, würde ich sagen! (Übrigens scheint es ein bisschen anmaßend zu glauben, dass die Spezifikation falsch ist [and has been wrong for more than 30 years] und plötzlich stellen Sie fest, dass Sie Recht haben und alle Mitglieder des Prüfungsausschusses nicht, nicht wahr?)

    – Fortran

    12. Mai 2010 um 14:56 Uhr


  • @fortran: Es ist überhaupt nicht anmaßend, es ist eine allgemeine Meinungsverschiedenheit. delete in C++ kann auf a verwendet werden const char*, also wenn es eine große Kontroverse ist, dann muss der eine oder andere Standardautor falsch liegen. Eigentlich denke ich nicht, dass es wirklich wichtig ist – das Wegwerfen von const, um einen Zeiger freizugeben, ist kaum eine Krise.

    – Steve Jessop

    12. Mai 2010 um 15:31 Uhr


  • const char* besagt, dass das, worauf gezeigt wird, eine Konstante ist und nicht geändert werden kann. es ist nicht sagen, dass der Zeiger selbst nicht geändert werden kann.

    – JeremyP

    12. Mai 2010 um 15:55 Uhr

  • @ Axel Gneiting: Ich habe nie gesagt, dass der Zeiger geändert wird. const weist darauf hin, dass die Daten an dieser Stelle sollte nicht verändert werden. Aber wenn Sie den Speicher freigeben, können die Daten an dieser Stelle überschrieben und damit verändert werden.

    – Felix Klinge

    12. Mai 2010 um 18:41 Uhr


1418840cookie-checkKonstante Zeiger in C können nicht freigegeben werden

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

Privacy policy