web-dev-qa-db-ja.com

Cでconstポインターを解放できません

const char*mallocを使用して新しいメモリを割り当てました。解放しようとすると、常に「互換性のないポインタ型」というエラーが表示されます。

これを引き起こすコードは次のようなものです:

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

free(str); // error here
64
lego69

数人が正しい答えを投稿しましたが、何らかの理由でそれを削除し続けています。非constポインターにキャストする必要があります。 freevoid*ではなくconst void*を取ります:

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

コードが逆になります。

この:

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

次のようになります。

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

constストレージタイプは、割り当てられたメモリブロックを(動的または静的に)変更するつもりがないことをコンパイラに伝えます。メモリーを解放すると変更されます。注: malloc()の戻り値をキャスト する必要はありませんが、それは別です。

メモリを動的に割り当て(nameの長さに基づいて実行しています)、メモリを使用する意図がないことをコンパイラに伝えることはほとんど使用されません。 usingは、何かに書き込み、その後(オプションで)後で解放することを意味します。

別のストレージタイプにキャストしても、最初にストレージタイプを逆にしたという事実は修正されません:)何かを伝えようとしていた警告が消えるだけです。

コードが逆になっている場合(あるべき)、free()は、実際にmodifyできるため、期待どおりに動作します割り当てられました。

23
Tim Post

Constへのポインタをmallocしても意味がありません。その内容を(いハックなしで)変更することはできないからです。

ただし、gccは次のことを警告するだけです。

//
// 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
$ 

どのコンパイラを使用していますか?

6
Paul R

const*を解放したい場合があります。ただし、同じ関数で割り当て/割り当てを行わない限り、実行したくないでしょう。そうでなければ、物事を壊す可能性があります。実際の例については、以下のコードを参照してください。関数宣言でconstを使用して、引数の内容を変更していないことを示しています。ただし、それはreassignedで、小文字の重複(strdup)を解放する必要があります。

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

Constにmallocされたポインターをキャストすることは目的がありません。 constポインターを受け取る関数は、渡されたメモリを解放する責任を負わないようにする必要があります。

2
Puppy

いくつかの答えは、単に_char*_にキャストすることを示唆しています。しかし、el.pescadoが上記に書いたように、

constconst以外にキャストすることは、コード臭の兆候です。

Gccの_-Wcast-qual_など、これを防ぐコンパイラ警告がありますが、これは非常に便利です。 本当にconstポインタを解放するための有効なケースを持っている場合(多くの人がここに書いたものとは反対に、そこにare nlstdによって指摘された有効なケースがあります) )、そのために次のようなマクロを定義できます。

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

これは少なくともgccで機能します。二重キャストにより、ロジック_-Wcast-qual_はこれを「キャストconst離れ」として検出しません。言うまでもなく、このマクロは注意して使用する必要があります。実際には、同じ関数で割り当てられたポインターにのみ使用する必要があります。

1
uncleremus

私は間違っているかもしれませんが、問題はconstにあると思います。ポインタを次のように非constにキャストします。

free((char *) p);

constで言うのは:このポインターが指すデータを変更しないでください

1
Felix Kling

純粋なCについて話していて、メモリ割り当てを完全に制御している場合は、次のトリックを使用して(const char *)を(char *)にキャストできます。これにより、コンパイラで警告が表示されません。

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;

これでfree(str)を使用できます。メモリを解放します。

しかし、これは言葉を超えた悪であり、厳密に制御された環境でのみ使用する必要があることに注意してください(たとえば、文字列を割り当てて解放しますが、ユーザーが文字列を変更することを望まないライブラリ)コンパイル時間「STRING」を無料の関数に追加します。

0
MMasterSK

本当の答えは、freeはconstポインター引数を取り、NULLconstポインターとして定義されるべきだと思います。これは標準のバグのようです。 constポインターの解放は、次のように実装する必要があります。

free(p);
p = NULL;

この場合、コンパイラがどのように誤ったコードを生成するかわかりません。constポインターpにはアクセスできなくなります。したがって、ポインターが指しているオブジェクトがconst、有効、その他何でも。そのconstは、レジスターまたはその他の場所にダーティーコピーが存在しないようにします。 constポインターを別の値に設定することは有効であり、その値がNULLであるという事実は、以前の値にアクセスできなくなったため重要ではありません。

0
free

constであるため、const char *を解放できません。 mallocから受け取ったポインターを非constポインター変数に格納し、freeに渡すことができるようにします。 char *引数を受け取る関数にconst char *引数を渡すことができますが、逆は常に真とは限りません。

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