无法释放C中的const指针


73

我怎样才能释放const char*?我使用分配了新的内存malloc,当我尝试释放它时,我总是收到错误“不兼容的指针类型”

导致这种情况的代码类似于:


您是否有特定原因需要这样做?通常,字符串常量是您提前知道的,因此为字符串常量动态分配空间似乎很奇怪。
詹姆斯·金斯伯里

4
基本上是C语言问题。free()的签名应该是void free(const void* p);。已在C ++中修复(带有delete
MSalters 2010年

8
@James Kingsbery:可能是字符串,可能是:最初填充char缓冲区后,随后将其视为才有意义const char*。提问者真的需要我们的许可才能遇到问题吗?;-)
史蒂夫·杰索普

6
但是,这毫无意义。一旦将内存分配给str,就无法通过对其进行更改str,这意味着它永久性地成为了内存中的所有malloc()内容。不进行强制复制就无法复制该名称str。(此外,将字符串文字分配给achar *也不好,因为尝试修改字符串文字是未定义的行为。我认为您只是将consts弄混了。)
David Thornley 2010年

3
@DavidThornley:const char *您所获取char *的内容可能已被填充,例如来自const char* foo() { char* s = malloc(...); strcpy(s, ...); return s; }
musiphil 2014年

Answers:


91

有几个人发布了正确的答案,但是由于某些原因,他们一直在删除它。您需要将其强制转换为非const指针;free需要一个void*,而不是const void*


21
它将起作用,但是强制const转换为非const是代码气味的征兆。
el.pescado 2010年

2
@el。free()是一个例外,因为您可能不希望在指针的生命周期内对其进行修改,但仍希望在最后将其释放
Michael Mrozek 2010年

10
为什么要强制转换为char *?为什么不直接释放((void *)str)?
10年

43
我回想起曾读过有关linux内核中使用const指针的内存释放函数的信息,有人问Linus为什么,他为它辩护说,无论是从概念上还是在实践中,它实际上都没有修改所指向的值,它看起来只是使用指针向上移动内存块并对其进行分配。我同意他的评估,因此认为free()函数的规范不正确。但是a,这是标准。
rmeador

13
如果“释放”在概念上发生了变化,那么可以声明aconst int然后离开声明它的范围了吗?从释放资源并使指向它的指针不再有效的意义上讲,这“释放”了自动变量。这只是一个free需要使用非常量的怪癖,而不是高尚的诫命。在极少数情况下,您只需要对非const指针做一件事,并且将其释放,那么在实用上,与非const指针(它转换为free)相比,您可能会从const指针(转换为free)中获得更多收益。您可能会意外修改)。
史蒂夫·杰索普

27

您的代码是反向的。

这个:

应该看起来像这样:

const存储类型告诉编译器,你不打算修改的内存块一次分配(动态,或静态)。释放内存正在对其进行修改。注意,您不需要强制转换malloc()的返回值,但这只是一个问题。

动态分配内存(根据的长度,您正在做的事情name)并告诉编译器您无意使用它,这几乎没有用。注意,使用含义向其中写入一些内容,然后(可选)稍后释放它。

强制转换为其他存储类型并不能解决以下事实:您从一开始就颠倒了存储类型:)只是警告消失了,它试图告诉您一些信息。

如果代码是反向的(应该正确),free()则将按预期工作,因为您实际上可以修改分配的内存。


3
OP询问如何释放指向const限定类型的指针-随附的代码示例反映了他的问题,您的解释与此矛盾。顺便说一句,指向类型的const限定符不会影响或表达对分配的对象本身要执行的操作或意图,它仅影响将通过此指针执行的操作。一次/如果丢弃指向常量的限定符,则可以修改分配的对象。
Dror K.

@DrorK。但是,这至少对我来说是最有用的答案,因为我犯了与OP相同的错误。多数遇到此问题的人可能也有类似的困惑,因此我认为这实际上是最好的答案。
Michael Dorst

6

m分配指向const的指针没有任何意义,因为您将无法修改其内容(没有丑陋的技巧)。

FWIW,gcc只是针对以下情况给出警告:

您正在使用什么编译器?


12
在一种情况下,您可能希望释放指向const的指针:char const* s = strdup("hello"); free(s);
bobbogo 2012年

2
@bobbogo:是的,尽管很难想象为什么首先要对字符串文字进行const复制。
Paul R

9
您可能希望获取一个字符串的副本,该字符串将要被free()或由库代码更改。您不会修改副本,因此将其标记为const。
bobbogo 2012年

4

在某些情况下,您想释放一个const*。但是,除非您在同一函数中进行分配/分配,否则您不希望这样做。否则您可能会破坏事情。有关真实示例,请参见下面的代码。我const在函数声明中使用以表明我没有更改参数的内容。但是,重新分配为需要释放的小写副本(strdup)。


3

将目标的malloc指针强制转换为const是没有目的的。任何使用const指针的函数都不应负责释放传递给它的内存。


怎么样的代码struct foo { const char *bar; ... }呢?这表示了一个事实,即指向的内存foo->bar应视为不可变的(而的其他成员struct foo可能是可变的)。这对于确保程序的正确性很有用。bar首次初始化对象时,可能仍需要进行malloc。如果要释放这样的对象,则也需要一种释放方法bar
Uncleremus

@uncleremus这是从您的操作角度来看的问题。foo-> bar指向的内存应被接收者视为不可变的。拥有它的人不应该将foo-> bar所指向的内存视为不可变的,因为他们需要释放该内存,这肯定构成了一个突变。因此,您需要向他人展示一个不变的界面,同时为您自己保留一个可变的版本。
小狗

您是否建议使用工会?struct foo { union { const char *bar; char *__bar; }; }我想会有用的。
Uncleremus

@uncleremus我建议您应该使用两种完全不同的结构,一种用于内部使用,一种用于外部使用。
小狗

2

有几个答案建议简单地转换为char*。但正如埃尔·佩斯卡多(El.pescado)上文所述,

强制const转换为非-const是代码异味的症状。

有防止这种情况的编译器警告,例如-Wcast-qual在gcc中,我发现它非常有用。如果您确实有一个释放const指针的有效情况(与许多此处编写的情况相反,则nlstd指出的有效情况),则可以为此目的定义一个宏:

这至少对gcc有效。双重-Wcast-qual强制转换使逻辑不会将其检测为“强制转换常量”。不用说,此宏应谨慎使用。实际上,它仅应用于在同一函数中分配的指针。


2
长应替换为intptr_t
好人

1

我可能错了,但我认为问题出在哪里const。将指针强制转换为非常量,例如:

因为const您说:不要更改此指针指向的数据


3
free不会更改指针。它释放指针指向的内存块。这是语言规范中的错误。free应该清楚地带一个const指针。
Axel Gneiting 2010年

6
@Axelconst意味着您不能更改存储对象的内容,不能更改指针的实际值...并且释放指向的内存是我要说的一个相当大的变化!(顺便说一句,认为规范是错误的(并且已经有30多年的错误了),似乎有点自命不凡,突然间您发现自己是对的,而所有审核委员会成员都不对,不是吗? )
fortran 2010年

9
@fortran:一点都不自命不凡,这是观点的普遍差异。deleteC ++中的C语言可以在上使用const char*,因此如果引起很大争议,那么一个或另一组标准作者肯定是错误的。实际上,我认为这并不重要-抛弃const以释放指针几乎不是危机。
史蒂夫·杰索普

3
const char *表示所指向的是一个常量,不能更改。这是不是说,指针本身不能改变。
JeremyP,2010年

4
@Axel Gneiting:我从未说过指针已更改。const表示不应更改此位置的数据。但是,如果释放内存,此位置的数据可能会被覆盖并因此被更改。
菲利克斯·克林

0

您不能自由,const char *因为它是const。将收到的指针存储malloc在非const指针变量中,以便可以将它们传递给free。您可以将char *参数传递给带有const char *参数的函数,但相反的情况并不总是正确的。


5
在C ++中,您可以delete使用const char*。那你为什么不呢?指针阻止字符被修改的事实,一旦不再需要,就不应不允许删除该字符串。我对C的了解还不够。有人在这里标出报价吗?
2010年

3
-1,指针的常数不会free以任何方式影响您对其的能力。
Hasturkun 2010年

2
@JeremyP:答案是未定义的行为(或可能是鼻恶魔),但这不是const由尝试释放字符串常量引起的。
Hasturkun 2010年

2
@JeremyP这个例子是似是而非的。这是错误的,但不是因为字符串是const,而是字符串文字的一种特殊情况
Michael Mrozek 2010年

2
@JeremyP:“您永远不要释放const char*。” 我不同意。如果是这样,则永远不要有const动态分配的字符串,因为您无法删除它们。那真是愚蠢。是否动态分配某些内容以及是否应该更改某些内容是正交的问题。我可以动态分配一些我不想更改的字符串,但是必须在某个时候释放它们。我认为这是C std库中的一个错误,可能是由于constC后来才从C ++中采用,而现在它有点像个红发继子。
2010年

0

如果您正在谈论纯C并且可以完全控制内存分配,则可以使用以下技巧将(const char *)强制转换为(char *),这在编译器中不会给出任何警告:

现在您可以使用free(str); 释放内存。

但是请注意,这超出了单词的含义,应仅在严格控制的环境中使用(例如,分配和释放字符串但不希望允许用户修改它们的库),否则当有人提供时,您将最终导致程序崩溃将时间“ STRING”编译为自由函数。


1
union当普通演员可以自己改变状态时,为什么在地球上您会毫无意义地使用这种丑陋的技巧const
underscore_d

0

我认为真正的答案是,free应该带有const指针参数,并且NULL应该定义为const指针。这似乎是标准中的错误。释放const指针应按以下方式实现:

在这种情况下,我看不到编译器如何生成不正确的代码,const指针p不再可访问,因此它所指向的对象是否const有效均无关紧要。其const所以不能在寄存器中或其他地方的任何肮脏的副本。将const指针设置为另一个值是有效的,并且该值NULL无关紧要的事实是因为不再可以访问以前的值。


-1

如果您看一下free函数的签名,free总是以void * ptr作为参数,因此您需要将其强制转换为适当的类型,例如free((void *)str);。free不允许直接释放const指针,因此您需要将其强制转换为非const类型


-2

我认为即使将指针转换为非常量,free的结果也将取决于实现。通常const是为您不想修改的变量而设计的!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.