为什么我可以更改const char * ptr的内容? [英] Why am I able to change the contents of const char *ptr?
问题描述
我将指针ptr
传递给一个函数,该函数的原型将其用作const
.
foo( const char *str );
根据我的理解,这意味着它将无法更改所传递的ptr
的内容.类似于foo( const int i )
的情况.如果foo()
尝试更改i
的值,则编译器给出错误.
但是在这里我看到它可以轻松更改ptr
的内容.
请看下面的代码
foo( const char *str )
{
strcpy( str, "ABC" ) ;
printf( "%s(): %s\n" , __func__ , str ) ;
}
main()
{
char ptr[ ] = "Its just to fill the space" ;
printf( "%s(): %s\n" , __func__ , ptr ) ;
foo( const ptr ) ;
printf( "%s(): %s\n" , __func__ , ptr ) ;
return;
}
在编译时,我只会收到警告,没有错误:
warning: passing argument 1 of ‘strcpy’ discards qualifiers from pointer target type
当我运行它时,我得到的是输出而不是Segmentation Fault
main():仅用于填充空间
foo():ABC
main():ABC
现在,我的问题是
1-原型中的const char *str
实际含义是什么?
这是否意味着函数不能更改str
的内容?如果是这样,那么上面的程序如何更改值?
2-如何确保我传递的指针内容不会更改?
从上述问题中的指针内容"开始,我的意思是指针指向的内存内容",而不是指针中包含的地址".
编辑
大多数答复说,这是因为strcpy
和C隐式类型转换.但是现在我尝试了
foo( const char *str )
{
str = "Tim" ;
// strcpy( str, "ABC" ) ;
printf( "%s(): %s\n" , __func__ , str ) ;
}
这次是输出,编译器未发出警告
main():仅用于填充空间
foo():Tim
main():只是为了填充空间
因此,显然,当str
指向的内存在foo()
中时,它更改为包含"Tim"
的内存位置.尽管这次我没有使用strcpy()
.
const
是否应该停止此操作?还是我的理解是错误的?
在我看来,即使使用const
,我也可以更改内存引用和内存引用的内容.那有什么用?
您能举个例子吗,编译器会给我一个我试图更改const指针的错误信息?
感谢大家的时间和精力.
您的理解是正确的,const char*
是一个约定,表示您无法通过此特定指针更改内存.
问题在于C在类型转换方面非常松懈. strcpy
使用一个指向 non-const char的指针,并且它被隐式从const char*
转换为char*
(编译器会告诉您).您可以轻松地传递一个整数而不是指针.结果,您的函数无法更改ptr
指向的内容,但是strcpy
可以更改,因为它看到了非const指针.您不会崩溃,因为在您的情况下,指针指向的是一个足够大的实际缓冲区,而不是只读的字符串常量.
为避免这种情况,请查找编译器警告,或例如使用-Wall -Werror
进行编译(如果使用的是gcc).
例如,此行为特定于C.C++不允许这样做,并且需要显式强制转换(C样式强制转换或const_cast
)来剥离const
限定符,如您所期望的那样. /p>
扩展问题的答案
您正在将字符串文字分配给非const字符,不幸的是, 在C甚至C ++中都是合法的!即使现在通过该指针进行写入将导致未定义的行为,它也会隐式转换为char*
.这是一个已弃用的功能,到目前为止,只有C ++ 0x不允许这种情况发生.
话虽如此,为了停止更改指针本身,您必须将其声明为指向char(char *const
)的const指针.或者,如果要使其指向的内容和指针本身都不变,请使用指向const char(const char * const
)的const指针.
示例:
void foo (
char *a,
const char *b,
char *const c,
const char *const d)
{
char buf[10];
a = buf; /* OK, changing the pointer */
*a = 'a'; /* OK, changing contents pointed by pointer */
b = buf; /* OK, changing the pointer */
*b = 'b'; /* error, changing contents pointed by pointer */
c = buf; /* error, changing pointer */
*c = 'c'; /* OK, changing contents pointed by pointer */
d = buf; /* error, changing pointer */
*d = 'd'; /* error, changing contents pointed by pointer */
}
对于所有错误行,GCC都会给我错误:分配只读位置".
I passed a pointer ptr
to a function whose prototype takes it as const
.
foo( const char *str );
Which according to my understanding means that it will not be able to change the contents of ptr
passed. Like in the case of foo( const int i )
. If foo()
tries to chnage the value of i
, compiler gives error.
But here I see that it can change the contents of ptr
easily.
Please have a look at the following code
foo( const char *str )
{
strcpy( str, "ABC" ) ;
printf( "%s(): %s\n" , __func__ , str ) ;
}
main()
{
char ptr[ ] = "Its just to fill the space" ;
printf( "%s(): %s\n" , __func__ , ptr ) ;
foo( const ptr ) ;
printf( "%s(): %s\n" , __func__ , ptr ) ;
return;
}
On compilation, I only get a warning, no error:
warning: passing argument 1 of ‘strcpy’ discards qualifiers from pointer target type
and when I run it, I get an output instead of Segmentation Fault
main(): Its just to fill the space
foo(): ABC
main(): ABC
Now, my questions is
1- What does const char *str
in prototype actually means?
Does this mean that function cannot change the contents of str
? If that is so then how come the above program changes the value?
2- How can I make sure that the contents of the pointer I have passed will not be changed?
From "contents of the pointer" in the above stated question, I mean "contents of the memory pointed at by the pointer", not "address contained in the pointer".
Edit
Most replies say that this is because of strcpy
and C implicit type conversion. But now I tried this
foo( const char *str )
{
str = "Tim" ;
// strcpy( str, "ABC" ) ;
printf( "%s(): %s\n" , __func__ , str ) ;
}
This time the output is, with no warning from compiler
main(): Its just to fill the space
foo(): Tim
main(): Its just to fill the space
So apparently, memory pointed to by str
is changed to the memory location containing "Tim"
while its in foo()
. Although I didn't use strcpy()
this time.
Is not const
supposed to stop this? or my understanding is wrong?
To me it seems that even with const
, I can change the memory reference and the contents of memory reference too. Then what is the use?
Can you give me an example where complier will give me error that I am trying to change a const pointer?
Thanks to all of you for your time and effort.
Your understanding is correct, const char*
is a contract that means you can't change memory through this particular pointer.
The problem is that C is very lax with type conversions. strcpy
takes a pointer to non-const char, and it is implicitly converted from const char*
to char*
(as compiler helpfully tells you). You could as easily pass an integer instead of pointer. As a result, your function can't change content pointed by ptr
, but strcpy
can, because it sees a non-const pointer. You don't get a crash, because in your case, the pointer points to an actual buffer of sufficient size, not a read-only string literal.
To avoid this, look for compiler warnings, or compile, for example, with -Wall -Werror
(if you are using gcc).
This behaviour is specific to C. C++, for example, does not allow that, and requires an explicit cast (C-style cast or a const_cast
) to strip const
qualifier, as you would reasonably expect.
Answer to the extended question
You are assigning a string literal into a non-const char, which, unfortunately, is legal in C and even C++! It is implicitly converted to char*
, even though writing through this pointer will now result in undefined behaviour. It is a deprecated feature, and only C++0x so far does not allow this to happen.
With that said, In order to stop changing the pointer itself, you have to declare it as const pointer to char (char *const
). Or, if you want to make it that both the contents pointed by it and the pointer itself don't change, use a const pointer to const char (const char * const
).
Examples:
void foo (
char *a,
const char *b,
char *const c,
const char *const d)
{
char buf[10];
a = buf; /* OK, changing the pointer */
*a = 'a'; /* OK, changing contents pointed by pointer */
b = buf; /* OK, changing the pointer */
*b = 'b'; /* error, changing contents pointed by pointer */
c = buf; /* error, changing pointer */
*c = 'c'; /* OK, changing contents pointed by pointer */
d = buf; /* error, changing pointer */
*d = 'd'; /* error, changing contents pointed by pointer */
}
For all error lines GCC gives me "error: assignment of read-only location".
这篇关于为什么我可以更改const char * ptr的内容?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!