Why am I able to change the contents of const char *ptr?
http://stackoverflow.com/questions/3228664/why-am-i-able-to-change-the-contents-of-const-char-ptr
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".
Why am I able to change the contents of const char *ptr?的更多相关文章
- Redis中的数据结构
1. 底层数据结构, 与Redis Value Type之间的关系 对于Redis的使用者来说, Redis作为Key-Value型的内存数据库, 其Value有多种类型. String Hash L ...
- unity导出工程导入到iOS原生工程中详细步骤
一直想抽空整理一下unity原生工程导入iOS原生工程中的详细步骤.做iOS+vuforia+unity开发这么长时间了.从最初的小小白到现在的小白.中间趟过了好多的坑.也有一些的小小收货.做一个喜欢 ...
- Array类
class Array Arrays are ordered, integer-indexed collections of any object. Array indexing starts at ...
- 转:RTMPDump源代码分析
0: 主要函数调用分析 rtmpdump 是一个用来处理 RTMP 流媒体的开源工具包,支持 rtmp://, rtmpt://, rtmpe://, rtmpte://, and rtmps://. ...
- 基于Httpfs访问HDFS的C++实现
Httpfs是hadoop2.x中hdfs项目的内置应用,基于tomcat和jesery,对外提供完备HDFS操作的RESTful接口,无需安装客户端,可方便实现数据交互,如从windows访问存储在 ...
- libcurl的封装,支持同步异步请求,支持多线程下载,支持https
最近在做一个项目,需要用到http get post等 需求分析需要做到同步和异步,异步请求的返回以可选的回调通知的方式进行. 本人以Linux为例,一步一步的来实现. 配置并且编译libcurl我以 ...
- leveldb 学习记录(四)Log文件
前文记录 leveldb 学习记录(一) skiplistleveldb 学习记录(二) Sliceleveldb 学习记录(三) MemTable 与 Immutable Memtablelevel ...
- 5、QT分析之网络编程
原文地址:http://blog.163.com/net_worm/blog/static/127702419201002842553382/ 首先对Windows下的网络编程总结一下: 如果是服务器 ...
- 安卓加固之so文件加固
一.前言 最近在学习安卓加固方面的知识,看到了jiangwei212的博客,其中有对so文件加固的两篇文章通过节加密函数和通过hash段找到函数地址直接加密函数,感觉写的特别好,然后自己动手实践探索s ...
随机推荐
- Cocos2d-JS地图性能问题
如图所示游戏场景,它是我们以往介绍的实例,在场景中有三个方块精灵(BoxA.BoxB和BoxC)和背景精灵,这个背景叫做“地图”有点牵强,地图采用了有规律的纹理. 游戏场景 那么我们如何设计这个游戏地 ...
- Cocos2d-JS中的Sprite精灵类
精灵类是cc.Sprite,它的类图如下图所示.cc.Sprite类直接继承了cc.Node类,具有cc.Node基本特征. 创建Sprite精灵对象 创建精灵对象可以使用构造函数实现,它们接受相同的 ...
- UI5_HomeWork
// // View.h // UI5_HomeWork // // Created by zhangxueming on 15/7/2. // Copyright (c) 2015年 zhangxu ...
- python基础day2作业:购物车
#功能:1.可注册账号2.登录买家账号3.可查询编辑购物车里商品4.可以余额充值5.可提示余额不足6.购物车结算 #使用:1.第一次使用先注册账号填写账号金额2.账号金额信息保存在buyer_acco ...
- State模式
地铁十字转门 状态迁移表格. 起始状态 触发迁移的事件 终止状态 要执行的动作. Locked Coin UnLocked UnLock UnLocked Pass ...
- /mnt /media /dev 目录区别
/mnt 是被系统管理员使用,手动挂载一些临时媒体设备的目录. /medai 是自动挂载的目录,比如我们的U盘插在ubuntu下回自动挂载,就会在/media下生成一个目录,这个目录就是U盘所在目录, ...
- javascript弹窗基础篇
confirm()意既确认框 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> ...
- 为apache与mysql创建快捷方式
为apache与mysql创建快捷方式 1)为apache创建快捷方式(软链接) 以后我们就可以在终端的任一位置,使用apachectl start|stop|restart 2)为mysql创建 ...
- C# 中有关 using 关键字
关于 C# 中的 using 关键字 我们往往只在代码的开头使用 using 关键字来引入名称空间,这是 using 的一个最常见的使用. 但是,using 关键字是否只有这么一处用武之地吗? 下面, ...
- IOS做一个简单计算器
//声明非原创 步骤: 1.打开Xcode,单机Creat a new Xcode project 2.左边选择ios下Application,右边选择single view Application ...